I’m sure this is basic, but can’t seem to figure out how to have one variable hold UObjects of same parent and have access to its functions. I can do it with Blueprints, but the idea is 100% C++ for this specifically.
This is what I have:
// In Actor Component
switch (ClassDefaults.CurrentState)
{
case ENUM::StateOne:
if (StateOne)
{
StateOne->Update(DeltaTime, WorldTime, ClassDefaults);
}
break;
case ENUM::StateTwo:
if (StateTwo)
{
StateTwo->Update(DeltaTime, WorldTime, ClassDefaults);
}
break;
}
ClassDefaults is a struct with TEnumAsByte< ENUM > CurrentState;
UStateOne and UStateTwo are both from the same parent: UBaseState.
Just store the pointers of the children as a pointer of the base class, then cast to the child class to get the overriden function?
//Make ClassDefaults.CurrentState of type UBaseState
//Assign CurrentState with child class objects normally, implicit upcast to UBaseState occurs
UChildState* foo;
ClassDefaults.CurrentState = foo;
//Call Update after downcast back to child class
if(ClassDefaults.CurrentState)
Cast<ClassDefaults.CurrentState::StaticClass()>(ClassDefaults.CurrentState)->Update(DeltaTime, WorldTime, ClassDefaults);
This won’t work. Template parameters must be compile time constants. You can’t Cast to a runtime value like the return value from StaticClass.
@pezzott1 What is the specific problem that you’re encountering? Your “Something like:” code is perfectly reasonable and should work fine. Why don’t you want to depend on the enum?
Personally, I’d recommend your Update parameters be ( float, int32, const Defaults& ) but that shouldn’t matter towards getting your state machine working.
The problem I’m having is that I keep getting a nullptr. Will share later what I’ve tried.
Feel like my approach with enums is forcing me to hard code each state in the switch, even when it’s all copy / paste just changing the variable name. I’m looking for a solution that automates adding / editing / removing states.
Hmm… One thing I would suspect from your typename would be that because Defaults isn’t a USTRUCT (since if it was it would be FDefaults) your references to the class objects aren’t visible to the Garbage Collector and are getting destroyed. But then you should be hitting garbage and not nullptr. You haven’t shared enough yet for me to give you anything definitive though.
I can see how it would seem that way. However you can do this:
ClassDefaults.NextState = ClassDefaults.States[ static_cast< int >( ClassDefaults.CurrentState ) ];
to use the enum as the direct index into the array. This will work as long as all the enum values are valid array indexes. Another option would be to use a TMap, which would allow you to do TMap< ENUM, UBaseState* > which is a bit harder to setup but would avoid the casting and ignore any of the actual values of the enumeration.
Either way, I would recommend changing up your enum to be declared as:
enum class ENUM : uint8
and drop the use of TEnumAsByte. That’s an old workaround that is unnecessary with the .27 and EA versions of the engine you’ve tagged the question for.
Maybe I don’t get what you are trying to do, but isn’t something like this?
class UBaseState
{
public:
virtual void Update() = 0;
};
class State1 : BaseState
{
public:
void Update()
{
printf(“Update from A”);
}
};
class State2 : BaseState
{
public:
void Update()
{
printf(“Update from B”);
}
};
…Pseudo-code follows
arr = array of BaseState
arr[0] = new State1();
arr[1] = new State2();
arr[0]->Update(); // Update from A
arr[1]->Update(); // Update from B
You shouldn’t be using TSubclassOf for CurrentState. That should just be UBaseState *CurrentState;
The reason it’s failing is because when you access it, it tries to return the UClass for a class that is derived from UBaseState. That’s not what you’ve assigned to it. You’ve assigned to it an instance of something derived from UBaseState and UBaseState is not a UClass.