Hi there,
Abstract:
I am currently trying to build a well structured class hierarchy for a game, where you can fly with planes.
My plane has some (sub-)parts which must have the ability to inform my plane that something has changed,
so that the plane updates its current settings.
Specific:
I have a plane with properties like health, speed and upgrades. Upgrades can either improve health, speed or both at the same time.
I don’t want to store all these data(health, regeneration, …, speed, acceleration …) in one single class. So I wrap them up into
- Health
- Engine(Propulsor - handles speed)
- Upgrades
or in code:
UCLASS()
class FLYING_API UPlane: public UObject
{
GENERATED_BODY()
public:
class UHealth* Health;
class UPropulsor* Propulsor;
class UUpgradeManager* UpgradeManager;
void CalculateCurrentSettings();
}
My problem is especially the UpgradeManager.
The UpgradeManager holds all the Upgrades which were added to my Plane.
To modify my upgrades, I would call: MyPlane->UpgradeManager->changeUpgrade(/whatever options/);
Since Upgrades are holding additional data which can influence my health or my speed, my Plane
has to know when it has to calculate its current settings again.
This means after a call of
MyPlane->UpgradeManager->changeUpgrade(/whatever options/);
I have to call
MyPlane->CalculateCurrentSettings();
from within the UpgradeManager.
Here are my ideas:
At first I thought about something like an Observer Pattern.
My Plane listens on my Upgrademanager for changes. And if the Upgrademanager informed the Plane of a change, the Plane would call the CalculateCurrentSettings()-function.
I am not sure If I want to expose a listener or addListener/removeListener-functions in the UpgradeManager.
I also thought about initializing my Upgrademanager with a function pointer to my MyPlane->CalculateCurrentSettings()-function. Then I could simply execute the function behind this pointer
after I changed an Upgrade.
In this case, I have no clue how this will work, if I further inherit classes from UPlane.
(Is the pointer to the CalculateCurrentSettings() still holding in the UpgradeManger even if I override my CalculateCurrentSettings-function in my inherited class?
Do I have to initialize my UpgradeManager again?)
Questions:
- Is this class hierarchy well designed?
- What is your opinion to these 2 ideas?
- Does another design pattern exist for this case?
- I also heard something of delegates, but I am not entirely sure of the use right now.
Some other questions in this context:
Currently I want to design my AFlyingPawn like this:
class AFlyingPawn: public APawn
{
GENERATED_BODY()
class UPlane* MyPlane;
// ... more code
}
With switching my MyPlane, I can “load” my properties for this pawn.
(MyPlane holds again health, speed and upgrades).
My player controller would create/posses such an AFlyingPawn.
Then it would init it with my UPlane, which is stored in my player controller(or somewhere else).
AFlyingPawn->init(PlayerController->PlayerPlanes[0]);
The AFlyingPawn would than act/fly based on the properties given through the UPlane-Object.
Questions:
- In example codes properties like health, speed, ammo are placed directly into the Pawn. Is it not encouraged to wrap these flat data?
- Especially for regeneration I am going to need a tick-function. Has an UObject a tick function? Or do I have to design such behaviour inside an AActor?
- In my constructor of AFlyingPawn I had some struggles with calling the constructor of UPlane. When should I use NewObject, NewNamedObject, ConstructObject or CreateDefaultSubobject?
Im still very new to this topic in general and right now I am pretty much confused with all these extra decorators for properties, several constructor, separate init-functions and so on…
So thanks for helping, it’s much appreciated
And another question: When should I use this forum and when the Answerhub?