Collision Detection with Rectangles in SpriteKit

At the moment, I'm on a game. And I've read several posts about the do's and dont's when it comes to game design. The game is built with Swift and Apples SpriteKit. Therefore, when it came to implement collisions, the obvious thing was to use the physics engine. But that quickly lead to some difficulties which I was not willing to handle.

One example is handling the movement of figures. When one decides to use the physics engine, "normal" movement by adjusting the position of the node is not sufficient, since the physics collision detection won't handle this but only impulses. For my game this made movement especially hard since moving by coordinates was the simplest thing to do and is absolutely sufficient in my case.

So, I decided to use a simple collision detection which is based on rectangles. For this to accomplish there need to be some rules:

  1. Collision is solely based on rectangles.
  2. Only one side can collide at a time, e.g. you can either have left/right or top/bottom but not both at the same time. Of course, you can have multiple collisions within one go.

First thing is setting up the rectangles to use for detecting collisions. So, simply declare a variable var collisionRect : CGRect in every node, or even better make a protocol containing it and let every node that should be collidable adopt that protocol. Note, that setting the proper rectangles may require some thinking about the coordinate system. It may be beneficial to also draw them with e.g. SKShapeNode so you'll get an idea when something is about to collide and it makes debugging much easier. Eventually, when all rectangles and the debugging code is in place, you can get something like in the following screenshot:
Screenshot Collision Rectangles

Next thing to do is creating a structure which holds information about a collision:

struct Collision  
{
    enum Direction
    {
        case None, Top, Bottom, Left, Right
    }

    let direction : Direction
    let rect : CGRect

    var hasCollision : Bool
    {
        get { return direction != Direction.None }
    }
}

Straightforward. Now, a function to actually detect collisions between two rectangles is needed. This function will also use the previously created structure to hold all information:

class func testRectangleCollision(#A: CGRect, B: CGRect) -> Collision  
{

    var rect = CGRectNull
    var direction = Collision.Direction.None

    if !CGRectEqualToRect(A, B) && (!CGRectIsNull(A) && !CGRectIsNull(B))
    {

        rect = CGRectIntersection(A, B)

        if !CGRectIsNull(rect)
        {
            if rect.height >= rect.width
            {
                direction = (A.origin.x <= B.origin.x) ? .Left : .Right
            }
            else
            {
                direction = (A.origin.y >= B.origin.y) ? .Bottom : .Top
            }
        }

    }

    return Collision(direction: direction, rect: rect)

}

In words: this function does nothing else, than checking whether both rectangles are non-null and whether they are not identical. If this is the case, the intersection is calculated using CGRectIntersection from CGGeometry. If the result is not a null-rectangle, the direction is determined by testing the origins of the rectangles. In this specific example, it is of great importance, that A is always a static rectangle and B is the movable one (compare the screenshot above).

The destinction between a left/right and top/bottom collision is done by comparing the collision rectangle, e.g. by rect.height >= rect.width. This results from the assumption, that only a single collision at a time is handled. Eventually, the more detailed distiction of e.g. left/right is done by comparing the origins.

With all this code in place, you can now traverse your node hierarchy, call testRectangleCollision and evaluate its result.

Happy colliding!