Skip to main content
gamedev.net
🔒 Locked

Structuring the Entity Hierarchy

Started by swiftcoder Feb 25, 2008 at 8:30 AM 7 replies 1.8k views
Original Post
swiftcoder
swiftcoder
I am having a little conceptual trouble with my new-fangled entity system, perhaps stemming from my OOP background. First a few technical details, the game is a space sim, implemented in python. It is an outboard-component entity system, and as much as possible is event driven (i.e. only rendering and physics have an update tick, everything else reacts to events). Entities are just empty python classes, to which any data or functions may be directly attached. Everything in game can affect the gamestate in some way is represented by an entity, but the entities can be broken down into subsets by common attributes. For instance, at a basic level we have 'ship' and 'planet' entities, where 'ship' can be broken down into specific classes of ship, such as 'viper' and 'raptor'. Obviously, every 'ship', whatever type it may be, will share the majority of attributes, so what would be the best way to represent this setup? Should I just define a factory for each type of entity, which initialises the entity with the necessary attributes? Or would it make sense to actually set up an entity -> superclass relationship?
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
speciesUnknown
speciesUnknown
Don't hard code your ships. Instead, load some of the properties from file, and store them somewhere. Then, when you spawn a ship, simply copy its data into the newly created object. One thing that can cause a project to become top heavy is an overly rigid class heirarchy.
Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!
speciesUnknown
speciesUnknown
I'll give you an example. My game has zombies, vampires, and werewolves. I have one class for characters, one class for human players, and one class for Ai players. the character class is controlled by either an AI character or a Human character, which has a pointer to its character. Everything that makes a zombie different from a vampire is loaded from file. The models (.md2 files) have different animations e.g. they all have their own unique "death falling forwards" animation, and their own unique "attack player" animation, but the character class is unaware of that difference, because the AI is in charge of how they actually move, and which animations they play at what speed.

(n.b. all my baddies are bipedal for reasons of simplicity)
Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!
Sneftel
Sneftel
Quote:
Original post by swiftcoder
Obviously, every 'ship', whatever type it may be, will share the majority of attributes, so what would be the best way to represent this setup? Should I just define a factory for each type of entity, which initialises the entity with the necessary attributes? Or would it make sense to actually set up an entity -> superclass relationship?

The line between the two is very thin in Python. I'd advise the class hierarchy approach, simply because it's more idiomatic.
swiftcoder
swiftcoder
Hmm, you triggered another part of my brain, and it appears as if my whole question may be moot. Here is an example, the contents of 'data/entity/raptor.entity', as an XML dump:
<Entity>	<Attribute name="Name" type="string" value="RAPTOR light interceptor" />	<Attribute name="Graphics" type="string" value="data/scene/raptor.scene" />	<Attribute name="Physics" type="string" value="data/physics/raptor.phys" />	<Attribute name="Speed" type="number" value="200" />	<Attribute name="TurnRate" type="number" value="100" />		<Attribute name="MaxHealth" type="number" value="200" />	<Attribute name="MaxShields" type="number" value="100" />		<Attribute name="Health" type="number" value="200" />	<Attribute name="Shields" type="number" value="100" />	<!-- more attributes --><Entity>

(this is perhaps misnamed, as it is loaded into a factory object, which when invoked produces an exact duplicate of this entity specification)

When the entity is added to the world, the Graphics and Physics components will each load an internal component, a scene hierarchy and simulation/collision data respectively.

There doesn't seem to be anything here that would benefit from a 'Ship' super class, because even though all ships share a set of attributes, the values are different for each class of ship.

Thanks for your responses, and my apologies for not thinking this through to completion in advance...
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
speciesUnknown
speciesUnknown
Quote:
Original post by swiftcoder
Hmm, you triggered another part of my brain, and it appears as if my whole question may be moot. Here is an example, the contents of 'data/entity/raptor.entity', as an XML dump:
*** Source Snippet Removed ***
(this is perhaps misnamed, as it is loaded into a factory object, which when invoked produces an exact duplicate of this entity specification)

When the entity is added to the world, the Graphics and Physics components will each load an internal component, a scene hierarchy and simulation/collision data respectively.

There doesn't seem to be anything here that would benefit from a 'Ship' super class, because even though all ships share a set of attributes, the values are different for each class of ship.

Thanks for your responses, and my apologies for not thinking this through to completion in advance...


This system is pretty much what I meant, if by "Factory Object" you mean

ShipFactory * the_factory = new ShipFactory();
Ship * the_ship = the_factory->give_me-a_ship("raptor",100,vector(10,9,18));

Thats what I do, except (analogously) my pointers to the ship are stored in the ship factory and the ship factory is in charge of updating all the ships I spawn. if that makes any sense.

And don't apologise, other people will ask the same question at some point and find your thread.
Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!
swiftcoder
swiftcoder
After reading this very interesting discussion, I decided to evolve my entity system a little.

Now when an outboard component attaches to an entity, it may extend that entity with functions as well as data, for instance when the Physics component attaches to an entity, it adds a set of methods to that entity, something like this:
class Physics:	def on_entity_added(self, entity):		if entity.has("Physics"):			self.load_collision_data(entity)						entity.thrust = instancemethod(...)			entity.cease_thrust = instancemethod(...)			entity.yaw_left = instancemethod(...)			entity.yaw_right = instancemethod(...)			entity.cease_yaw = instancemethod(...)


This means that my AI component no longer needs access to the Physics component at all, and can just call those functions directly on the entity. Which seems to streamline everything, except for the nagging voice in my head which says that the AI still depends on the Physics component indirectly, and I may have just made this system a great deal harder to understand...

Does this strike you as a good idea? Has anyone tried a similar approach?
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
Sneftel
Sneftel
Sure, sounds reasonable. Much of the outboard design I came up with was designed to cope with shortcomings of C++. In Python, less circuitous solutions may be possible.
swiftcoder
swiftcoder
Quote:
Original post by Sneftel
Sure, sounds reasonable. Much of the outboard design I came up with was designed to cope with shortcomings of C++. In Python, less circuitous solutions may be possible.


Ja, the discussions around your thread made much of the reason I decided to use exclusively python for this.
Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.