Different varieties of a component being used by the same system?

Started by
5 comments, last by Kirlim 7 years, 2 months ago

I'm noticing that the nature of OOP inheritance is becoming a frustration in how I want to implement my project, and I'm considering moving to ECS.

What I'm interested in is whether there's a drawback to combining the two in a certain circumstance.

Say I have a "position" component, which basically just has world coordinates.

In my current implementation, some objects have a position which is dependent on other objects (for example, offset at a certain angle and distance from the parent object). At the moment, this is handled by some objects having getters for their position variables that return a position based on the position of the object they're attached to, and setters that apply the appropriate movement to their parent object.

Is that the same way you'd handle this in ECS? If there's a system that needs the position of an entity, and doesn't care whether that position is absolute or derived, would you have a component which instead of storing position, has an internal reference to another "position" component, and returns the coordinates based on the result of a getter? And then have the system see both of those components - the absolute and the derived position components - as identical?

Intuitively this seems like the right way to go, but I'm very new to ECS so I'd love to know if I'm missing a better way to do this.

Advertisement
I would simply have a position component that holds relative coordinates, and a pointer to an optional parent space. If the parent space is present, the coordinates need to be transformed into world space; otherwise they can be assumed to be in worldspace already.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

I'm noticing that the nature of OOP inheritance is becoming a frustration in how I want to implement my project, and I'm considering moving to ECS.
If inheritance is causing issues in your OOP code, switching to ECS isn't the answer; learning OOP properly is the answer. OOP teaches that you should use composition of components instead of inheritance whenever possible, and inheritance doesn't even get a mention in the core principles of OOP.

As for the hierarchy of positions problem... I would have every "position component" have two position values -- one "local position" (relative to parent) and and "global position" (relative to world) which is generated from the local data. At a specific point during the frame, I would iterate through all the position components and calculate all of the "global positions" from the "local position" data. This can be done most efficiently if the component pool is sorted so that parents always appear before their children -- in that case, the per-component update logic is basically this.global = this.local + parent.global.

Ask yourself this question: How is the position of an entity set? It could be:

- set by a physics library in response to forces/collisions, etc...

- explicitly set by code (e.g. drop a sword at this location)

- set by virtue of being attached to some other object at a particular offset

In all cases, this is just "some other code" that is modifying the same Position component class.

In your case, instead of having a special Position component that "calls into another object to get its position and offsets it by some amount", you would have code that says "this entity X is offset from entity Y by a,b,c" - that code would get entity Y's position, modify it, then push that to entity X's Position component.

Now, of course, having objects attached to each other is a common scenario, so you might consider formalizing this and having a LocalPosition component that has an offset and parenty entity reference - then you'd have a system that goes through all those and updates them each frame. You could also possibly combine local/global position into one component class, if that makes sense for you.

I'm noticing that the nature of OOP inheritance is becoming a frustration in how I want to implement my project, and I'm considering moving to ECS.
If inheritance is causing issues in your OOP code, switching to ECS isn't the answer; learning OOP properly is the answer. OOP teaches that you should use composition of components instead of inheritance whenever possible, and inheritance doesn't even get a mention in the core principles of OOP.

That said I remember almost all very early OOP literature and teaching back in the day was all very biased towards inheritance with classic inheritance trees taught with vector draw apps and the like. This has left its terrible mark on many a long standing code base :)

That said I remember almost all very early OOP literature and teaching back in the day was all very biased towards inheritance with classic inheritance trees taught with vector draw apps and the like. This has left its terrible mark on many a long standing code base


The timer traveler's TODO list should look something like:

1) Stop Hitler
2) Prevent the null reference from ever existing
3) Eject bad Java/C++ instructors into a volcano

Sean Middleditch – Game Systems Engineer – Join my team!

If inheritance is causing issues in your OOP code, switching to ECS isn't the answer; learning OOP properly is the answer. OOP teaches that you should use composition of components instead of inheritance whenever possible, and inheritance doesn't even get a mention in the core principles of OOP.

I second this, and I'd like to add that, having worked in both OOP and ECS systems, I didn't feel that one isn't above the other. Each has it sets of pros and cons, and a good OOP architecture will feel close to ECS at times (objects mounted by composition). I got the hand of OOP when I had to start making testable code, so it might be a good point to acquire some good OOP practices.

In my current implementation, some objects have a position which is dependent on other objects (for example, offset at a certain angle and distance from the parent object). At the moment, this is handled by some objects having getters for their position variables that return a position based on the position of the object they're attached to, and setters that apply the appropriate movement to their parent object.

In both ECS and OOP, the way I've solved it is by using a Transform class (or component), and making transform hierarchies. If your game is simple, transformation matrices might be overkill if you've never worked with them before, as the math can be confusing at first. The good side of transformation matrices is that you can simply multiply one by the other in order to compose orientation and position, abstracting away a lot of "how-to-do-this" details. As an extra, they work nicely with shaders.

This topic is closed to new replies.

Advertisement