To me it seems like Unreal lacks something built-in to cleanly represent a manager class, such as a class to represent all actors of a given type. Say I have an AActor called ABuilding, I likely then want a BuildingManager class.
Using AActor seems inappropriate since the manager has no physical representation.
Using UObject seems inadequate because there is no Initialize/Deinitialize/Tick.
Using a subsystem is also a poor match.
Am I missing something?
I assume most people use an AActor and ignore the wastage.
AInfo is used for Actors that don’t need a representation in the world but since it inherits from AActor it can still be used for replication.
It is used by various GameFramework classes like GameMode and WorldSettings.
Nothing stops you from creating your own manager based on UObject but if by wastage you are talking memory usage then you got to have a serious amount of managers for that to be of any concern.
Looking at AInfo I think you’re right, that’s the intended.
/**
* Info is the base class of an Actor that isn't meant to have a physical representation in the world, used primarily
* for "manager" type classes that hold settings data about the world, but might need to be an Actor for replication purposes.
*/
UCLASS(abstract, hidecategories=(Input, Movement, Collision, Rendering, HLOD, WorldPartition, DataLayers, Transformation), showcategories=("Input|MouseInput", "Input|TouchInput"), MinimalAPI, NotBlueprintable)
class AInfo : public AActor
It inherits from Actor but hides certain categories of properties in the editor.
I guess with inheritance hierarchies you tend to tend to compromise between simplicity and overhead. Perhaps a future version of Unreal will be flatter with more composition.
Honestly I never really liked the AInfo approach that much. It feels too much like a workaround to me. Being an Actor forces you to deal with things like how to spawn it (or place it in a level) and where to get that reference from (quickly leads to Get All Actors Of Class).
Personally I prefer ActorComponents for this use case. It gives the most flexibility in my opinion. You get the BeginPlay/EndPlay/Tick functionalities you were missing from just plain UObject but you avoid the problems of having a (limited) Actor. The component can be attached to the GameMode or GameState depending on whether it needs to replicate or whether it’s only needed on the server. Both GameMode and GameState already act like singletons which allows you to access the component from (almost) anywhere. Of course if you have that component you can still decide to attach it to an AInfo as well in case you decide to go down that route.
If you don’t need replication, need no actor and look for something even simpler, just use UObject. If what you are looking for doesn’t need an instance, use a static utility library. In some other cases I go for a subsystem, usually when there is a single system managing things on for example the game instance, like the zombie spawner in left 4 dead could be, or the system managing all music for the game.
I’d say a manager does have location requirements because level designers might want to change its settings in the editor. It would make sense to have the manager located in the map near or central to the things it is managing.
@UnrealEverything I think I found a reason to not use UActorComponent for a manager: you can’t add a UActorComponent to an UActorComponent, AFAIK. But a manager might want to use a UActorComponent.
I don’t think you should want to add a component to a component, they should be as independent as possible. You could still make a base class actorcomponent marked abstract and inherit specialized components from that. In reality it’s often much easier to have all components independent and even avoid that if you can.
If you can’t avoid having two components communicate (think of a custom movement component and a custom navigation component) then I’d make the navigation component injectable in a method of the movement component. say MyMovementComponent::MoveTo(MyNavigationClass, MyDestinationVector) or something similar. The more you mix communication between components or the actor they are on the more the code spaghettifies.
A great spagghetified example is actually the CharacterMovementComponent that ships with the engine.
What kind of other component were you looking to add? And would it be a problem if you’d add that other component to the Actor that already owns the manager component?
I wouldn’t want to restrict Managers to not being able to have components of their own.
In my case, every instantiated object in my game, including actors and managers, has a diagnostic component which by default shows its local role and netmode. This has been enormously helpful not only for learning how the framework works, but also for checking for objects that should or shouldn’t exist for a given role or at a given time.
These diagnostics are collected automatically. Here’s an example for a listen server and plain client:
Therefore my current conclusion is that AInfo is best.
It’s a little funny that AInfo derives from AActor and essentially subtracts some stuff. But that’s unsurprising when you’re dealing with deep inheritance hierarchies.