Delegate does not bind

It being “cut down for relevance” impacts the ease of debugging here. For example I see no assignment to ContainerInstance which as well might be the bug.
Have you attached VS to the UE4 process and set breakpoints in VS? When you attach VS to the UE4 process you can debug every single line without having to print debug messages. Set breakpoints to verify what lines the code execution does reach. If there are no errors during compilation then the delegate binding itself will be fine.

I’m working on a small strategy game and one of the things I need is to register the units spawned to the game logic, which I’ve chosen to store in the Gamemode. I figured the best way to do this is to use Delegates and in my research on how to apply them I have copied the syntax of the many examples I’ve found online but for some reason my Delegate fails to bind. This is my code (cut down for relevance):

GenericUnitContainer.h

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "GenericUnitContainer.generated.h"

UDELEGATE()
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FUnitContainerSpawned, AGenericUnitContainer*, 
UnitContainer);

UCLASS()
class RTSGAME_API AGenericUnitContainer : public AActor
{
	GENERATED_BODY()

public:
	// Sets default values for this actor's properties
	AGenericUnitContainer();

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	UFUNCTION()
	bool InitializeContainer();

	UPROPERTY(BlueprintAssignable, Category = "Event Dispatchers")
	FUnitContainerSpawned OnUnitContainerSpawned;
};

GenericUnitContainer.cpp

#include "GenericUnitContainer.h"

// Called when the game starts or when spawned
void AGenericUnitContainer::BeginPlay()
{
	Super::BeginPlay();
	UWorld* WorldPtr = GetWorld();

	// Call initialisation function to make sure container is properly registered and 
        assigned to a player.
	if (WorldPtr != nullptr)
	{
		InitializeContainer();
	}
}

bool AGenericUnitContainer::InitializeContainer()
{
	// Add Unit Container ID to universal array.
	if (OnUnitContainerSpawned.IsBound())
	{
		GEngine->AddOnScreenDebugMessage
            (-1, 5.f, FColor::Cyan, TEXT("Delegate is bound!"));

		OnUnitContainerSpawned.Broadcast(this);
	}
	return true;
 }

GameMode.h

#include "GenericUnitContainer.h"

UCLASS()
class RTSGAME_API AGameMode_Default : public AGameModeBase
{
	GENERATED_BODY()
	
public:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	UPROPERTY()
	AGenericUnitContainer* ContainerInstance;

	UFUNCTION()
	void AddUnitContainerToWorldArray(AGenericUnitContainer* UnitContainer);
};

GameMode.cpp

#include "RTSGameGameMode_Default.h"

// Called when the game starts or when spawned
void ARTSGameMode_Default::BeginPlay()
{
	Super::BeginPlay();

	if (ContainerInstance)
	{
		ContainerInstance->OnUnitContainerSpawned.AddDynamic(this, &ARTSGameMode_Default::AddUnitContainerToWorldArray);
	}
}

void ARTSGameMode_Default::AddUnitContainerToWorldArray(AGenericUnitContainer* UnitContainer)
{
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Purple, TEXT("Adding Unit Container to World Array!"));
}

Using debug messages I’ve been able to determine that IsBound fails, so my conclusion is that the delegate fails to bind for some reason but after trying to figure out myself and failing I was hoping someone could point to what I’m doing wrong here.

Thanks in advance

If I correctly understand what I’m looking at, you want the spawned unit to broadcast the message, but you’re trying to bind to the delegate before the unit is spawned? I don’t see how that’s going to work at all.

Which class spawns the units? Maybe create your delegate there, and let it broadcast the message with the reference to the newly spawned unit.

With “cut down for relevance” I mean that I removed all the functions that have nothing to do with this issue. As for the assignment, what do you mean exactly?

That’s an interesting point, and something I’ve been considering while examining the logic in what I’m trying to accomplish. At this moment, I’m trying to build the base functionality for the game. Right now no class spawns the units, they are placed in the editor as a blueprint class derived from the base C++ class. Is the answer that I should code a spawner first as I realised that that might be a better solution as I could just add them to an array. I didn’t know it was impossible to bind a delegate before a class is spawned. I assumed delegates superceded that.

You can’t bind to a delegate in a generic class, you can only bind to the instance of that class. If you have units placed into the level, you can bind to the delegates of those units one by one (in a ForEach loop etc.).

And yes, having a class that spawns the units and then broadcasts messages about it seems the most viable way to go, since you can manually place in into the level and then bind to its delegate.

Here:

UPROPERTY()
AGenericUnitContainer* ContainerInstance;

You only declare the pointer. Pointers don’t have default values like generic variable types (int32, FString, etc.), so it is nullptr. Until you set its value somehow, you can’t do anything with this variable, because you’ll try to work with the empty portion of the memory. In order to use ContainerInstance, you first have to assign a value to it, which must be an instance of the AGenericUnitContainer class. And this is basically what I wrote in another comment of mine below.

Based on your feedback, I did some more research and I fixed it by including GameplayStatics.h and casting to the gamemode instead` of using a delegate. I also ditched the array and instead used a TMap to register the units.

GenericUnitContainer.cpp

bool AGenericUnitContainer::InitializeContainer()
{
	// Add Unit Container ID to universal array.
	RTSGameMode_Default* CurrentGameMode = Cast<RTSGameMode_Default>(GetWorld()->GetAuthGameMode());
	CurrentGameMode->AddUnitContainerToWorldArray(ContainerName, this);
	return true;
}

RTSGameMode_Default.cpp

void RTSGameMode_Default::AddUnitContainerToWorldArray(FName UnitContainerFName, AGenericUnitContainer* UnitContainer)
{    
	ActiveUnitContainers.Add(UnitContainerFName, UnitContainer);
}

The reason I don’t want to have to spawn through another class is because I want to be able to place units in the editor that will register themselves upon spawn so I don’t have to reconstruct everything upon BeginPlay. Thank you!