Add entity component system in cocos2d-x

@almax27
@Packora
Thanks.

I fixed most problems. You can refer to my physics-component branch to have a try. There is a test case named Node: PhysicsComponent in cpp-tests.

There is one issue left. Ray cast doesn’t work correctly with some special triangles. I think it is something about the codes i changed in PhysicsShapePolygon::updateScale()

https://github.com/minggo/cocos2d-x/blob/physics-component/cocos/physics/CCPhysicsShape.cpp#L656

I changed the codes

        cpVect n = cpvnormalize(cpvperp(cpvsub(vects[i], vects[(i + 1) % count])));

        planes[i].n = n;
        planes[i].d = cpvdot(n, vects[i]);

to

planes[i].d = cpvdot(planes[i].n, vects[i]);

If i don’t change the codes, then i can not query polygons in cpSpace, which means cpSpaceNearestPointQuery() can not find polygon though the query point inside it. You can test it by the step:

  • revert the codes i changed
  • run cpp-tests
  • select Node: PhysicsComponent
  • enter Pyramid Stack
  • you will find you can not select grossinis but can select the ball

Does anybody have any idea?

What i did these days:

  • added all test cases and fixed bugs
  • remove all unneeded codes
  • add doxygen comments for new classes and functions
  • add some comments of the codes
  • move codes of PhysicsComponentTest.cpp/.h into PhysicsTest.cpp/.h and deleted PhysicsComponentTest.cpp/.h
  • delete test case PhysicsComponentTest and reuse PhysicsTest

The only bug left i mentioned above has not been resolved.

In order to be reviewed conveniently, i squashed all commits into one commit. All the modification is in this commit. You can ignore the modification of physics test case.

@ricardo
Will you please review it?

Things left:

  • modify all projects settings
  • modify corresponding lua test case

Then i will send a pull request to v3.

Update: update the commit address.

@zhangxm ouch, I missed your post. yes, sure I’ll review it.

@zhangxm
well done. the code is much cleaner, much easier to maintain.
I haven’t reviewed it if it works Ok, or if it is performant, but I like the high-level design.

A few things that I would do:

  • run Instruments and profile the code. Try to find possible bottlenecks, or parts of the code that might run slow. In particular, the getInversed() might slow down things a bit…
  • also compare its performance with v3.7. Is it slower? How much slower?

thanks.

@ricardo
Thanks.

Yep, it will be slower compared to previous version as expected. Because it needs to query transform each loop.

I have tested all the test cases. It works correctly except the ray cast. The logo test case is slower because of so many physics bodies.

I will try to optimize it as possible, and not add codes in Node as before.

@zhangxm
ok. Instruments is a great tool to find bottlenecks. I’ve used it before and was very happy with it. If you need help with it let me know.

@ricardo
Thanks.
I will post here if i need your help.

I do some optimization in this commit. What i did are:

  • avoid invoking Node::getComponent<>() in PhysicsManager, it is time consuming
  • not invoking PhysicsBody::setScale() if there is not changed because PhysicsBody::setScale() is time consuming too

There are some operation that are time consuming too, such as

  • Node::getNodeToWorldTransform()
  • Node::getParentToWorldTransform()
  • Mat4::getInversed()

But i can’t avoid using them.

ok.
perhaps getNodeToWorld or getParentToWorld, or even getInversed could be cached.
If the matrix is not dirty, we don’t need to re calculate it.

Yep, i am thinking about it too. But i can’t, because there is not way to know if the transform is changed or not.

If i can cache the result in physics component, then i think we can cache it in Node too. And it is more reasonable to cache it in Node because even without physics component, we should get the transform every frame.

why not?

yes. And I think some of them are already cached in Node.

Did you mean the variable _transformDirty in Node? If so, then the reason is:

  • Node::getNodeToParentTransform() will change the variable to false, and this function may be invoked in anytime anywhere

If we can cache the result in Node, then the component can use the result, don’t have to cache it in component too. But as i can see, it just use _transformDirty to reduce some computation, but not caching the world transform.

if the nodeToWorld is called multiple times, it might make sense to cache it then.

I think it is Node should cache the result, because when there is anything changed, the cached transform should be updated.

yes, agreed.

I think guys CCNode has became too heavy, it’s so overloaded! Think about developers who want to make simple 2d games, or games without collision detection, my suggestion is adding a special CCNode beside the original one for such purpose and leave the choice for the developer : use it or not…

@Packora
The physics component is to remove physics related codes out of Node.

2 Likes

exactly as @zhangxm said… the goal of the components is to be less bloated

Is there any progress on the subject?

meanwhile: CppCon 2015: Vittorio Romeo “Implementation of a component-based entity system in modern C++”

1 Like

I am interested too. Is there any news to this topic? Do we have ECS available in Cocos2d-x today?