---
title: "Goal Collision"
date: 2019-06-03T12:39:11-07:00
weight: 10
---

A goal destroys a ball, and then spawns a ball. So let's set up a new actor-receiver-response set of components to model this behavior.

Our Actor: **PongFE/Components/CanDestroyComponent.cs**:

```cs
using Encompass;

namespace PongFE.Components
{
    public struct CanDestroyComponent : IComponent { }
}
```

Our Receiver: **PongFE/Components/CanBeDestroyedComponent.cs**:

```cs
using Encompass;

namespace PongFE.Components
{
    public struct CanBeDestroyedComponent : IComponent { }
}
```

Our Response: **PongFE/Components/SpawnBallAfterDestroyComponent.cs**:

```cs
using Encompass;

namespace PongFE.Components
{
    public struct SpawnBallAfterDestroyComponent : IComponent
    {
        public float Seconds { get; }

        public SpawnBallAfterDestroyComponent(float seconds)
        {
            Seconds = seconds;
        }
    }
}
```

Now let's create **PongFE/Messages/DestroyMessage.cs**:

```cs
using Encompass;

namespace PongFE.Messages
{
    public struct DestroyMessage : IMessage
    {
        public Entity Entity { get; }

        public DestroyMessage(Entity entity)
        {
            Entity = entity;
        }
    }
}
```

In **CollisionEngine.cs**:

```cs
    ...

    CheckBounce(message.EntityA, message.EntityB, message.HitOrientation);
    CheckBounce(message.EntityB, message.EntityA, message.HitOrientation);

    CheckDestroy(message.EntityA, message.EntityB);
    CheckDestroy(message.EntityB, message.EntityA);

    ...

    private void CheckDestroy(Entity a, Entity b)
    {
        if (HasComponent<CanDestroyComponent>(a))
        {
            if (HasComponent<CanBeDestroyedComponent>(b))
            {
                SendMessage(new DestroyMessage(b));
            }
        }
    }
```

Don't forget to add **typeof(DestroyMessage)** to CollisionEngine's Sends.

Now let's create **PongFE/Engines/DestroyEngine.cs**:

```cs
using Encompass;
using PongFE.Components;
using PongFE.Messages;

namespace PongFE.Engines
{
    [Reads(typeof(SpawnBallAfterDestroyComponent))]
    [Receives(typeof(DestroyMessage))]
    [Sends(typeof(BallSpawnMessage))]
    public class DestroyEngine : Engine
    {
        public override void Update(double dt)
        {
            foreach (ref readonly var message in ReadMessages<DestroyMessage>())
            {
                if (HasComponent<SpawnBallAfterDestroyComponent>(message.Entity))
                {
                    ref readonly var respawnComponent = ref GetComponent<SpawnBallAfterDestroyComponent>(message.Entity);

                    SendMessage(
                        new BallSpawnMessage(
                            new MoonTools.Structs.Position2D(640, 360),
                            new System.Numerics.Vector2(-200, 100),
                            16,
                            16
                        ),
                        respawnComponent.Seconds
                    );
                }

                Destroy(message.Entity);
            }
        }
    }
}
```

Notice that **SendMessage** has an extra argument here. What's that about? If you pass a numeric value along with **SendMessage**, the message will be delayed, and send after the given number of seconds has elapsed. This can be very convenient for producing timing-based behaviors. Be warned however, that there is no way to cancel a delayed message send. So if you need to be able to cancel a timed action, it's probably better to set up a component/engine structure that keeps track of the time.

We'll need a way to create our goal entities now.

Create a file, **PongFE/Messages/GoalBoundarySpawnMessage.cs**:

```cs
using Encompass;
using MoonTools.Structs;

namespace PongFE.Messages
{
    public struct GoalBoundarySpawnMessage : IMessage
    {
        public Position2D Position { get; }
        public int Width { get; }
        public int Height { get; }

        public GoalBoundarySpawnMessage(Position2D position, int width, int height)
        {
            Position = position;
            Width = width;
            Height = height;
        }
    }
}
```

And a file, **PongFE/Engines/Spawners/GoalBoundarySpawner.cs**:

```cs
using Encompass;
using PongFE.Components;
using PongFE.Messages;

namespace PongFE.Spawners
{
    public class GoalBoundarySpawner : Spawner<GoalBoundarySpawnMessage>
    {
        protected override void Spawn(GoalBoundarySpawnMessage message)
        {
            var entity = CreateEntity();

            AddComponent(entity, new PositionComponent(message.Position));
            AddComponent(entity, new CollisionComponent(new MoonTools.Bonk.Rectangle(0, 0, message.Width, message.Height)));
            AddComponent(entity, new CanDestroyComponent());
        }
    }
}
```

Let's add some components to **BallSpawner.cs**:

```cs
    AddComponent(ball, new CanBeDestroyedComponent());
    AddComponent(ball, new SpawnBallAfterDestroyComponent(0.5f));
```

Finally let's add our new engines and spawn messages to **PongFEGame.cs**:

```cs
    ...

    WorldBuilder.AddEngine(new DestroyEngine());

    ...

    WorldBuilder.AddEngine(new GoalBoundarySpawner());

    ...

    // right boundary
    WorldBuilder.SendMessage(
        new GoalBoundarySpawnMessage(
            new MoonTools.Structs.Position2D(1280, 0),
            6,
            720
        )
    );

    // left boundary
    WorldBuilder.SendMessage(
        new GoalBoundarySpawnMessage(
            new MoonTools.Structs.Position2D(-6, 0),
            6,
            720
        )
    );
```

Now when the ball hits the left or right side of the play area, it will destroy and respawn. Great!
