0

I have a working collision system in place in my Monogame/C# project that uses a quadtree to determine potential collisions, and test them accordingly. My problem is that I want to be able to send out a method to the entity (that has been collided with), either OnCollisionEnter() or OnCollisionStay() depending on if the collision was present in the previous frame.

In the following code, OnCollisionEnter() is never called:

public class Collision : iSystem
{
    private List<Entity> currentCollisions; // Collisions occurring in the current frame
    private List<Entity> previousCollisions; // Collisions from the previous frame

    public override void Initialize(Entity caller)
    {
        currentCollisions = new List<Entity>();
        previousCollisions = new List<Entity>();
        base.Initialize(caller);
        hasInitialized = true;
    }

    public override void Update(GameTime gameTime)
    {
        List<Entity> nearby = Global.QuadTree.GetNeighbours(parent);

        for (int i = 0; i < nearby.Count; i++)
        {
            if (nearby[i] != parent)
                if (parent.Collider.Intersects(nearby[i].Collider))
                {
                    currentCollisions.Add(nearby[i]);
                    AlertEntity(nearby[i]);
                }
        }


        previousCollisions = currentCollisions; // Ready for the next frame
        currentCollisions.Clear();
        base.Update(gameTime);
    }

    public void AlertEntity(Entity entity)
    {
        if (previousCollisions.Contains(entity))
           parent.OnCollisionStay(entity.Collider);
        else
           parent.OnCollisionEnter(entity.Collider); // This is never called
    }
}

('parent' refers to the entity that the component 'Collision' is attached to)

If you could suggest why this is happening, I'd be grateful. Thanks

  • 1
    Should you be clearing out currentCollisions before setting it to previous collisions? I would do something like `previousCollisions = currentCollisions; // Not empty when set now` `currentCollisions = new List();` Clearing currentCollisions would also clear previousCollisions because they reference they same list object –  Jun 02 '16 at 12:57
  • In my actual code, `currentCollisions.Clear()` is after `previousCollisions = currentCollisions`. Thanks for pointing it out to me (: What you suggested worked! I didn't know they referenced the same object, that's never became a problem to me. Thanks! @Danny – Jordan Skittaraps Jun 02 '16 at 13:03
  • Then is seems like the else branch would _always_ hit, because `previousCollisions` will always be empty. Calling `currentCollisions.Clear()` will also clear `previousCollisions` because they are both referencing the same List object. Instead of calling `currentCollisions.Clear()`, you should set it to a `new List()`. I would also make sure that your predicates are set up correctly in your actual code. Edit: just saw your edited answer. I will put it in a real answer. –  Jun 02 '16 at 13:10

1 Answers1

1

Calling currentCollisions.Clear() will also clear previousCollisions because they are both referencing the same List object. Instead of calling currentCollisions.Clear(), you should set it to a new List<Entity>().

// . . .

previousCollisions = currentCollisions; // Ready for the next frame
currentCollisions = new List<Entity>(); // Now both lists are not clear
base.Update(gameTime);