Collision Notification Protocol with Swift and SpriteKit
Tags: swift, gamedev, spritekit, gameplaykit
Published: 2022-04-04 15:14:50

---
description: "How to implement contact notifications with a Swift protocol to delegate hit test logic on collisions between entities on top of GameplayKit and SpriteKit."
---
I've previously written about how I've implemented and configured the hit tests using components in [Implementing a GKComponent for Contact Tests with SpriteKit](https://blog.bitbebop.com/contact-test-physics-gkcomponent/). I also further touch on the implementation in my [Devlog #3: Collision Detection](https://blog.bitbebop.com/collision-detection-swift-game-devlog-3/). Check them out if you haven't already.

## Contact Notification Protocol

The goal has from the first line of code been to end up with a streamlined collision detection handling between entities. A system, that once implemented, I can keep assigning to different entities and it takes care of all the heavy lifting as automatic as possible. While at the same time keeping the code neat and well organized.

Using the _Entity Component System_ design pattern with GameplayKit and Swift has been a great experience so far and has made organizing the game logic and mechanics very natural.

Continuing from my previous posts on the subject, what I had left to do was to actually let the entities know when they have been hit or have hit something. I didn't want to end up with huge `didBegin(_:)` and `didEnd(_:)` methods for `SKPhysicsContactDelegate` so I opted to use a Swift protocol to delegate the logic elsewhere.

That allows me keep all the logic in a different place than where the actual detection happens. Instead the logic can be contained within each entity or delegate it even further away to a `GKComponent` or a `GKState`.

This is the protocol I ended up with.

```swift
protocol ContactNotifiable {
    func contactDidBegin(with entity: GKEntity)

    func contactDidEnd(with entity: GKEntity)
}
```

Apart from having methods to let an entity know that it collided with another entity, it also gets a reference to the entity it collided with. By passing in a reference to the entity it collided with it's easy to determine what logic to run and to get access to any relevant data. Like how much damage that entity does.

An entity that needs to be aware of collisions needs to implement these two methods which is pretty much all there is to it. A solution that is beautiful in its simplicity.

## Adopting the Protocol

How each entity deals with the contact notifications spans a wide range in complexity. When an entity needs to receive notifications it adopts the `ContactNotifiable` protocol.

We have the most basic version where I can let the logic live in the entity itself. A bullet would be such a case where all I'm doing on detected contact is to remove the bullet from the game. The damage done by the bullet is handled by the entity getting hit.

So the Bullet `GKEntity` would get this implementation to handle the contact notifications.

```swift
extension Bullet: ContactNotifiable {
    func contactDidBegin(with entity: GKEntity) {
        addComponent(RemoveComponent())
    }

    func contactDidEnd(with entity: GKEntity) {}
}
```

In the bullet example above there would also be another entity involved, probably an Enemy entity, which would also receive a contact notification. The Enemy `GKEntity` class adopts the `ContactNotifiable` protocol as well.

When an Enemy collides there are many paths of action that might be taken so in contrast to the Bullet entity I did not want that much logic in the `GKEntity` class. So in the Enemy case I use a finite state machine based on `GKStateMachine` to take care of the different scenarios that might occur.

The actual state machine is implemented as a `GKComponent`. The `StateMachineComponent`, which I'm also reusing for other entities that needs to use states.

So an enemy getting hit by a bullet would tell the state machine to enter the exploding `GKState` when it gets hit.

```swift
extension Enemy: ContactNotifiable {
    func contactDidBegin(with entity: GKEntity) {
        guard let stateMachine = component(ofType: StateMachineComponent.self)?.stateMachine else { return }
        if entity is Bullet {
            stateMachine.enter(EnemyExplodeState.self)
        }
    }

    func contactDidEnd(with entity: GKEntity) {}
}
```

So far we haven't used the `contactDidEnd(_:)` method from the `ContactNotifiable` protocol. A use case when that method is convenient would be when the Player is taking damage while in contact with an Enemy entity.

```swift
extension Player: ContactNotifiable {
    func contactDidBegin(with entity: GKEntity) {
        if entity is Enemy {
            // Code to begin take damage...
        }
    }

    func contactDidEnd(with entity: GKEntity) {
        if entity is Enemy {
            // Code to end take damage...
        }
    }
}
```

## Delegate Notifications

Finally we just need to delegate the contact events using SpriteKit's `SKPhysicsContactDelegate` to the entities that should receive contact notifications.

The implementation looks something like this where we check each entity involved in the collision if it would want to get a notification. If it is a `ContactNotifable` entity we call the method and pass in the entity it collided with and then the custom logic in the entity can take over. Swift protocols are beautiful.

```swift
extension LevelScene: SKPhysicsContactDelegate {
    func didBegin(_ contact: SKPhysicsContact) {
        let entityA = contact.bodyA.node?.entity
        let entityB = contact.bodyB.node?.entity

        if let notifiableEntity = entityA as? ContactNotifiable, let otherEntity = entityB {
            notifiableEntity.contactDidBegin(with: otherEntity)
        }

        if let notifiableEntity = entityB as? ContactNotifiable, let otherEntity = entityA {
            notifiableEntity.contactDidBegin(with: otherEntity)
        }
    }

    func didEnd(_ contact: SKPhysicsContact) {
        let entityA = contact.bodyA.node?.entity
        let entityB = contact.bodyB.node?.entity

        if let notifiableEntity = entityA as? ContactNotifiable, let otherEntity = entityB {
            notifiableEntity.contactDidEnd(with: otherEntity)
        }

        if let notifiableEntity = entityB as? ContactNotifiable, let otherEntity = entityA {
            notifiableEntity.contactDidEnd(with: otherEntity)
        }
    }
}
```

## Conclusion

That wraps it up for collision handling in this game project. By using a `GKComponent` to define the collision configuration and a `ContactNotifiable` protocol to delegate the logic to where it belongs the best, we have ended up with a solution that is solid, fast to work with and that can scale when more entities gets added to the game.