Add entity component system in cocos2d-x

As @Packora mentioned in the thread, cocos2d-x is very hierarchical, it makes cocos2d-x hard to extend. So we want to add Entity Component System(ECS) or similar mechanism in cocos2d-x to make it extendable.

I am doing researching on ECS and trying to add it in cocos2d-x. I will discuss and post progress in this thread. You are appreciated if you have any suggestion.

There is already some discussion in this thread. So please read this thread if you want to join the discussion.

GameplayKit - iOS 9

Features:

  • GKEntity is a container of components. It has a function named updateWithDeltaTime:, this function will invoke each component’s updateWithDeltaTime:. It provides functions to add/remove/find a component.
  • GKComponent will holds a reference to its entity, can use it to find other components. It only has a function named updateWithDeltaTime:. This function will be invoked by GKEntity or GKComponentSystem to do something in every period duration.
  • GKComponentSystem is to invoke registered components without looping GKEntitys. It can add a component by a component instance or by an entity instance.
  • Should use GKEntity or GKComponentsystem to invoke GKCompoent's update function.
  • It also provide some help classes, such as State Machines, Pathfinding, and Rule System. Detail information please refer to this thread.

Pros

  • It can be used with any rendering system, like SpriteKit or SceneKit or any other, but see below.

Limitations:

  • There are no callbacks / messages between different components, or at least not in the current version. But perhaps it uses SpriteKit events??

Unity

Features

  • Entity: GameObject is the entity. It can find a component, but there is not way to remove a component.
  • Component: Almost all components are added to an entity through editor. Script is a special component, can use it to communicate with other components.
  • There is no obvious systems. It seems systems are implemented internally, and can take effect as needed. For example, when a RigidBody is added into a GameObject, then it can do physical simulation automatically.
  • There is not update function in Component and GameObject. But there are many call back functions in script component(inherits from MonoBehaviour, such as:
    • Update: invoked every frame
    • OnCollisionEnter2D: it is invoked when an incoming collider makes contact with this object’s collider

Limitations

  • All component controlling codes will be in a registered script, because only the script can receive messages.
  • It is not easy to add a new component that is not provided by Unity.
  • All script will be looped many times no matter they need to be updated or not, because these functions will be invoked every frame or every fixed period:
    • Update: will be invoked every frame
    • FixedUpdate: will be invoked in fixed frame rate
    • LateUpdate: will be invoked after Update and FixedUpdate

I am not familiar with Unity, please correct me if there is something wrong.

entityx

Features

  • Entity: entity is just an id. It doesn’t contain components. EntityManager record the relationship of entity and components. It has come helper functions of:
    • create a component and associate with the component to entity
    • find a component
    • remove a component
  • Component: component doesn’t contain anything. Developer should subclass it and it is better to just include data. Most time developers deal with ComponentHandler.
  • EntityManager: It records the relationship of entity and component. And it provides functions to find components.
  • System: just a base class. subclass should implement update function.
  • SystemManager: will loop all added systems.
  • EventSystem: can use it to subscribe new event type and emit events.

Limitation:

  • It is a framework of ECS, developers should implement all needed systems. For example, should implement rendering system, physics system, audio system.

Unreal

Features

  • Entity: Actor is the entity. It is a container of Components. It is a complex class, it includes many variables and many functions. InputComponent and RootComponent is two variables that can be accessed directly. InputComponent is intialized internally; RootComponent should be assigned outside, and it holds the transform information of the Actor. It has a Tick() function, which will be invoked every frame.
  • Component: component can be created by Editor or by code. If a component is created by code, then we can continue to edit it in editor. As the documents shows, we can create a StaticMeshComponent component in c++, and assign its Static Mesh in editor. And a component can be attached to another component no matter they are belongs to the same Actor or not. Their transform is relatives to the component it attachs to. Actor’s transform is the same as its RootComponent's transform.
  • System: there is not obvious system that developers should notice. When a coomponent is added into an Actor, the component takes effects automatically. For example, when a StaticMeshComponent is added into an Actor, then the Actor will be visable.
  • Message: As the document shows, developers should keep reference of a component if it wants to use it in future. But Actor provides some functions to find a component, such as AActor::GetComponentsByTag and AActor::GetComponentsByClass.

Limitation

The component system is not as pure as Unity. Some concept is treated as component, such as physics, but others are not, such as network. I think it is a duration that it towards to more pure component system. But it is more valuable for cocos2d-x because we are on the road too.

2 Likes

Let’s put all the ECS that are out there:

And engines using ECS in case they are using its own ECS:

Please, keep posting the other ECS… I’ll keep updating this post.

One of the things I’ve struggled with, is mixing and ECS with parent/child relationships. I think that would need some thought. Some of the questions I’ve thought about include :

Would an ECS system even maintain the current parent/child relationship of nodes or would all nodes just be rendered via z-order (One of the things I hate about unity is the lack of parent/child transform relationships in their game objects).

If parent/child relationship is maintained, would the ability to have children be a core part of the entity, or stored as a separate component?

There are way more ECS out there … just to be clear. What do you guys are proposing? a pure ECS ?
in a pure ECS the Entities are only an int and components only has data (no behavior).

Most engines does not use ECS. Usually they use a CBS approach: components have behavior (aka functions) like proposed in gameprogramming patterns for example.

Depending on what kind of system will be finally implemented. The parent/children approach makes sense for the “Transform” component. The entities should not be part of a parent/child hierarchy themselves, but any drawable entity should support chaining transforms, that could be implemented using a Transform component which can have parents/childs.

I have thought a bit about this. In my experience with Cocos2d-x I have found that the architecture is very flat. A great deal of features have been added in the last few versions, and those features do not work well with each other, but rather function individually.

I was thinking along these lines…

Since backwards compatibility is important, leave the current node implementations as is. However, in my humble opinion, we really only need one node type. A geometry node, or perhaps just Node with attachments. The current implementation of Node permits components, so perhaps adding a geometry component while leaving the remaining node types untouched would suffice.

I would separate the geometry from the code that loads/creates/modifies geometry and make those components as well. I.e. a Label is just a Node with a geometry component and label component. The geometry part goes to the renderer, and the Label part is what converts the string to vertices/uv’s etc.

Anyway, the idea is to leave the hierarchical version of cocos2d-x intact while building out a component based version alongside. I believe that the cocos codebase requires some serious consolidation to remove all the duplicated code for drawing different node types. Only a single component is needed to represent geometry which is handed to the renderer. All the other nodes can just manipulate a geometry object to achieve the results they want. All engine features such as shadows, lights, etc. would operate at the renderer pipeline level on the geometry which makes implementing features across the board possible.

My 2c :smile:
Justin

3 Likes

I can’t see what this would bring to the engine.
Leave game things to game code…

Unreal 4 should be CBS. But there is a request for using ECS
https://forums.unrealengine.com/showthread.php?62450-Feature-suggestion-Complete-Entity-Component-System-for-UE4

As a starting point, designing components (i.e. CBS) should be the first step for “evolution”. Then later you could review if converting to pure ECS.

The EntityFu hardcode some items and may need to change before implementation

  • Restricted maximum number of entities (4096)
  • Log function
1 Like

Also just to be clear, there is a difference between an entity system and component based system. The first is talking about objects in a game world, whereas the second is more how objects in the programming domain are constituted, i.e. inheritance or component based.

I believe that this thread is about the second, and not the first type.

@winipcfg @mannewalis yes. we should start with an CBS system first, and then, if it makes sense, evolve it into a ECS.

And I think we can do a CBS for v3.x and being 100% backwards compatible.

Right now our nodes have 3 things hardcoded:

a) Transform properties:

For performance reasons, I wouldn’t convert the Transform properties into a component. Even Unity has the Transform properties as part of Object.
That means that all Nodes will have Transform properties… and I don’t see this as an issue since 99% of Nodes will need it and that means better performance.

b) Rendering properties:

Ideally this should be a component, it should be decoupled from Sprite and similar… but for the sake of backward compatibility we should not do this in v3… perhaps in v4. @mannewalis idea of having a Geometry as a component is interesting. It is worth noting that in v3.7 we are adding Material system to Sprite3D and this will improve a little bit in decoupling the rendering code from Sprite3D. And Geometry + Material = render object

c) physics properties:

The physics code in particular, is messy. It is full of #ifdef… that is a great candidate for being a component.
If by moving the Physics logic to a component doesn’t break compatibility, then this will be a great candidate to be our first useful component.

thoughts?

@ricardo Having a transform properties part of the node means a developer wouldn’t be able to provide a custom transform component, if they wanted to. They would have to subclass Node. Mixing inheritance and ECS seems to defeat the purpose, no? Is the benefit worth the limitation?

Edit:

Technically, in Unity all GameObjects get a transform components, the transform properties aren’t part of the GameObject.

I juste want to know what is so important about retro-compatibility?? I think the solution hère is to create a new node type from scratch…

4 Likes

I think I have to agree with @Packora here, it is a fundamental shift in how objects will be created. For example, rather than create() methods factories would be better suited to a component model, so I don’t think there will be a clean long term compromise, we would just end up with loads of code bloat just to support backwards compatibility. That said to refactor the entire codebase to a new unified component system is a monumental task. Perhaps this could be a primary focus for v4+?

1 Like

good point. Just to understand, in which case would you need a custom transform? Could you describe its use case ? thanks.

Being API and ABI backward compatible in v3.x is something very important.
If we break API / ABI in v4.0 is not that important, but we should avoid it if we can.
In particular, I prefer to not to create a complete new set of hierarchy nodes. I want that Sprite, Sprite3D and the others use components.
Of course, if you prefer to create a new hierarchy from scratch, you can do it, and it will be much easier. But all the existing code won’t be able to use… I prefer to add components to existing nodes than to create a new concept.

Custom transform aside who’s to say the object you’re building needs one? What if you wanted a manager that requires no transform, but can be configured via a component system. One thing that always irked me about Unity was the necessity for gameObjects to have transforms. It kinda makes sense from their editor UI point of view because instantiation happens via the scene graph, but there’s no reason it should be mandatory from code, aside from perhaps a simplified lifetime, but that could be abstracted to scene ownership.

It doesn’t make sense to have Sprite/Sprite3D at all in an ECS. They are implicitly Node derivatives. Rather we should be providing renderable components that ‘require’ other components on the same object, transforms, meshes, animations, etc.

The direction of a hybrid could be more of an Node/Controller setup, where you can attach various controllers that manipulate a Node for physics, AI, networking etc. Rendering would still be tightly coupled in the Node inheritance tree but at least this way we would have a clear definition of what that inheritance should be restricted to.

1 Like

I do not understand how could you bring ABI compatibility and lift the engine … from what I see, this task is plainly impossible!

Even if you only want to provide API compatibility, take into account that protected = public regarding to this … (thats a good reason to avoid protected stuff).

I must agree with @Packora, I would focus on getting CBS working in v4 and not making it retro compatible. I would keep v3 as it is now …

1 Like

@dredok @Packora @almax27

Assume that we do it only for v4, and we don’t care about compatibility, what would you do with the existing code?
I mean, would rewrite Sprite and Sprite3D and all the different nodes in a CBS way, or would you just leave them as they are and create a new hierarchy… and what features would you like to have?

I’m not a big fan of super big refactors, because usually they mean:

  • big delays
  • too many bugs
  • incompatibilities issues

I prefer to do it in an incremental way if possible. As @almax27 said, adding behavioral components to existing nodes in v3.x as the first step. And then keep adding features on top of that.

1 Like

Seems to be a good point, by the way I’m already working on a super freaking fast ECS module! It’s going to be opensource and cocos2d-x compatible, and why not integrate it in v4 as a node alternative for developers who are ready to forget about all node/sprite stuff and start from scratch like me :smile:…

1 Like

@almax27 One could argue that if it doesn’t need a transform, and is not going to be rendered, it is outside the scope of cocos2d and not relevant to it’s architecture. It goes back to what @mannewalis was saying about an entity system and component based cocos2d classes.

@ricardo The only use case that I can think of at the moment is something like a follower transform where you would node.addComponent<FollowerTransform>(dependent). The follower transform would then update the transform of it’s dependent. Think one node following another, without them being in a parent child relationship. There probably would be another way to do this, but it’s the only thing that came to mind. Don’t let my lack of imagination speak for the lack of need of a component based transform.

What’s the advantage to it not being a component? What are the performance concerns? I would assume that whether it’s node.getPosition() or node.getComponent<Transform>().getPosition(), modern compilers would be able to optimize accordingly, no?

A middle ground, assuming the performance hit is in getComponent() would be to do what unity does and have an automatic transform member reference to the Transform component (node.transform.getPosition()). Construction of nodes could take a similar route to STL containers which have optional template parameters for ‘allocators’. The default allocator would use the default transform component and if you needed different behavior you could create your own “allocator”. Just thinking out loud here.

@Rick_S
Thanks for the info. I got the use case.

@Packora
Thanks. If you are working on one, I would like to take a look at the code if possible.
I still have to do more homework and read the code/design ideas from the existing ECS/CBS that are out there before making a decision.

I think you are right. I had an overly optimistic thought.