Componentization vs Polymorpism for similar object types?

Godot Version

4.2.2

Question

I’m rebuilding something I made in Unity. My game has a bunch of different objects like Rock, Tree, Sheep, Merchant, Bandit, etc. They’re basically all just tokens with data fields and some functions. In Unity, I used derived classes to build all of these off a base object, adding new fields to children to flesh out their game info.

All objects have a base class CoreObject. This contains basic data such as the object’s name, owner, visibility, etc.

TerrainObjects are children of CoreObject. They contain data for stuff like trees or rocks, stuff that just sits there. They hold fields like toughness, destructibility, scavenge value, etc.

ActiveObjects are also children of CoreObject. I used them for merchants, bandits, sheep—anything that moves or does things with its own decision making process. It contains data like the object’s speed, bravery, sight range, aggression, etc.

Finally, I have specific classes for things like Merchant, Enemy, Animal, etc, which are all children of the ActiveObject class. Merchants can buy and sell resources. Enemies will attack and fight back. Animals will run away if you attack them.

This all works pretty smoothly in Unity, but now I’m trying to adapt it over to the node structures in Godot. Pic below to help explain. Questions:

Would it be better to use the derived class approach:

CoreObject >> ActiveObject >> Merchant

Or would it be better to make each of these classes its own node:

A Sheep scene has a CoreObject node and an ActiveObject node and an Animal node, each with the fields and code needed for those components.
A Rock would have a CoreObect node and a Terrain node.

Or is there just a better way to do this and I’m way off base?

Pic for examples:

Hi!

More complex topic than it seems, but in your case, it seems to me that composition would do a better job than inheritance/polymorphism to keep your architecture clean and maintainable.
Inheritance feels almost natural at first for a lot of OOP programmers, but when it comes to architectures like yours, it quickly becomes inadequate imho.

Also, I haven’t been using Godot for a long time, but I feel like Godot and its node/tree architecture is made for node composition (hence, classes composition).

I would suggest this video on the topic, it’s short and well explained!

sounds like a lot of redundancy. godot already provides most of these like visibility and name.
think of what you really need to be in a script that is not already in a node. visibility would only matter if the object has to banish with an animation, otherwise just use the visible property.
also there can be more than one node with the same name as long as they don’t have the same direct parent.

limit this to one for each unique behaviour. it sounds like you have a tree and a rock being different classes when they could just have a health and resistances.
even if these must drop wood and stone, I would still use just one and instead use an export to select what they must drop.
the class must be the same, but what changes is that in godot you must create a scene for each unique game object.

why are these different? In most games if something has health, it is put into the base class and a character is destructible. and then it can be made unkillable to prevent them from being unalived.

Entity->Destructable->Character
                   |->Tree

I would also avoid putting everything in the same script, this is not a problem of composition vs inheritance, you need both.

as I said, both, because it depends on what we are talking about.
you don’t need a class for moving characters and a class for inanimate objects and a class for a merchant.

your root of scene should just control physics and provide a generic “interface” for a bunch of generic methods. these would test and return children nodes. but ONLY if there needs to be an interaction with the character.
for example, we have an NPC. we add an AI node to it. this AI node controls what the NPC does. we can have two inherited classes of AI, one for merchant and one for bandit.

then, we can use an Area3D called “trade”, which the character can interact with. we put this as children of the merchant and it would allow the player to trade (unless you want to control this from a dialog system). you just put the “trade” node on the character.

Good afternoon,

In addition to the advice of everyone else here, I just wanted to note that, from the looks of
your post, it appears you are tapping into concepts regarding abstraction of high-level
object-oriented programming, particularly with respect to programming to an interface.
I will start out by say I have never developed nor published any type of game (yet). However,
I do have experience working with Software Design patterns when I was studying for my
Bachelor of Science degree in Computer Science. It appears that what you are describing
and visualizing here, that is, your design of the software architecture of your game you
have previously worked with in Unity, appears to implement Software Design patterns by
programming to an interface to take advantage of OOP. To my knowledge, as you noted,
and as other replies here have suggested, Godot is a node-based Game Engine as opposed
to one that relies on traditional abstraction techniques. However, as noted in the Godot Docs,
and on GDQuest’s website, Software Design patterns can still be used in Godot, even within
GDScript, to structure the design of our software codebase to our needs (e.g. definining a
Finite State Machine for Player Movement, etc.). I will link those resources to you here in
this reply for your perusal, if you should find they might be helpful for you to use.
Best of luck, my fellow learner of Godot!

Godot Docs Software Design Patterns Free E-Book (PDF): Table of Contents · Game Programming Patterns

GDQuest Free Text-Based Tutorials on Software Design Patterns: Design patterns in Godot · GDQuest

1 Like

+1 on that one, I’ve read the book a few years ago and it’s reaaaally good!