Creating an Object based on TSubclassOf & calling a BlueprintNativeEvent

Hello everyone,

I’m working on a small side project that has RTS controls. When the player clicks on a unit and then clicks on another unit, the unit should perform an action so I thought I would implement an action system. What I’ve done so far is create an Action_Base class derived from UObject, it has some basic logic like:

//returns true or false based on whether or not we can perform an action on this object 
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Action")
		bool CanPerformActionOn(UObject * obj);

	//Requests that we do the action on the specified object - mostly meant to handle timer logic
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Action")
		bool RequestActionOn(UObject * obj);

	//Does the specific action stuff
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Action")
		void DoAction() const;

	//fires off when the action succeeded
	UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "Action")
		void ActionSucceeded() const;

	//fires off when the action failed
	UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "Action")
		void ActionFailed() const;

The unit has this:

    //actions this agent comes with
    	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Actions")
    		TArray<TSubclassOf<UAction_Base>> actionClasses;
    
    	//the actual actions
    	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Actions")
    		TArray<UAction_Base *> actions;

When the unit is created, I initialize its actions as follows:

for (int i = 0; i < actionsToSpawn.Num(); i++)
	{
		UAction_Base * newAction = NewObject<UAction_Base>(this, NAME_None, RF_NoFlags, actionsToSpawn[i].GetDefaultObject());
		if (newAction)
			actions.AddUnique(newAction);
	}

I then went into unreal and made a blueprint subclass of Action_Base called DebugPrintStringAction. All it is meant to do is print “hello” when the unit performs the action. I overwrote the functions above and added printstrings in them.

When the time comes and I call RequestActionOn, it fires the C++ logic, but not the specific blueprint logic I overwrote. It seems the actions that are created are Action_Base classes and they are unaware of the subclass that was passed in the TSubclassOf variable. I even tried casting the created action to the specific subclass then calling the function but the cast always fails which tells me I don’t seem to understand what TSubclassOf is meant to do or I am using it wrong.

Does anyone have any pointers on this? I thought it might be strange that I am using objects? Is there something else I should use for something like this? Is there something fundamentally wrong with how I am understanding the whole TSubclassOf an object and how I am creating it?

Thanks for the help!

You not passing UClass pointer (which TSubclassOf stores), insted NewObject creates class defined in template argument which is UAction_Base and you only pass CDO of class you wanted as template, which only transfers defaults and thats it, but you creating UAction_Base .

You need to give actionsToSpawn[i] as 2nd argument, and those 2 arguments (outer and class) should do the job, the rest is optional:

So:

NewObject<UAction_Base>(this, actionsToSpawn[i]);

Maybe template argument confuse you, main purpose of it is auto casting, so function return already proper type of pointer, but if class is not defined in function arguments function it gonna use class from template, it is optional feature, normaly class should be defined in function arguments (UClass pointer, which TSubclassOf is just special template storing it to limit selection to specific class relation).

Since you creating instance of UAction_Base instead of blueprint class, blueprint does not get executed at all