How to change the parent class of `APawn`?

I use an Actor Component to add a behavior to my actors and pawns.
Now I realized that literally all of my actors and pawns have that component,
thus I created classes AMyActor and AMyPawn and do the setup of the component in there and all my actors and pawn inherit from MyActor and MyPawn.

So far so good.

I still have code duplication, because the setup work happens in both, AMyActor and AMyPawn.
That is some code in the constructor and the OnConstruction script.

Now I wondered: I might as well have APawn directly inherit from MyActor instead of AActor. But how do I go about it?

Just changing code inside “Pawn.h” shouldn’t exactly break stuff, but I don’t know.

Another option is to literally copy “Pawn.h” and “Pawn.cpp” into my project and make the changes there.

Any pointers to what is best practices here?

Perhaps create a class that inherits from Pawn, add your code, then change the parent of your other classes to your new custom. ?

Do you mean all my actors will inherit from MyPawn?

That would work, but I don’t want my actors to have all the pawn code.

Hey, I apologize for not elaborating. As a suggestion meant inherit to create custom parent classes for the actors and pawns accordingly for the scope of the project without editing engines default (unless you dont mind to do so). This is what I would do (and am currently doing in a relatively small project).

Would also like the opinion of other more experienced since this interests me as well.

Pawn inherits from actor so theres also the option to modify that class in your case.

1 Like

Yeah, creating custom parent classes MyActor and MyPawn just means code duplication.

Indeed, if I modify engine code, I have two options

  • modifying the AActor (which will affect APawn automatically)
  • create MyActor and modify APawn to inherit from MyActor

Duplicating a little code in Actor and Pawn (and Character, for that matter) are pretty much going to be staples of working in UE5.

Hacking the engine to save yourself a few lines of cut/paste is not a time efficient choice. Maintaining hacks on the engine long term will take vastly more time and energy than just copying a few lines of code in your actor/pawn/character class.

3 Likes

I guess you are right.

Modifying engine code doesn’t seem worth it.

I tried to copy APawn into my project, but this causes all kinds of problems, too. I don’t even understand all the compiler errors, but the ecosystem is built around the fact that there is exactly one pawn implementation. Renaming to AMyPawn breaks delegates (and other stuff, apparently).

Generally any time you find yourself needing to modify Engine code, that should be a red flag that there is probably an easier way to do something.

There are definitely times when you MUST modify the engine, but in general that’s not something you WANT to do, if it can be avoided.

As for Pawns, Epic does not generally use pawns for anything. They make shooters, and everything they do is a Character.

They provide the Pawn so you can use it instead of a Character, in case you need something with a non-capsule primitive as its root component, but if you go that route, you will have A LOT of code duplication to make the Pawn even close to the level of functionality of the Character.

This is by design and it’s just a necessary evil.

The majority of UE projects, it seems, just uses the Character class and ignores the Pawn. If you decide you want custom pawns with custom movement etc, that’s a perfectly valid choice, but involves a lot of code duplication. 10,000s of lines of code. (Either that, or buy plugins others made where they did that code duplication for you).

The easiest way to work with UE is just to ignore the Pawn, and use the Character as a base instead.

1 Like

One final thought, if you really have some functionality that is common to different types of actors, then you should consider implementing that as a component.

It’s very easy to add a component to an actor, a pawn, a character…

Try to put AS LITTLE functionality into the Actor/Pawn/Character as possible, and AS MUCH as you can into components that you can just attach to those.

It’s way better for future code reusability that way.

I am happy with APawn.

I am abusing Unreal Engine for a game that is nothing like a shooter (lacking a better term for the type of game that UE is made for). The movement component of ACharacter doesn’t work for me.

Btw, I thought APawn is useful for shooter-style game, e.g. to implement bots.

My solution is a component, together with a C++interface, to get the component from actors and pawns alike

Cf. projectzero/ActorComponentInterface.md at main · rubenmoor/projectzero · GitHub

To clarify, they use pawns in their games. They just don’t provide engine code for replicated pawn movement.

So if you want to use a character, they do all the work for you. If you want to use a custom pawn, you have to do all that work yourself. (Or buy one of the plugins that does it). Anyway, that work is not included in the engine.

This is a well-known problem in object oriented class hierarchies, related to the “fragile base class problem” and “god object” anti-patterns. (And one of the valid criticism of object-oriented design, btw.)

You will have to fork the engine, build it yourself, and update APawn to derive from AYourActor – there’s no way to do this as a “plug-in,” because the inheritance of APawn is baked into the built engine and editor.

If your main concern is just code duplication, and the class duplication is OK for you, then you could break the common setup out into a separate free function, and call that free function from both places. If the function needs some standard class members, you’ll probably want to make that a template function, that takes a pointer to an object of any class that has those members.

You could also use the template-inherits pattern to build the standard setup. You’d make AYourActor and AYourPawn derive from YourTemplate<AActor> and YourTemplate<APawn> respectively. Except I’m not sure UnrealHeaderTool will be very happy with that.

2 Likes

Thanks for the idea with a templated function.

The template-inherits pattern seems more interesting, still. I will try that out.

And yes, this is just about code duplication. But code duplication leads to complexity that is avoidable by some better design (usually). I already shoot myself in the foot on a regular basis when I don’t remember where (or if at all) I implemented some functionality - Unreal doesn’t only provides endless option to implement this or that, often it’s difficult to say with certainty where stuff belongs.

The sum of those ambiguities make up the complexity that will slow me down in the long run, when implementing new features, but also when I try to refactor my code.

I now managed to reduce my problem a step further.

I am using the pattern where I have a corresponding interface for my component.

Say, UMyComponent and IHasMyComponent.

This interface provides a getter:

virtual UMyComponent* GetMyComponent() = 0; // using C++-exclusive interface

… but: I can use the interface to enforce properties on the original actor.
This way, adding MyComponent to some actor and forgetting about the interface results in a run-time error right away.

Then, adding the interface without implementing its purely virtual functions results in a compile-time error, even better.

Before, I needed to set up my component with data from the owning actor.
Now I enforce the data to be present by the interface at compile-time. Much nicer.

This way, I don’t mind the code duplication as much.

I have difficulties implementing the template-inherits pattern.

Let’s see what the C++ community says.

First: You don’t actually need to restrict to a subclass. If the template doesn’t work, you’ll get a compiler error anyway.

template<typename Base> class MyThing : public Base {
public:
    MyThing() : Base() {
        Component = CreateDefaultSubObject<UMyComponent>();
    }
    virtual void OnConstrction() override {
        Base::OnConstruction();
        Component->Whatever();
    }
    // I don't think UnrealHeaderTool likes this in a template, unfortunately
    UPROPERTY()
    UMyComponent *Component;
};

If the base class doesn’t have the right constructor, or a virtual OnConstruction() to override, the template will fail and you’ll be told about it.

There are also special tricks you can play with partial specializations to opt in only specific classes. Or you can use the address of a member as a default template argument.

template<typename Base, void (*Base::Func)() = &Base::OnConstruction> {
    // Base must have an OnConstruction method
};
template<typename T> struct IsSupported {};
template<> struct IsSupported<AActor> { enum { Yes = 1 } };
template<> struct IsSupported<APawn> { enum { Yes = 1 } };

template<typename Base> class MyClass : public Base {
    enum { Yes = IsSupported<Base>::Yes };
    ...
};

There’s even fancier ways to do this, especially in C++20 lumbering towards “concepts,” but again, I think the main challenge for this stuff might be the UnrealHeaderTool.

There’s nothing wrong with a free function.

template<typename T> void MyInitialize(T &t) {
    t.TheThing = whatever;
    ...
}

UCLASS()
class AMyPawn : public APawn {
    ...
public:
    void OnInitialize() override {
        Super::OnInitialize();
        MyInitialize(*this);
    }
};
1 Like

You can wrap code in

#if CPP
...
#endif

for UHT not to parse it. There are a couple of examples in the engine already e.g. https://github.com/EpicGames/UnrealEngine/blob/46544fa5e0aa9e6740c19b44b0628b72e7bbd5ce/Engine/Source/Runtime/Engine/Public/PerPlatformProperties.h#L174. But as already pointed out UPROPERTY won’t be useful in those. You may be able to derive from FGCObject and implement AddReferencedObject or use a WeakObjectPtr instead if the main concern is garbage collection.

Not sure whether that’s going to work though due to the way subobjects are instanced (I doubt it but would like to be proven wrong :D)

1 Like

Yes a component works well as an interface for different types of actors.

I was working on a plugin for creatures and encountered the similar issue. Initially I created a base class of all creatures, and a player character inheriting it. Issue emerged when bringing them to my project: game animals inherit creature and game players inherit player character, and their hierarchy is not as expected.
Finally I made only one character class and add all additional functions (player controlling, monsters, NPCs,…) in independent components. By browsing specific components in the character instance you can easily identify what class it is. To add new functions, simply define new components and add to your actor.

1 Like