Allow to press a button when the player is close enough to it

Hi!

I have to do this in C++:

The player approaches to a button, when it is near enough he/she pushes the button and then a door opens.

I have already done almost everything except the logic to push the button. I’ve thought to put this code in the actor which has the button:

PlayerInputComponent->BindAction(TEXT("Action"), IE_Pressed, this, &AMyActor:::Push);

But, I don’t think I can do it because an Actor doesn’t have the PlayerInputComponent.

Another way is using something that I have found in blueprints called “Interactions By Event Dispatcher”, but I’m not sure how to do it in C++ or if it is a good idea to use it.

How can I do it?

How I did it in a recent project of mine:

  1. Create a class ABaseInteractableActor (you can create an interface instead);
  2. Make a variable in the character of type ABaseInteractableActor (or of the interface type);
  3. The button actor contains a trigger; when the character overlaps the trigger, the button actor writes itself into the character’s variable, and sets it to nullptr when overlap ends;
  4. In the character class, when you press Use, check if that variable is valid, and if it is, call the needed function in the button actor.
1 Like

An option could be: Create a c++ interface with a multicast delegate. Apply the interface to your character (c++) and use that delegate to broadcast on every interaction. On the door, add a sphere component that checks every overlapping pawn for the interface, if found bind a function to the delegate and unbind on end overlap.

You won’t need to include the character class in the door, just the interface. So if the player is overlapping and presses a button, everything bound (the door in this case) will know btn was pressed and will do stuff.

Maybe you could add a trigger box around the button and bind pushing behavior of the trigger box’s OnComponentBegin/EndOverlap events .

Thanks, but I’m dealing with this all the day and I don’t know how to do it.

I have added this header file using Visual Studio to do it.

#pragma once

#include "EnableActionButtonTriggerInterface.generated.h"

UINTERFACE(MinimalAPI, Blueprintable)
class UEnableActionButtonTriggerInterface : public UInterface
{
    GENERATED_BODY()
};

class IEnableActionButtonTriggerInterface
{
    GENERATED_BODY()

public:
    /** Add interface function declarations here */
};

After that, I have closed Unreal Editor and Visual Studio, generate Visual Studio projects, and compile the project.

But I get some errors, one of them is:

Cannot open file EnableActionButtonTriggerInterface.generated.h.

And now, I don’t know how to continue.

  1. Is it correct the way I have added the header file?

  2. How do I have to continue?

  3. Is there any example find code file to see what I have to do?

I have found how to add an Interface from Unreal editor:

I continue looking how to add the multicast delegate. Stay tuned!

I’m trying to create a multicast delegate but I don’t know how many parameters do I have to put.

Are there any rules about how to declare the multicast delegate?

I’m reading Multi-cast Delegates | Unreal Engine 4.27 Documentation, but without understanding anything (sorry).

Thanks!

It can be a bit confusing.

Here is a quick example:

  1. Create new c++ class and select Unreal Interface


    I called mine Interface_Interact, so it generated two classes in a single .h called UInterface_Interact and IInterface_Interact.

  2. Add your delegate in the .h:

// Above class
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FInteractMultiDelegate);
// ....
// In IInterface_Interact, under public
FInteractMultiDelegate InteractDelegate;

What you will use to bind will be InteractDelegate. That is all for this interface.

  1. In your characters .h, add the interface. To do that you must add the #include and then declare it. It should look something like this:
// No interface
UCLASS()
class AMyCharacter : public ACharacter
{
// ...
}

// w/ interface
UCLASS()
class AMyCharacter : public ACharacter, public IInterface_Interact
{
// ...
}
  1. To use the delegate, just use the declared InteractDelegate in the characters cpp. For example: I created an interact action and bound it to &AMyCharacter::Interact. This is all it does:
void AMyCharacter::Interact()
{
	InteractDelegate.Broadcast();
	UE_LOG(LogTemp, Warning, TEXT("[ AMyCharacter::Interact ] : Interacting"));
}

We are done with the interface and characters. All that is left is for the other actor to find the interface and bind itself.

  1. On the door actor, in the .h create a variable of the type of the interface:
TObjectPtr<class IInterface_Interact> ActorWithInterface;
  1. In the cpp #include the interface and in the overlap function check for it to bind:
// Try to save a pointer to the actor with interface
	ActorWithInterface = Cast<IInterface_Interact>(OtherActor);
	// Check if the actor had the interface
	if (ActorWithInterface != nullptr)
	{
		ActorWithInterface->InteractDelegate.AddUniqueDynamic(this, &AOverlapTriggerActor::TriggerDoor);
		UE_LOG(LogTemp, Warning, TEXT("[ AOverlapTriggerActor::SphereBeginOverlap ] : Binded"));
	}

By binding AOverlapTriggerActor::TriggerDoor we are telling to run that function everytime the player presses the interact input. We could also bind at the same time other functions from same or different classes to the same delegate.

  1. On end overlap you’ll need to unbind so that it doesnt get triggered even when pawn walks away:
	if (ActorWithInterface != nullptr)
	{
		ActorWithInterface->InteractDelegate.RemoveDynamic(this, &AOverlapTriggerActor::TriggerDoor);
	}

… and that’s it. Seems like much but think setting it up this way allows to keep minimum code in the character and everything else encapsulated in their respective class.

Character doesnt have to know what it is interacting with and the interactibles dont have to know it was the character that told them to interact.

Hope it helps.

1 Like