Advertisement

Logic in ECS?

Started by January 20, 2018 05:16 PM
6 comments, last by flodihn 6 years, 7 months ago

This is my first time building a game engine, albeit a 2D one for Android.

I've decided to build a simple ECS engine. The game I'm trying to *almost* duplicate at the moment is Doodle Jump.
I currently have the following systems running in my update loop, in the given order:

1) Physics (applies gravity)
2) Collision (works by predicting next position based on current position and velocity, and updates the current position on collision)
3) Transform Update (updates all entities based on their current velocities)
4) Render System (Draws to canvas)

I have the following questions:
I want to write a manager that generates obstacles at, say, fixed gaps and when the player reaches the middle of the screen.
This manager will need the current position and velocity of the player. (It finds the player by quering the ComponentManager for all entities having a PlayerComponent)
1) Where should this manager be placed in the game loop?
2) Should it even be a manager? Can such logic lie in systems?
3) Extending upon 2, what really are Systems supposed to handle?

 

Any help is appreciated!

The terms "manager" as well as "system" are widely used. In general a "system" is a set of components that work together to fulfill a purpose (see software system and also self-contained system). In game development we often speak of sub-systems as parts of the engine like the graphics sub-system, the animation sub-system, the physics sub-system, ..., so grouping components by functionality. Moreover, we obviously allow (sub-)systems to exist in a more or less shallow hierarchy. I'm not aware of an analog definition for "manager". The term is often used when something is responsible for the lifetime of objects (memory manager or resource manager). Personally I use that term mostly for the front-end object of a facade implementation, because it is in the limelight as seen by the clients and delegates all the work to the hidden objects ;) E.g. the resource manager is the public interface in front of a resource cache, resource directory, and resource loader.

Systems w.r.t. ECS means software that handles ECS component data and runs the necessary processes on the data. It is often chosen as an opposite to the distributed component management when the components are strongly coupled to the entities. That is IMHO a different definition as the one given above, so that the same term seems me to be used for different things, and looking at the context is necessary to understand.

With the above being my understanding of things, let's talk a bit about your questions.

17 hours ago, Sunny Kumar said:

I want to write a manager that generates obstacles at, say, fixed gaps and when the player reaches the middle of the screen.

BTW: Here the term "manager" is hard to be interpreted. What does it mean? A better name would hint at the purpose. Dependent on how obstacles are implemented, does it spawn game objects, or is it a procedural map generator, or ...?

17 hours ago, Sunny Kumar said:

1) Where should this manager be placed in the game loop?

It needs access to position and velocity. It makes no sense to use values that are not validated, i.e. values that may still be altered due to collision correction or so. Hence it need to be placed behind "3) Transform Update" if I understand your loop correctly. Should it be placed necessarily before "4) Render System"? Well, that again depends on how the obstacles are implemented. If they are game objects, then no (although I would place it before rendering anyway, just because it counts to the logic part of the game loop). If so, you may want to read the thread Question on organization of draw loop where I explain my approach a bit deeper. But if the obstacles are just static objects in a generated map, then putting the task before rendering allows the obstacles to occur already just after creation.

17 hours ago, Sunny Kumar said:

2) Should it even be a manager? Can such logic lie in systems?

A game loop should IMO be there to execute systems in the general meaning of the term. That may or may not be a system in the ECS meaning. With respect to the thread I've cited above, any system is allowed to have one or even more GameLoop::Task objects bound to the game loop.

Again, "manager" is somewhat an empty phrase. Please chose another name or, at least, prepend it with something meaningful. However, whether it could be "a manager" or lie in a (ECS like) system depends on how an obstacle is implemented (I know I repeat myself).

17 hours ago, Sunny Kumar said:

3) Extending upon 2, what really are Systems supposed to handle?

See the discussion above.

Advertisement

Thanks a lot for this detailed explanation!

Quote

With respect to the thread I've cited above, any system is allowed to have one or even more GameLoop::Task objects bound to the game loop.

I take from this that the logic I mentioned can be part of a system that could be placed between Physics and Collision.

 

Quote

Again, "manager" is somewhat an empty phrase. Please chose another name or, at least, prepend it with something meaningful. However, whether it could be "a manager" or lie in a (ECS like) system depends on how an obstacle is implemented (I know I repeat myself).

Yes, I agree that the term "manager" doesn't explain anything. In my code, I've used the term "ObstacleGenerationManager". The tentative logic within this class is as follows:

1) Get the player entity.
2) Check if the player has reached the middle of the screen.
3) If the condition in (2) is satisfied, then translate all game world objects down by the player's velocity.
4) Get the topmost obstacle.
5) Check if this obstacle has reached a threshold distance from the top of the screen.
6) If the condition in (5) is satisfied, then spawn a new obstacle at some random X at the top of the screen.

14 minutes ago, Sunny Kumar said:

I take from this that the logic I mentioned can be part of a system that could be placed between Physics and Collision.

But collision may change position and/or velocity of your player entity, wouldn't it? Hence is has been settled after collision.

Quote

But collision may change position and/or velocity of your player entity, wouldn't it? Hence is has been settled after collision.

Sure, but I'd like the newly created platform to take part in the collision too. (albeit it won't :D)
The velocities, in my design, do not change in between physics and collision, so that seems like a safe place to insert this code into.

I'm risking being out-of-topic here, and perhaps just saying something that you already known or others said. It is also, only a belief of mine and I have no data to back it up, but...

When working with an ECS, it feels like data-oriented design fits better than thinking on components as instances of classes (with their own methods). By system, I understand as a set of controlled functionality with inputs and outputs. By manager, I understand as something that has to handle some kind of ownership. Using a data-oriented approach, your components will start becoming "tags" and data will end up mostly on systems or containers used by systems and managers. Since logic is a series of transformations over data, it is very likely that the best place to let it be is in the systems themselves.

Of course, data-oriented approaches will have some degree of conflicts with Object Oriented Programming concepts, but if you're using an ECS, odds are that you're already having some attrition, anyway...

So, answering "3) Extending upon 2, what really are Systems supposed to handle?": I believe that systems should handle most consistent data transformations that can be run batch.

Advertisement

Through experience, I found it quite nice when I treat my game objects as pure persistent data classes that has one or multiple pieces of logic attached to them.

 

So for example, if you have a player, the player has some data.
 


{
     "image": "Resources/Sprites/Player.png",
     "position": {"x": 0, "y": 32, "z": 23},
     "hp": 100,
     "mana": 250,
     "animation": "walking",
     "collider": {"shape": "box", "size": 1}
}

Then you could attached the logic scrips "PlayerController", "Animator" and "Animal" attached to it. The PlayerController would probably be responsible for moving around the player when certains keys are pressed. The Animator logic could pick up on the movement or other actions and play proper animations.

Then the Animal logic could provide functionality to add/remove hitpoints and mana, and dying etc.

This topic is closed to new replies.

Advertisement