NEW: Master Swift design patterns with my latest book! >>

< Previous: Falling boxes: SKSpriteNode, UITouch, SKPhysicsBody   Next: Spinning slots: SKAction >

Bouncing balls: circleOfRadius

You're not going to get rich out of red rectangles, so let's use balls instead. Take the box code out (everything after let location = in touchesBegan()) and replace it with this instead:

let ball = SKSpriteNode(imageNamed: "ballRed")
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width / 2.0)
ball.physicsBody?.restitution = 0.4
ball.position = location

There are two new things there. First, we're using the circleOfRadius initializer for SKPhysicsBody to add circular physics to this ball, because using rectangles would look strange. Second, we're giving the ball's physics body a restitution (bounciness) level of 0.4, where values are from 0 to 1.

Note: the physics body of a node is optional, because it might not exist. We know it exists because we just created it, so it’s not uncommon to see physicsBody! to force unwrap the optional.

When you run the game now, you'll be able to tap on the screen to drop bouncy balls. It's fractionally more interesting, but let's face it: this is still a dreadful game.

To make it more exciting we're going to add something for the balls to bounce off. In the Content folder I provided you with is a picture called "bouncer.png", so we're going to place that in the game now.

Just before the end of the didMove(to:) method, add this:

let bouncer = SKSpriteNode(imageNamed: "bouncer")
bouncer.position = CGPoint(x: 512, y: 0)
bouncer.physicsBody = SKPhysicsBody(circleOfRadius: bouncer.size.width / 2.0)
bouncer.physicsBody?.isDynamic = false

There's a new data type in there called CGPoint, but, like CGSize, it's very simple: it just holds X/Y co-ordinates. Remember, SpriteKit's positions start from the center of nodes, so X:512 Y:0 means "centered horizontally on the bottom edge of the scene."

Also new is the isDynamic property of a physics body. When this is true, the object will be moved by the physics simulator based on gravity and collisions. When it's false (as we're setting it) the object will still collide with other things, but it won't ever be moved as a result.

Using this code, the bouncer node will be placed on the screen and your balls can collide with it – but it won't move. Give it a try now.

Adding a bouncer took five lines of code, but our game needs more than one bouncer. In fact, I want five of them, evenly distributed across the screen. Now, you could just copy and paste the code five times then change the positions, but I hope you realize there's a better way: creating a method that does all the work, then calling that method each time we want a bouncer.

The method code itself is nearly identical to what you just wrote, with the only change being that we need to position the box at the CGPoint specified as a parameter:

func makeBouncer(at position: CGPoint) {
    let bouncer = SKSpriteNode(imageNamed: "bouncer")
    bouncer.position = position
    bouncer.physicsBody = SKPhysicsBody(circleOfRadius: bouncer.size.width / 2.0)
    bouncer.physicsBody?.isDynamic = false

With that method in place, you can place a bouncer in one line of code: just call makeBouncer(at:) with a position, and it will be placed and given a non-dynamic physics body automatically.

You might have noticed that the parameter to makeBouncer(at:) has two names: at and position. This isn’t required, but it makes your code more readable: the first name is the one you use when calling the method, and the second name is the one you use inside the method. That is, you write makeBouncer(at:) to call it, but inside the method the parameter is named position rather than at. This is identical to cellForRowAt indexPath in table views.

To show this off, delete the bouncer code from didMove(to:), and replace it with this:

makeBouncer(at: CGPoint(x: 0, y: 0))
makeBouncer(at: CGPoint(x: 256, y: 0))
makeBouncer(at: CGPoint(x: 512, y: 0))
makeBouncer(at: CGPoint(x: 768, y: 0))
makeBouncer(at: CGPoint(x: 1024, y: 0))

If you run the game now you'll see five bouncers evenly spread across the screen, and the balls you drop bounce off any of them. It's still not a game, but we're getting there. Now to add something between the bouncers…

Love Hacking with Swift?

Get all 40 projects in PDF and HTML: buy the Hacking with Swift book! It contains over 1300 pages of hands-on Swift coding, and will really help boost your iOS career

< Previous: Falling boxes: SKSpriteNode, UITouch, SKPhysicsBody   Next: Spinning slots: SKAction >
Click here to visit the Hacking with Swift store >>