Now we are going to look at using Physics in our Spritekit based game. If you’ve worked with a physics engine before, a lot of this is going to feel very familiar. One of the key differences from many other engines is SpriteKit handles updating the graphics as well as the physics. It’s a fairly involved process, so I am going to split this across multiple posts.
The first one is going to be short and sweet. We are going to configure the physics of a sphere, a SKShapeNode. It is simply going to exist and let gravity take it’s course. Code time:
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
view.scene!.anchorPoint = CGPoint(x: 0.5,y: 0.5)
var shapeNode = SKShapeNode();
var path = CGPathCreateMutable();
CGPathAddArc(path, nil, 0, view.bounds.height/2, 45, 0, M_PI*2, true);
shapeNode.path = path;
shapeNode.lineWidth = 2.0;
shapeNode.physicsBody = SKPhysicsBody(circleOfRadius: 45.0);
shapeNode.physicsBody.dynamic = true;
// Make gravity “fall” at 1 unit per second along the y-axis
self.physicsWorld.gravity.dy = –1;
self.addChild(shapeNode);
}
}
And once run:
Well, that was simple enough, let’s take a quick run through the code.
We start off by creating an SKShapeNode. This shape node is defined by a CGPath. You can think of a CGPath as a set of drawing instructions. In this case it consists of a single arc that draws a circle. Once our path is created we set it to be our shapeNodes path. We set the lineWidth to 2 to make it a bit more visible.
Next we define the physicsBody. Every SKNode has a SKPhysicsBody. The SKPhysicsBody is the nodes’ representation in the physics engine. When defining a physics body you pick the shape that most matches your underlying shape. In this case it’s a no brainer to use a circle. There are constructors available for rectangles, polygons, edges, etc. Of all the options however, the circle is the least processing intensive. So if you need just a rough physical representation, prefer the more simple types ( circle, then rectangle ) and leave the more complex types until required. The key thing here is the dynamic property. This is what tells SpriteKit to include your SKNode in the physics calculation. If this isn’t set, nothing is going to happen!
Finally we set the gravity value dy to -1. This means gravity moves by a delta of -1 unit per second on the y axis. Notice the concept of “unit” here, it is very import. When dealing with SpriteKit ( and many other Physics engines ), a unit is completely arbitrary. So you may ask “1 what?”. The answer is, 1 whatever… just be consistent about it. In your code you could choose 1 to be a millimetre, an inch, a foot, a lightyear. A lot of it comes down to the type of game you are working on. One thing to keep in mind here though, massive ranges in value are not a good thing… so don’t mix units. For example, trying to represent something in millimetres and kilometres in the same simulation is a sure recipe for disaster!
Now let’s give our ball something to collide with… that being the edge of the window. While we are at it, let’s add a bit of bounce to our step:
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
//Create the ball
var shapeNode = SKShapeNode();
var path = CGPathCreateMutable();
CGPathAddArc(path, nil, 0, 0, 45, 0, M_PI*2, true);
CGPathCloseSubpath(path);
shapeNode.path = path;
shapeNode.lineWidth = 2.0;
shapeNode.position = CGPoint(x:self.view.frame.width/2,y:self.view.frame.height);
// Set the ball’s physical properties
shapeNode.physicsBody = SKPhysicsBody(circleOfRadius: shapeNode.frame.width/2);
shapeNode.physicsBody.dynamic = true;
shapeNode.physicsBody.mass = 1;
shapeNode.physicsBody.friction = 0.2;
shapeNode.physicsBody.restitution = 1;
// Now make the edges of the screen a physics object as well
scene.physicsBody = SKPhysicsBody(edgeLoopFromRect: view.frame);
// Make gravity “fall” at 1 unit per second along the y-axis
self.physicsWorld.gravity.dy = –1;
self.addChild(shapeNode);
}
}
And run this:
Not, the jerkiness you see isn’t from the physics, but instead the animated gif. Getting that to encode to a reasonable size was oddly a bit of a battle.
The key difference here is first of all, we set the edges of the screen as a physics object for our ball to collide against. A key thing to remember with SpriteKit, every thing is a SKNode, even the scene itself!
Next we set a couple key physics properties for our ball, mass, friction and restitution. Mass is the weight of the object… going back to the age old question, what falls faster… a ton of feathers, or a ton of bricks? Friction is how two surfaces react to each other, generally used when simulating “sliding” and is fairly irrelevant in this example. Restitution is the key value. For lack of a better explanation, restitution is the bounciness of the objet. Lower value, less bounce, higher value, higher bounce. A value higher than 1 will result in an object actually gaining momentum after a collision ( aka, going higher UP then it fell from before bouncing ).
Next up we will work on actual collisions.