WWDC24 SALE: Save 50% on all my Swift books and bundles! >>

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…

Save 50% in my WWDC sale.

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.7/5

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.