How to design world, player, obstacles etc classes so they can communicate, which class does what?

Started by
40 comments, last by bovine.genius 6 years, 7 months ago

I think the main value of an ECS is actually that the data and the code are separated. The reason for this is that for most actions in a game engine, it's useful to be able to access multiple entities at once.


You don't need to use components to get this benefit. You can still have your entities be classes (or even just structs), but you don't put any functionality in them. Then you have a render function that works on an array of entities, and similarly for physics and AI. These are the Systems of an ECS.

It doesn't have to be complicated, and you don't have to use components to get the most important benefits of an ECS.

Advertisement

If doing it that whay one ends up with, let's say 1000 Systems, is still ok? Or it would mean something went wrong?

The way that I did it is almost exactly how bovine.genius said. The components should only be individual pieces of data that differ from one actor type to the next. The way I implemented them they are just holding the same variables you'd normally put in an actor/entity class.

So, yes if you have 1000 of them, you more than likely did it wrong. You can have different actors by giving them those "components" or not(or setting to default values), along with changing the actual data inside of the "components". The systems that act on them should only act on one particular set of variables/component, mostly anyway. Physics should do anything with health, unless your returning a value, like the force of the actor colliding with something, from it to send to whatever manages the health.

3 hours ago, bovine.genius said:

You can still have your entities be classes (or even just structs), but you don't put any functionality in them. Then you have a render function that works on an array of entities, and similarly for physics and AI.

My components are just structs that provide different pieces of data, model, transform, physics, ai, etc. In fact my Actor/Entity class is just data, it also has a std::map (could be a std::list or even a std::vector instead) of those structs.

The functionality comes from the class managing all the actors. It just checks to see if the current actor has certain components, if not it does nothing, if it does then it does whatever it needs it to. The only functions my actor class has are helper functions to reduce  the amount of code I have to write to get a certain component, and an initialize function that reads an xml file to get the components.

All of my components are however derived from a base class so the initialize function could be different for each, they all take only a TiXmlElement* so that I load just one xml file per actor/actor type, and pass the relevant part to the right component.

Its entirely possible to achieve basically the same effect with just an entity class, but I wanted more modular actors. For instance, a building needs physics (infinite mass so it doesn't move, and a physics shape) so you don't walk through it, but it more than likely doesn't need AI, or stats (which I could have just initialized to default values).

The main problem is, there are ton of tutorials/implementations out there, teaching, showing ECS - but all does it differently, some use the data oriented approach, some use abstract update/render methods for each component, some uses systems, some does a mix, some does weird things, some are extremely slow, some have good ideas, some are extremly bad - so there are no "This is the way to do it" solution out there.

 

The full generic way we see in unity and unreal engine are not the best way for all cases - there are drawbacks: Hard to debug, hard to control - especially performance.

Some games have no problem with that, some are a total disaster using that approach, some may be easy to implement with, some are extremely hard, etc.

 

Overall you should always prefer to implement it in a easy way first. You can always extend it - making it more complex later on.

 

Also we dont want to force you to not do it - its your choice after all, but a lot of people here have a ton of experience writing/shipping games or writing/shipping software in general. So when we say, start out simple then you can at least give it a try.

 

I have seen a ton of people, including myself falling into this pit: starting out complex, for no reason, from the very beginning and failing miserably. Some can overcome this, some cannot.

4 hours ago, bovine.genius said:

I think the main value of an ECS is actually that the data and the code are separated. The reason for this is that for most actions in a game engine, it's useful to be able to access multiple entities at once.

These 2 statements don't correlate in any way.

 

3 hours ago, Kylotan said:

These 2 statements don't correlate in any way.

 

Of course they do. By separating code and data, I really meant moving the update code out of an instance method on entities. Maybe it would have been clearer if I had said entities and the code that updates them are separated. The point is that putting an update method on an entity class always ends up in hard-to-solve communication problems, because you need more global knowledge to do the updates.

For example, having an update method on an entity that runs the next step in the physics simulation is going to introduce a lot of complexity, because physics engines often require updating multiple entities at once.

Having the update function be external to the entities means that you can easily have it operate on all entities without introducing hacks or complex communication systems into the code.

ECS has nothing to do with being data-driven.  You can have a data-driven setup without components.  For example, my current game project uses a bunch of json files to populate a level (the data is separate from the logic), but I don't use components, I'm using simple inheritance, since it's the simplest solution that accomplishes what I need for my use-case.

ECS doesn't "solve" the problem of deciding what class is responsible for what, it just changes it.  Now instead of deciding if an entity should have any say over another entity, you're deciding if one component has any say over another component, or the entity, or other entities, etc.

ECS answers the question "how do I compose the objects in my game", it doesn't answer the question of "what object is responsible for what".

15 minutes ago, bovine.genius said:

For example, having an update method on an entity that runs the next step in the physics simulation is going to introduce a lot of complexity, because physics engines often require updating multiple entities at once.

That doesn't makes any sense. There is no reason why 2 actors containing physics data can't interact just as easily as 2 pieces of isolated physics data that live outside of the actor. It's not complex. Thousands of games have managed it. Sometimes the physics has been pushed out to a completely separate system but that has no bearing on how the rest of the entity is structured.

1 minute ago, Kylotan said:

That doesn't makes any sense. There is no reason why 2 actors containing physics data can't interact just as easily as 2 pieces of isolated physics data that live outside of the actor. It's not complex. Thousands of games have managed it. Sometimes the physics has been pushed out to a completely separate system but that has no bearing on how the rest of the entity is structured.

Of course 2 actors containing physics data can interact, but it's going to require something extra. If you have an "updatePhysics" method on your entity, how does it know about the other entities? It needs something else. You can pass in an array of the other entities I guess, but at that point you've already made things more complicated, because you have to filter out the current entity.


In any case, I'm only pointing out that pulling the update code out of the entity class is an easy way to simplify things a bit. I never said it's the only way to structure a game. You don't even have to move all updates out of the entity. It's just a useful design tool. Not sure why you seem to be so upset about it.

"If you have an "updatePhysics" method on your entity, how does it know about the other entities? It needs something else." - An entity can ask the world, or the physics manager, or some other interface of your choice, for a list of other physics entities. That's one extra object, the same as you'd need if you had a standalone System.

Nobody is seriously suggesting that, for a complex physics based game, you'd have your complex physics in Entity::Update or Entity::UpdatePhysics. You'd have a PhysicsSystem that handles it. But that does not require that all your data lives outside of the Entity. Even if you did want your physics data outside the Entity - i.e. the way that most games do, with it tucked away inside PhysX or Havok - that's completely unrelated to how the entity itself is structured.

You do not, and never did, require an 'ECS' in order for there to be additional systems that help with complex parts of your gameplay. Entities in old-fashioned systems were never expected to handle absolutely every part of behaviour that affects an entity. They have their own methods and data and they collaborate with other objects to get things done, just like pretty much all software does.

13 minutes ago, bovine.genius said:

Not sure why you seem to be so upset about it.

The main problem is the constant use on these forums (not by you, but by a series of people) of strawman arguments to support following these entity/component patterns, suggesting that they solve problems that often don't exist, and often just by moving the problem anyway.

This topic is closed to new replies.

Advertisement