Add entity component system in cocos2d-x

Physics is probably one of the best cases for an uncoupled update. You may want a fixed dt unlike other update steps, and most (if not all) operations will happen iteratively on physics-only data, which is a prime candidate for parallelism and cache thrash optimisations.

Also by coupling component types (rendering, audio, physics, script, etc) with their respective systems, we can clearly separate update steps for each.

@zhangxm

I think physics component should response on collide event, then it can invoke audio component to play a effect/music.

I donā€™t agree with putting logic for triggering sounds in the physics component at all. Another component; a logic controller; script or otherwise, should subscribe to the physics component to perform a necessary response. Separation of concerns and all that jazz.

2 Likes

I guess this would also lead to problems regarding threading, as the audio thread would need a higher priority(there is much more critical stuff involved like buffer fills, hardware interrupts and such). A stall in there would lead to audio glitches. If there is a decoupling between the two, they could run on separate threads, which enables a finer-grained, in-place control to adopt to the mentioned issuesā€¦

Regarding parallelism itself, are there any ideas or thoughts yet? Like affinity, a job system, tbb, fibers?
At least the parallelism features play a big role in C++17.

A little offtopic but there has been work done on an async task pool in the past, but itā€™s been more of a nudge in the right direction than a full fleshed out and supported feature. It it currently only sees use for Sprite3D mesh loading but should really be used for any and all async jobs required by the application. It may even be worth us considering an abstract ā€˜resourceā€™ loading mechanism used to fill disparate caches from raw data, rather than caches doing the loading themselves in a bespoke manner. Separation of concerns and all that jazz.

Random thoughts

class Resource { int getType(); }
void onLoadedCallback(Resource*)
ResourceManager::load("myImage.png", onLoadedCallback)
TextureCache::add(Resource*)
1 Like

As I understand, the idea behind it was just an async resource loader. The intention was never to support a fully fledged job system.
Does the Sprite3D just provide an async loading feature, or is there really an async task system, which is generic?

As the engine undergoes a major restructure regarding the rendering system and command buffer generation, it is questionable, if the existing mechanism can be adopted or the system has to be implemented from scratch.
An ideal solution would be to jobify everything from game-play to command buffer generation. The resource system itself is still lacking a mechanism for handling encryption. There was some consideration to provide various file system hooks for that, but dunno the state of that. So the resource management could be already in flux right now.

Future plans for parallelism in mind could also throw over existing concepts.

There really is a generic async task system. At a glance, Sprite3D::createAsync() uses the AsyncTaskPool ā€˜singletonā€™ to perform IO and parsing into NodeDatas/MeshDatas/MaterialDatas instances, but still loads the textures themselves synchronously, which I confess is rather odd. AsyncTaskPool manages a thread per enumerated task type: IO, NETWORK, OTHER, which could easily be expanded.

https://github.com/cocos2d/cocos2d-x/blob/v3/cocos/base/CCAsyncTaskPool.h

But there are so many bespoke async implementations elsewhere.
Uses of std::thread I could find in XCode: AssetsManager, AudioPlayer, AudioEngine, TextureCache, Console, DataReaderHelper, Downloader, HttpClient, WebSocket.

Thereā€™s definitely a balance to be struck between changing for the sake of correctness and not changing for the sake of everyoneā€™s sanity. Which funnily enough is also the biggest point of contention for an ECS :smiley:

Ah, thank you! Kind of oversight from my side.

Itā€™s hard to follow the concepts of the engine, as there is not really a technical documentation on how everything works together. Is there any besides the source code comments and some sparse docs on github/Google docs?

Yeah, itā€™s kind of inconsistent. There is support for multi-threading in the engine, but itā€™s not used consequently.

And also could be useful for a profiler overlay.

Seems like every object wants to know best itself, how to do multi-threading :smile:

Definitely. But why implement the same feature all over and over again, if you have the possibility to just handle it over to some single component? The way it is, is just more error prone, but maybe more flexible.

There were always fights between DOD and OO. I vote for correctness.

1 Like

Sorry, I didnā€™t understand that.

My point is that if we create a physics component and people can use it to simulate physics, then it means that people can use our component API to do complex things, at least for behavior-wise components.

The physics component that Iā€™m thinking of should not replace the current physics code that we haveā€¦
As I said, first we must have a good component, test it, test it, test it, have many samplesā€¦ if everything works ok, it means the developers can use the component API to create behavior-wise componentsā€¦ as simple as that.

BTW, Apple just released an Entity / Component API for iOS9:
https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/GameplayKit_Guide/EntityComponent.html#//apple_ref/doc/uid/TP40015172-CH6-SW1

Nice. They are really pushing things.

I also just found an engine/framework based on/using an ECS.

Adopting an inversion-of-control + entity-component concept
https://code.google.com/p/awe6/ (inactive project. but still some old infos there)
https://github.com/hypersurge/awe6 (active project)

1 Like

So Apple is doing more or less this:

  • created a new framework that could or could not work with SpriteKit
  • base class is GKEntity, which could have GKComponents.
  • logic can be added in to GKComponents and GKComponets should override update
  • rendering logic is delegated to SpriteKit elements, but developers could use something else if needed/wanted

I guess this is similar to what some users wanted to do. I havenā€™t read the rest of the ECS libraries code yetā€¦

About time (late actually) for Cocos to catch up, especially when lots of engines come out for free.

BTW, the topic ā€œAgents, Goals, and Behaviorsā€ is interesting.
I donā€™t expect this come out by Apple

1 Like

What i mean is that, when a component is added into an entity, how can the entity take effect. For example, the component has an update function, then when does this update function be invoked?

How did you implement it? Does every type of component has a unique id or else? Or did you use dynimaic_cast to find Physics, such as

template <typename T>
T* Nuclear::get()
{
    for (const auto& component : components)
    {
        if dynamic_cast<T*>(component) return component;
    }

    return nullptr;
}

Without adding a single line of code components are being updated. Please take a look at this piece of code:

Yep, this function will work only Node::scheduleUpdate() is invoked. Does it mean Node should enable update by default?

I donā€™t think that Node or components should receive any message by default. A component should only subscribe to signals/messages that it needs, otherwise the whole thing is just going to grind to a halt as you add more and more objects with components.

3 Likes

But i think a component is always needs to receive update message.

Some will, and I think you can decouple the update rate of components from the frame rate in some cases. Take a pathfinding component for example. It only needs to find a path when the desired location changes, then it sets up an action to perform the walk. Or a mouse click component, will only respond to mouse event messages. Sure there will be some components that need to do something every frame, but that should be opt in, not by default.

Yep, i agree with you.
Thatā€™s why i think we should add other system to update different types of component. Now cocos2d-x only have two places to trigger it:

  • Node::visit(): it is used for rendering
  • Schedule::Update(): it is to invoke Node::update, action and other call back

All these are frame fate.

@iQD
Good to know.
Thanks.

I have added comment of GamePlayKit at top of the thread.