Function arguments within AddDynamic() call

I have a Tmap called CameraSetups and I’m trying to bind a Delegate (OnTriggerEnterDel) that was referred to in the Value to a function that would take a CameraActor as an argument. The CameraActor should be the respective Key to the Value but I can’t seem to find a way to pass this argument to the function.

for (auto& Elem : CameraSetups)
{
    // I need to somehow pass in the paired key to the function MoveToCamera
    Elem.Value->OnTriggerEnterDel.AddDynamic(this,&ACameraDirector::MoveToCamera);
}

void ACameraDirector::MoveToCamera(AActor* Camera)
{
	if (OurPlayerController)
	{
		if ((OurPlayerController->GetViewTarget() != Camera) && (Camera != nullptr))
		{
			// Blend smoothly to camera
			OurPlayerController->SetViewTargetWithBlend(Camera, SmoothBlendTime);
		}
	}
}

I am trying to modify CameraDirector that was presented in (Quick Start Guide to Implementing Automatic Camera Control in Unreal Engine CPP | Unreal Engine 5.1 Documentation) in such way that I would control the cameras using simple trigger volumes that broadcast a dynamic multicast delegate when a character overlaps the volume.
I was trying to use Tmap container to map references from the trigger volumes to their respective Camera actors that should then be transitioned to.

So I would like to know how to pass the argument within the AddDynamic() call.
I’m probably missing something here so some alternative approach suggestions are welcome.

Now I know that I can pass arguments through the broadcast in the TriggerVolume but I would like to keep the TriggerVolumes away from the tasks of the CameraDirector as much as possible.

For anyone looking for the answer: You can’t. The reason is that the Dynamic delegates survive serialization, and getting arbitrary bound arguments to work like that is … somewhere between “very hard” and “impossible in the general case.”

The work-around is to either declare a separate delegate that takes a struct of all the data you need, and then re-dispatches, or you need to create a small UObject that has UPROPERTY() for each argument it wants to forward, has the appropriate function signature for the dynamic delegate, and then forwards to the target callee. The problem is that delegates use weak object refs, so the delegate itself won’t keep this UObject alive, and you have to keep it around somewhere yourself for it to survive.

UCLASS()
class UMyDelegateTrampoline : public UObject {
    UCLASS_GENERATED_BODY
public:
    SomeBoundType *MyInstance;
    AWhateverTarget *Target;

    void MyDelegateImpl(TheDelegateArgType *Value) {
        Target->MyCallbackFunction(Value, this->MyInstance);
    }
};

Now, create a UMyDelegateTrampoline, fill it in with your augmented “MyInstance” value, as well as the Traget that you will call into, and bind that to your AddDynamic() call.

1 Like

Clever. Great solution. Do you still use this workaround or maybe there’s something better?

This is as good as it gets with the current system unfortunately.
It works, it’s just more fingers on keyboard time needed…

1 Like