Add entity component system in cocos2d-x

@ricardo unfortunately I have stopped the development process of the module and a game witch I was working on it since I have a MAJOR exam on 17/16 of this month, but I will resume my work after that date… This module was designed first to be a CCParticleSystem alternative, if you are using an android device you can pm your email and I will send you a prototype, and believe me it will blow away your mind!

What I would do is to make a solid core:

  • entities/nodes/objects must be as light as possible. Avoid any data member which is not strictly necessary. One could argue that position / transform properties should be located at entity level. This is a design decision, there are several approaches.

  • components should be as light as possible too. Only have data which is concerned to the component and communication should be performed via events / dependency injection.

Performance wise, is way better to have in objects only data members which matter to the process which is being conducted. For example, it is better to have a transform component with only transform data (with parentship and whatever). Then, you can arrange these components with a custom allocator potentially contiguous in memory, making the update-transform process really fast.

Having this core composed of a rich cataloge of components and system to process them, you can provide higher level common features like for example a Sprite. Sprite should be composed of the needed components and you can provide it as an out of the box to use as a game object.

So Sprite for me would be a “nono” in its current form. I would provide Sprite as a composition of components. So I would rewrite it in a CBS way.

Another thing that I would like is to avoid customization via inheritance as much as possible, I would like to use strategy design pattern instead. Right now, I’m inheriting from Node because is the only way to customize stuff … and I would really like to be able to have a really tiny node which only implements Transform. With components this will be alleviated too.

as a final note: Please, avoid singletons / friends and all public access that are everywhere: those promote coupling and make everything very rigid.

I agree a big refactor is painful, tbh I do not know what would be the optimal route to make it incremental and do not waste a lot of time maintaining compatibility in each iteration of the process.

3 Likes

@IslandPlaya It depends how we can achieve. If we can have a pure ECS system, then developers will easy to extend cocos2d-x. They don’t have to inherit from Node, and it is easy to use data to create Objects.

I wanted to make physics properties as a component at first step. But i found it is very hard. Because the communication between Node and Physics Body are so tight and exist in many places. I mean there are many functions, such as Node::setScale, Node::setPosition, Node::setAnchorPoint() and many other functions are something related with Physics Body.

I think we should define an interface between Node and Physics component. For example, Physics component only has a update function, and it can be invoked every frame.

If we need to keep transform in Node or just to make it as a component. I think it is not important right now. What i think the most important thing right now is that, what will be engine look like after using ECS or CBS. And is it possible to implement it without breaking compatibility.

I have discussed with @WenHai who takes charge of 2d physics. He said the reason there are much code about physics is that

  • Node’s position/rotation information should be synchronized to physics body
  • after physical simulator, Node’s position/rotation information should be synchronized back to Node

Because the position recorded in Node is local position(position compared to parent), and physics body only accept world position, so need to

  • transfer Node’s position to world position before passing to physics body
  • physics body should transfer world position to local position before passing to Node

Matrix computation is time-consuming. In order to re-use matrix computation process in Node::processParentFlags(), he inserted physics related codes there. And other physics related codes are something related to it.

If we want to put physics codes as component, it may:

  • break compatibility
  • have performance issue if using physics

This.
Out of topic, I thought it will be fixed in v3 but it seems to be long way to go

Check the following link if you don’t know why it is bad.

yeah. I think everybody agrees that we have to get rid of them… But probably it will be a v4 thing.

2 Likes

Physics3d uses existing Component mechanism. What it modifies just:

  • start physics3d simulation in Director::drawScene()
  • invoke component’s onEnter() and onExit() interfaces in Node’s onEnter() and onExit()

Though it is not a real component system, but i think physics2d can be refactored like this way at first step.

Any thought?

hooking onEnter, onExit is a good starting point, but far from being a complete CBS.

the best way to know what we need is by doing putting physics as a component.

Just to throw in some information on ECS/CBS/Engines, that might be to some good use.

Insomniac games provided some information on their Dynamic ECS designed to run on the PS3 SPUs. Optimized for parallel processing, so to speak. IIRC they use/used it for their AAA games(E.g., the Resistance franchise, Ratched & Clank, Fuse, Sunset Overdrive). They alter or even implemented a complete new engine(E.g. for Sunset Overdrive), but they still use the same component systems/approaches based on Data Oriented Design.

One of the more important features, that may be interesting to you:

Dynamic components are allocated and deallocated on-demand from efficient memory pools, and the system provides a convenient framework for running updates in parallel and on different processors such as SPUs. The system can be layered on top of a traditional game object model, so a codebase can gradually migrate to this new architecture.

http://www.insomniacgames.com/a-dynamic-component-architecture-for-high-performance-gameplay/

Another information of how they use it for gameplay and AI code:
http://www.insomniacgames.com/mobyasyncupdate/

An implementation of the idea above by some 3rd party(with some additional info):
http://www.hmrengine.com/blog/?p=387

The guys from Insomniac games are very into Data Oriented Design and especially Mike Acton is always sharing tons of information about it.

Another approach worth to check out, but about game objects and maybe not directly “engine related”.
It was developed by Gas Powered Games for Dungeon Siege:
http://gamedevs.org/uploads/data-driven-game-object-system.pdf

It seems that there are ideas and approaches to develop ECS even further by using functional reactive programming.

Naughty Dog uses a System called “buckets”. They have nice presentation of their bucket/component and job system tech here:

They also did a presentation on how they speed up their tech with something called “fibres”:

The information could be some sort of “off topic”, but some stuff is still ECS related.

1 Like

Physics3d is already uses this way, so i think it can work with physics2d too.
What i confused is what’s complete CBS.
And can a complete CBS system work together with current architecture with 100% back compatible.

@iQD
Thanks for sharing.

@ricardo I think there are two things discussed:

  1. add CBS in cocos2d-x
  2. how to use CBS to refactor physics2d

I think we should first resolve what CBS we want in cocos2d-x. Then we can use it to refactor physics2d.

Awesome stuff, really enjoyed reading these :smiley:

How Sprites are being rendered or other engine parts being dealt with behind the scenes, is not part of the game code.
The game code just defines how the components should interact over time, doesn’t it?

An ECS/CBS could speed things up and use the resources in a more optimal fashion. Multi-threading/multi-core implementations can be implemented more easily, as it’s all about transforming data.

Bu isn’t ECS just an approach to how to implement a CBS? An ECS is a CBS, but a CBS is not necessarily an ECS.

But in fact everything is just about data transformation, right?
The input data is transformed by that fancy “black box” into the output data.

E.g., the file system component(let’s just assume, it is implemented as part of an ECS/CBS). It does not “transform” positions or even rendering things, but it’s still in scope with cocos2d-x and relevant to it’s architecture.

There’s a file service/system interface, which the components are implementing. One for basic I/O, others for compression, encryption or even net streaming.
They all just transforming the input data into some other output data, so basically it’s interface is just a single call with an input and an output parameter. The compressing and encryption components are also independent of each other and could be coupled together in different order.

Reading through the thread, I have a feeling, that the ECS/CBS is just about handling Nodes like Sprites or Physics. Basically all the fancy stuff, that is dependent on the delta time, needed to be updated over time.
But how about all the other things like file system, resource management and various others?

Can they also be stuffed into an ECS/CBS? If so, how could the different components work together?
Picking up the file system example. The encryption component needs some behavior/function to do it’s fancy stuff. But a component in an ECS just holds the data. A component manager class itself would transform it(like the health system, animation system or the sound system). A game object can be setup to have some sound played, as it is attacked by some entity, as some sort of sticking together components.
But how could this be done regarding the file system? E.g., some developer wants to compress and encrypt data or encrypt and then compress it? If there is some manager for compression and encryption, it would be limited to it’s order. Therefore it would need a mechanisms to inform other components, just like a parent/child, through e.g., messaging.
But there is also the possibility to just have one crypto-compress system, that can handle both of it and just reacts on the data defined in the compression and encryption component.

So there are cases, where the component maybe should have some behavior/function itself and not only data. But in the end all is just about transforming data.

I’m happy it was to some good use. Unfortunately the majority of the GDC presentations and talks(which are just great), cannot be shared/distributed due to licensing/copyright stuff(unless you pay for it).

The great thing about that stuff is, that it shares a lot of information and sometimes are ice openers. Not everyone can afford to spend big bucks on years of R&D to find out what’s hot and what’s not. So thanks to all the fine people who release that stuff for free :smile:

I don’t think we should refactor physics2d… in any case what we should do is to create a physics2d component, make sure it works Ok with Sprite, Node, etc…
By doing that, we will know if CBS works Ok. We can put that in the tests/samples and show people how to create their own components…
If that works perfect, only then I would try to remove the existing physics2d code and replace it with the physics2d component…

But the goal is not to replace physics2d… the goal is to create a very good CBS… and in order to do that, a physics2d component will help test it.

I think the key to a CBS is messaging. We need some way for components to talk to each other to coordinate things. It is vital that this be super lightweight and performant. For example, if a physics component is added, then it needs to know when the transform changes, perhaps when LOD changes, when the object is culled etc. You can do this via explicit function calls, but this will result in a lot of getting/caching pointers to components (which is slow and fragile) as well as needing to cast things to the right class, having a common base for components and their categories.

Another way would be to have a pub/sub messaging system per objects. Allowing subscription to a component. This could also be used to control instancing, i.e. if an object has a geometry component and the rule is that you can only have a single one per object, then when you add another it can broadcast adding component type and the existing component can reject it causing an error.

The physics component can subscribe to messages from the Node component to update. A LOD component can send out LOD changed messages which could cause the physics component to switch hulls. This needs to be super lightweight though. I would route this all through a single message handler in the Component class, possibly use the CRTP to inject the implementation into the component rather than use virtual functions for speed. Use hashes instead of strings for keys. Avoid lambdas as much as possible since they are fairly computationally expensive to dispatch (although I have not tested this in a release build)

The signals and slots mechanism of Qt would also do the trick. We don’t have the preprocessing capability they do, and I’m not sure I would want to incorporate that anyway. It’s a bit fragile, and c++14 will have capabilities to make all that work without having to run the MOC tool.

I think that in the end, coming up with a lightweight component comms implementation would be the best, basically pub/sub, broadcast, etc. and build it on top of that.

I’ve always thought of an Entity system as a game object system, that is more generalized than a class. The idea being that it can have arbitrary members, and is a collection of traits that gives the object its behaviour.

This can be done using a CBS, but there are other ways to implement it as well, a dictionary for example.