How to implement a contact listener in Monogame with Aether.Physicw2D?

I’m recently on a project which our team uses Monogame to develop a small game, and currently I’m struggling with the collision detection.

Basically, our character would need to shoot out particles in wave forms, and I’d like to see the particles disappear as they bump into obstacles. So I wanted to test out this feature by narrowing down the problem to just the collision between two game objects, “Particle” and “Platform” (these are the names of our C# Classes).

First, in the constructor of “Particle”, I set the physics Body of the Particle Class as a sensor. Like so:

     public Particle(string PATH, Vector2 Speed, Vector2 Position, int color, World world) {
            // ... more code but irrelevant

            this._particleBody = world.CreateRectangle(Rect.X, Rect.Y, 1f, new tainicom.Aether.Physics2D.Common.Vector2(Position.X, Position.Y));
            this._particleBody.BodyType = BodyType.Dynamic;

            // set the body as a sensor
            this._particleBody.SetIsSensor(true)
    }

Then in my main game.cs file, I created the platform object and stored them to a static list, so I can access the list in the Particle Class (currently there’s only one Platform object in the list)

    static public List<Platform> platforms;
    public Platform platform1;

    // ... 

        protected override void Initialize()
        {

            base.Initialize();

            // ...

            
            
            /* Platforms */
            tainicom.Aether.Physics2D.Common.Vector2 platRect1 = new tainicom.Aether.Physics2D.Common.Vector2(15f, 1f); // 15 x 1
            tainicom.Aether.Physics2D.Common.Vector2 platPos1 = new tainicom.Aether.Physics2D.Common.Vector2(0, -(platRect1.Y / 2f));
            platform1 = new Platform(platPos1, platRect1, _world);

            // push that platform to the platform list (for collision events)
            platforms.Add(platform1);

        }

After I set up the things I need, in the Update method of the Particle Class, I then start to handle the collisions by accessing the Contact List, extracting the contacting bodies:

    public void Update() {

            foreach (Contact contact in _world.ContactList)
            {
                foreach (Platform platform in Game1.platforms)
                if ((contact.FixtureA.Body == _particleBody && contact.FixtureB.Body == platform._platformBody) ||
                    (contact.FixtureB.Body == _particleBody && contact.FixtureA.Body == platform._platformBody))
                {
                    // destroy that one particle 
                    // (I didn't do it here, there's another class that handles the action of these particles, I simply set a flag. )
                    // (e.g. toBeDestroyed = true)
                }
            }   
        }

Finally, the particle do get destroyed, but in a very strange behavior, the white spot in the video is an instance of “Particle”, and the green stripe platform is an instance of “Platform”, I expect to see the white spot disappear after bumping into the platform.

This was before I add the collision handling code: https://drive.google.com/file/d/1kUMqna0rk0Z7hs3-999dQcJT8vRmWlrs/view?usp=sharing

After I added the code, the particle (which is the little white spot in the video) appears for a short second then disappears before even hitting the platform, even if I put the particle in a higher position, it still disappears after travelling for a short second, not even bumping into any physics body. Had to record this by hand, because it disappears too quick: https://drive.google.com/file/d/1R0YORFtCnxirGLQcJvcazGKKIwu5vwUB/view?usp=sharing

I’ve been trying to find resources about Farseer or Aether, but there seems to be very few, if anyone’s got useful articles or links, please let me know.

Contacts are a proxy of the broadphase. Some contacts are created simply because the bodies are close enough, or the collision might have been resolved during the step. Check the .IsTouching property for active collisions. If one body is sensor the collision might be active between two steps, that depends on the speed and area of the object, if for example Platform is an Edge or thin box then the particles could pass through in a singe step.

A better approach would be to subscribe to a callback event to catch all collisions during the simulation. Store that body in a list, and remove it the next update.
A relative example is BodyPoolTest that is using the OnCollision/OnSeparation event and a pool of bodies.