1
\$\begingroup\$

This question seems to be a duplicate of mine, but I don't think it is.

I'm trying to build a game using an ECS, but I want this ECS to be as simple as possible, therefore I am eschewing messages.

My question is where should the the behaviours go for collision responses. Not physical responses, but logical response (e.g. bullet hurts player, player picks up health, explosion destroys enemies).

Is there a big HandleCollisionsSystem, or does each type of collision have it's own system or should the logic be in one or both of the colliding entity's components (but a component is just data, right?)

I'm sure there are several approaches, but for the moment I would like to err on the side of simplicity.

\$\endgroup\$
  • \$\begingroup\$ "...as simple as possible, therefore I am eschewing messages..." - what could be simpler and more flexible than passing messages? But, yeah the kind of ECS you are talking about is likely to end up with either many systems for different component permutations or one mega-system. \$\endgroup\$ – Den Jun 20 '15 at 22:07
1
\$\begingroup\$

You can call certain collision events like Unity does, allowing components to exist independently but still work together. For my physics engine, I have all collision processing centralized so detecting when a collision just started or ended, or if there is collision at all is just a matter of a boolean check and calling off the corresponding events. I.e.:

CollisionPair[,] CollisionPairs;
void ProcessCollision (Body b1, Body b2)
{
    CollisionPair colPair = CollisionPairs[b1.ID, b2.ID];
    if (/*CollisionDetected*/)
    {
        if (!colPair.IsColliding)
        {
            b1.OnCollisionEnter (b2);
            b2.OnCollisionEnter (b1);
        }
        colPair.IsColliding = true;
    }
    else {
        if (colPair.IsColliding)
        {
            b1.OnCollisionExit (b2);
            b2.OnCollisionExit (b1);
        }
        colPair.IsColliding = false;
    }
}

Then to listen to these events:

void Start ()
{
    GetComponent<Body>().OnCollisionEnter += HandleOnCollisionEnter;
}

void HandleOnCollisionEnter (Body body)
{
    if (body.Tag == "Bullet")
    {
        Health -= 20;    
    }
}
\$\endgroup\$
1
\$\begingroup\$

In my articles I wrote about a possible solution to your problem. In my vision of ECS, I group the systems according their context and level of abstraction. When I talk about context, I mean the scope of the systems. For example, are the systems handling enemies? Are the systems handling weapons? Are the systems handling the player? Once I give a context to the systems, I group them under the same namespace, like PlayerSystems, EnemySystems and so on.

Level of abstraction is instead about how abstracted a system is, for example: is it the system that manages the general physic collision? Or is it the system that manages the collision between enemies and enemy targets? The latter is less abstracted than the first one.

In this scenario, what I would do is to let the general system, that manages collisions, communicate with the less abstracted systems.

The communication could happen through an observer, defined in the same namespace of the abstracted system and used by injection by the other systems.

Alternatively (and that's what I actually do), I let the systems communicate through the components. The EnemyTargetColliderSystem knows exactly the same component used by the PhysicCollisionSystem therefore knows when an enemy collides with something. At that point it must check if something is a valid target.

This is just one way to solve the problem, it really depends if you want to take advantage of the computation already performed by the PhysicCollisionSystem. If not, you can simply perform a collision check between all the enemies and possible enemy targets inside the EnemyCollisionSystem.

Be careful that I call it enemy target and not player. It would be wrong to let an EnemyEngine know about a component relative to the PlayerEngine.

if you want to know more about my point of view on ECS, you can read my articles starting from this one: http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-i-dependency-injection/

\$\endgroup\$
0
\$\begingroup\$

I would Have a Handler, "Handle" those depending on the type of entity. Unfortunately, in my Non-ECS engine, I have collision code for every type of collision between different types.

Works like a charm tho :)

\$\endgroup\$
  • 1
    \$\begingroup\$ The point of ECS is that your systems and components do not know what types of entities are there. \$\endgroup\$ – Den Jun 20 '15 at 22:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.