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
addChild(ball)

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
addChild(bouncer)

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
    addChild(bouncer)
}

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…

Get six books for only $150

The Swift Power Pack includes my first six books for one low price, helping you jumpstart a new career in iOS development – check it out!

< Previous: Falling boxes: SKSpriteNode, UITouch, SKPhysicsBody   Next: Spinning slots: SKAction >
MASTER SWIFT NOW
Buy Practical iOS 12 Buy Pro Swift Buy Swift Design Patterns Buy Practical iOS 11 Buy Swift Coding Challenges Buy Server-Side Swift (Vapor Edition) Buy Server-Side Swift (Kitura Edition) Buy Hacking with macOS Buy Advanced iOS Volume One Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with Swift Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let me know!

Click here to visit the Hacking with Swift store >>