Now that the physics is working for this basic node component, let’s make it a full contact sport. Contact detection is a huge benefit of using a physics engine, so in this SpriteKit tutorial I want to make sure that we can still enjoy those benefits while adhering closely to my weird interpretation of Entity Component Systems.
Now that I have node components working in SpriteKit, it’s time to add something more dynamic than tapping to add a node that then doesn’t do anything.
After the development of my simple puzzle game, one of the things I wanted to do differently was using a generic Node Component. This would be a component that would do all the scaling, rotating, and positioning in such a way that it could apply to any node type (label, sprite, shape, etc) or even things like particle emitters.
In this post, I’ll create a simple SpriteKit scene with a basic render system and a few simple components to see how this might work.
As I write this, I’m walking the Dale’s Way with nothing but my iPad Pro so this will all be done using the Swift Playgrounds app.
As I’ve been working with Entity Component Systems in SpriteKit, I’ve come to realise that Apple’s implementation of the pattern is subtly different to what I understand is the ‘pure’ form of this pattern.
In part one, I set up a Movement Component that moved sprites around a space without any regard for the type of scene that they inhabit.
However, many adventure game scenes have some sort of perspective where it’s possible for players to move around an object.
Imagine a game where, say, a character in a trench coat is visiting a square in Lecce, Italy. For some reason, there’s a crate in the middle of it:
In my initial prototype I used SKActions exclusively to handle movement. It’s a fire and forget solution—I create an action with a destination point and a duration and run that action on a sprite. SpriteKit will move that sprite to the given point over the given time without me having to think about it again.
let moveAction = SKAction.moveTo(x: hasTarget, duration: length / moveSpeedInPointsPerSecond)
It’s great for many situations. However, there are a few limitations: