sup { font-size: 80%; vertical-align:super; } blockquote { padding-left: 30px; }

*Update Note:* This is the third incarnation of one of our very popular tutorials – the first version was written by Tutorial Team member Matthijs Hollemans for Cocos2D, and the second version was update to Sprite Kit by Tony Dahbura. This latest version still uses Sprite Kit, but is updated for iOS 8 and Swift.

Welcome back to the Trigonometry for Game Programming series!

In the first part of the series, you learned the basics of trigonometry and saw for yourself how useful it can be for making games. Math doesn’t have to be boring – as long as you have a fun project to apply it to!

In this second and final part of the series, you will extend your simple space game by adding missiles, an orbiting asteroid shield and an animated “game over” screen. Along the way, you’ll learn more about the sine and cosine functions, and see some other useful ways to put the power of trig to work in your games.

Get ready to ride the sine wave back into space!

## Getting Started

This tutorial picks up where you left off in the last part. If you don’t have it already, here is the project with all of the source code up to this point.

As of right now, your game has a spaceship and a rotating cannon, each with health bars. While they may be sworn enemies, neither has the ability to damage the other, unless the spaceship flies right into the cannon (which works out better for the cannon, damage-wise).

It’s time for some fireworks. You will now give the player the ability to fire missiles by swiping the screen. The spaceship will launch a missile in the direction of the swipe. For that, you’ll need to add some new properties for tracking touches.

Open *GameScene.swift* and add the following properties to the class:

let playerMissileSprite = SKSpriteNode(imageNamed:"PlayerMissile") var touchLocation = CGPointZero var touchTime: CFTimeInterval = 0 |

You’ll move the missile sprite from the player’s ship in the direction it’s facing. You’ll use the touch location and time to track where and when the user taps on the screen to trigger a missile.

Then, add these lines at the bottom of the code inside `didMoveToView()`

:

playerMissileSprite.hidden = true addChild(playerMissileSprite) |

Note that the missile sprite is hidden initially; you’ll only make it visible when the player fires. To increase the challenge, the player will only be able to have one missile in flight at a time.

The first touch handling method to add is `touchesBegan()`

, which will be called whenever the user first puts their finger on the touchscreen:

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { if let touch = touches.anyObject() as? UITouch { let location = touch.locationInNode(self) touchLocation = location touchTime = CACurrentMediaTime() } } |

This is pretty simple – whenever a touch is detected, you store the touch location and the time. The actual work happens in `touchesEnded()`

, which you’ll add next:

override func touchesEnded(touches: NSSet, withEvent event: UIEvent) { let TouchTimeThreshold: CFTimeInterval = 0.3 let TouchDistanceThreshold: CGFloat = 4 if CACurrentMediaTime() - touchTime < TouchTimeThreshold && playerMissileSprite.hidden { if let touch = touches.anyObject() as? UITouch { let location = touch.locationInNode(self) let swipe = CGVector(dx: location.x - touchLocation.x, dy: location.y - touchLocation.y) let swipeLength = sqrt(swipe.dx * swipe.dx + swipe.dy * swipe.dy) if swipeLength > TouchDistanceThreshold { // TODO: more code here } } } } |

The outer `if`

statement calculates the time between starting and ending the swipe. If the time is greater than the `TouchTimeThreshold`

value of 0.3 seconds, the missile doesn’t fire. Also, since the player can only shoot one missile at a time, the touch is ignored if a missile is already flying.

The next part works out what sort of gesture the user made; was it really a swipe, or just a tap? You should only launch missiles on swipes, not taps. You have done this sort of calculation a couple of times already – subtract two coordinates, then use the Pythagorean Theorem to find the distance between them. If the distance is greater than the `TouchDistanceThreshold`

value of 4 points, treat it as an intentional swipe.

*Note:*You could have used UIKit’s built in gesture recognizers for this, but the aim here is to understand how trigonometry is used behind the scenes to implement this kind of logic.

There are two ways you could make the missile fly:

The first option would be to create a `playerMissileVelocity`

vector, based on the angle that you’re aiming the missile. Inside `update()`

, you would then add this velocity (multiplied by the time delta) to the missile sprite’s position each frame, and check if the missile has flown outside of the visible screen area, so that it can be reset. This is very similar to how you made the spaceship move in Part 1 of this tutorial.

However, unlike the spaceship, the missile never changes course; it always flies in a straight line. So you can take a simpler approach:

The second option is to calculate the final destination of the missile in advance, when you launch it. Then you can use a `moveTo()`

action on the missile sprite and let Sprite Kit animate it to it’s final position.

This saves you from having to check whether the missile has left the visible screen, and is also an opportunity to do some more interesting math!

To begin, replace the `// TODO`

comment in `touchesEnded()`

with the following code:

var angle = atan2(swipe.dy, swipe.dx) playerMissileSprite.zRotation = angle - 90 * DegreesToRadians playerMissileSprite.position = playerSprite.position playerMissileSprite.hidden = false |

Here, you use `atan2()`

to convert the swipe vector to an angle, set the sprite’s rotation and position, and make the missile sprite visible.

Now, however, comes the interesting part. You know the starting position of the missile (which is the current position of the player’s ship) and you know the angle (derived from the player’s swipe motion). What you need to calculate now is the destination point of the missile based on these facts.

You already have the direction vector, and you learned in Part 1 how to use *normalization* to set the length of a vector to whatever you need. But what length *do* you want? Well that’s the challenging bit: Because you want the missile to stop when it moves outside the screen border, the length it travels depends on the starting position and direction.

The destination point always lies just outside the screen instead of exactly on the edge of the screen, because it looks better if the missile completely flies out of sight before it vanishes. For this purpose, add another constant at the top of *GameScene.swift*:

let PlayerMissileRadius: CGFloat = 20 |

Finding the destination point is a bit complicated. If you know that (for example) the player is shooting downward, you can work out the vertical distance the missile needs to fly – that is simply the starting Y-position of the missile, plus the `PlayerMissileRadius`

, but you then need to calculate the X component by determining where the missile will intersect that invisible line.

For missiles that fly off the bottom or top edges of the screen the X component of the destination can be calculated with the following formula:

destination.x = playerPos.x + ((destination.y – playerPos.y) / swipe.dy * swipe.dx)

This is similar to the *normalization* technique from Part 1, where you scaled up a vector by first dividing both components by the current length, and then multiplying by the desired length. Here, you work out the ratio of the swipe vector’s Y component to the final distance, then multiply the X component by the same value and add it to the ship’s current X position in order to get the destination X coordinate.

For missiles that go off the left or right edges, you’d use essentially the same function, but just swap all the X and Y values.

This technique of extending a vector until it hits an edge is known as *projection*, and it’s very helpful for all sorts of game applications, such as detecting if an enemy can see the player by projecting a vector along their line of sight and seeing if it hits a wall first, or the player.

There’s a snag, however. If the intersection point is near a corner, it’s not obvious which edge the missile will intersect first:

That’s OK; you’ll just calculate both intersection points, then see which is the shorter distance from the player!

Add the following code immediately beneath the `playerMissileSprite.hidden = false`

line you added to `touchesEnded`

:

//calculate vertical intersection point var destination1 = CGPoint.zeroPoint if swipe.dy > 0 { destination1.y = size.height + PlayerMissileRadius // top of screen } else { destination1.y = -PlayerMissileRadius // bottom of screen } destination1.x = playerSprite.position.x + ((destination1.y - playerSprite.position.y) / swipe.dy * swipe.dx) //calculate horizontal intersection point var destination2 = CGPoint.zeroPoint if swipe.dx > 0 { destination2.x = size.width + PlayerMissileRadius // right of screen } else { destination2.x = -PlayerMissileRadius // left of screen } destination2.y = playerSprite.position.y + ((destination2.x - playerSprite.position.x) / swipe.dx * swipe.dy) |

Here, you’re calculating the two candidate destination points for the missile; now you need to work out which is nearer to the player. Add the following code next, below the code you just wrote:

// find out which is nearer var destination = destination2 if abs(destination1.x) < abs(destination2.x) || abs(destination1.y) < abs(destination2.y) { destination = destination1 } |

You could have used the Pythagorean theorem here to work out the diagonal distance from the player to each intersection point, and chosen the shortest, but there’s a quicker way: you know that since the two possible intersection points lie along the same vector, if either the X or Y component is shorter then the distance as a whole must be shorter – so there’s no need to calculate the diagonal lengths.

Now to fire the missile!

Add this last piece of code to `touchesEnded()`

, immediately after the code you just wrote:

// run the sequence of actions for the firing let missileMoveAction = SKAction.moveTo(destination, duration: 2) playerMissileSprite.runAction(missileMoveAction) { self.playerMissileSprite.hidden = true } |

Build and run the app. You can now swipe to shoot bolts of plasma at the turret. Pretty neat, huh? Note that you can only fire one missile at a time – you have to wait until the previous missile has disappeared from the screen before firing again.

There’s still one problem (isn’t there always?) — The missile appears to travel faster or slower depending on the distance it travels.

That’s because, currently, the duration of the animation is hard-coded to last 2 seconds. If the missile needs to travel further, then it goes faster in order to cover more distance in the same amount of time. It would be more realistic if the missiles always travelled at a consistent speed.

Your good friend Sir Isaac Newton can help out here! As Newton discovered, `time = distance / speed`

. You can use Pythagoras to calculate the distance, so there’s just the matter of specifying the speed.

Add another constant to the top of *GameScene.swift*:

let PlayerMissileSpeed: CGFloat = 300 |

This is the distance that you want the missile to travel each second. Now, replace the last block of code you added with this new version:

// calculate distance let distance = sqrt(pow(destination.x - playerSprite.position.x, 2) + pow(destination.y - playerSprite.position.y, 2)) // run the sequence of actions for the firing let duration = NSTimeInterval(distance / PlayerMissileSpeed) let missileMoveAction = SKAction.moveTo(destination, duration: duration) playerMissileSprite.runAction(missileMoveAction) { self.playerMissileSprite.hidden = true } |

This time, instead of hard-coding the duration, you’ve derived it from the distance and speed by using Newton’s formula. Run the app again and you’ll see that the missile now always flies at the same speed, no matter how far or close the destination point is.

And that’s how you use trig to set up a `moveTo()`

action. It’s a bit involved, but then it’s largely fire & forget because Sprite Kit does all the work of animating for you.

## Hitting Your Targets

Right now, the missile completely ignores the cannon – your spaceship might as well be firing a beam of green light!

That’s about to change. As before, you will use a simple radius-based method of collision detection. You already added a `PlayerMissileRadius`

constant, so you’re all set to detect cannon/missile collisions using the same technique as you used for the cannon/ship collision.

Add a new method:

func checkMissileCannonCollision() { if !playerMissileSprite.hidden { let deltaX = playerMissileSprite.position.x - turretSprite.position.x let deltaY = playerMissileSprite.position.y - turretSprite.position.y let distance = sqrt(deltaX * deltaX + deltaY * deltaY) if distance <= CannonCollisionRadius + PlayerMissileRadius { playerMissileSprite.hidden = true playerMissileSprite.removeAllActions() cannonHP = max(0, cannonHP - 10) updateHealthBar(cannonHealthBar, withHealthPoints: cannonHP) } } } |

This works pretty much the same as `checkShipCannonCollision()`

: you calculate the distance between the sprites, and consider it a collision if that distance is less than the sum of the radii.

If the collision is detected, first hide the missile sprite and cancel its animations; then reduce the cannon’s hit points, and redraw its health bar. Simple!

Add a call to `checkMissileCannonCollision()`

inside the `update()`

method, immediately after the other updates:

checkMissileCannonCollision() |

Build and run, then try it out. Finally you can inflict some damage on the enemy!

Before moving on, it would be nice if the missile had some sound effects. As with the ship-turret collision before, you can play sounds with a Sprite Kit action. Add the following two properties to `GameScene`

:

var missileShootSound: SKAction! var missileHitSound: SKAction! |

Set them up in `didMoveToView()`

:

missileShootSound = SKAction.playSoundFileNamed("Shoot.wav", waitForCompletion: false) missileHitSound = SKAction.playSoundFileNamed("Hit.wav", waitForCompletion: false) |

Now, change the line `playerMissileSprite.runAction(missileMoveAction)`

in `touchesEnded()`

to:

playerMissileSprite.runAction(SKAction.sequence([missileShootSound, missileMoveAction])) { |

Rather than a single action to move the missile, you’re setting up a sequence to play the sound *and then* move the missile.

And, finally, add the following line to `checkMissileCannonCollision()`

, at the bottom of the inner `if`

statement:

runAction(missileHitSound) |

That should do it: The missile now shoots out with a *ZZAPP* sound, and – if your aim is true – hits the turret with a satisfying *BOINK!*

## Challenges for the 1337

Here’s a challenge for you: can you make the cannon shoot back at the spaceship?

You already know all the required pieces, and this will be some really good practice to make sure you understand what we’ve covered so far. Try it out for yourself before you look at the spoiler!

Solution Inside: Make the cannon shoot back | SelectShow |
---|---|

To implement this on your own, all you have to do is create a new missile sprite (using Collision detection with the player works the same way as before: the missile has hit as soon as the distance between the missile and the player becomes less than the sum of their radii. To make the game extra challenging for the player, allow the cannon to shoot more than one missile at a time (hint: you’ll probably want to set up an array of missile sprites). |

Got that done already? Think you’re pretty hot stuff, huh? Here’s another challenge for you!

Currently, your missiles fly to their destination point in a straight line. But what if the missiles were heat-seeking? A heat-seeking missile adjusts its course when it detects that the player has moved.

You’ve got the power of trig on your side, so how would you do it? Hint: instead of calculating the speed and direction of the missile just once, you would do it again and again on each frame, as you do with the ship.

Solution Inside: Make the missile heat seeking | SelectShow |
---|---|

Since you’re calculating the speed and direction of the missile on each frame, you can no longer use a Make sure to give the guided missile a limited lifetime, so the player can avoid it if they keep dodging it long enough, or the game might become a bit too hard to play! |

How’d you do? Is your spaceship dodging guided missiles like Tom Cruise, or still flying around scot-free?

## Adding an Orbiting Shield

To make the game more challenging, you will give the enemy a shield. The shield will be a magical asteroid sprite that orbits the cannon and destroys any missiles that come near it.

Add a couple more constants to the top of *GameScene.swift*:

let OrbiterSpeed: CGFloat = 120 let OrbiterRadius: CGFloat = 60 let OrbiterCollisionRadius: CGFloat = 20 |

And some new properties to `GameScene`

:

let orbiterSprite = SKSpriteNode(imageNamed:"Asteroid") var orbiterAngle: CGFloat = 0 |

Initialize the new sprite inside `didMoveToView()`

, after the other sprites:

addChild(orbiterSprite) |

Then, add the following new method to `GameScene`

:

func updateOrbiter(dt: CFTimeInterval) { // 1 orbiterAngle = (orbiterAngle + OrbiterSpeed * CGFloat(dt)) % 360 // 2 let x = cos(orbiterAngle * DegreesToRadians) * OrbiterRadius let y = sin(orbiterAngle * DegreesToRadians) * OrbiterRadius // 3 orbiterSprite.position = CGPointMake(cannonSprite.position.x + x, cannonSprite.position.y + y) } |

The asteroid will orbit around the cannon. In other words, it describes a circular path, round and round and round and round. To accomplish this, you need two pieces: the radius that determines how far the asteroid is from the center of the cannon, and the angle that describes how far it has rotated around that center point.

This is what `updateOrbiter()`

does:

- It increments the angle by a certain speed (from the
`OrbiterSpeed`

constant), adjusted for the delta time. The angle is then wrapped to the 0 – 360 range using`% 360`

. That isn’t strictly necessary, as`sin()`

and`cos()`

work correctly with angles outside of that range, however if the angles get too large then floating point precision may become a problem (also, it’s easier to visualise angles if they are in this range, for debugging purposes). - It calculates the new X- and Y-positions for the orbiter using
`sin()`

and`cos()`

. These take the radius (which forms the hypotenuse of the triangle) and the current angle, and return the adjacent and opposite sides, respectively. More about this in a second. - It sets the new position of the orbiter sprite by adding the X- and Y-positions to the center position of the cannon.

*Note:* You’re using the `%`

operator to constrain the `orbiterAngle`

to the range 0 – 360, even though `orbiterAngle`

is a CGFloat. In C/Objective-C you would have had to use the `fmod()`

function for this, because the `%`

operator only works with integers, but Swift’s `%`

operator supports floating point values too!

You have briefly seen `sin()`

and `cos()`

in action, but it may not have been entirely clear how they worked. You know that both of these functions can be used to calculate the lengths of the other sides of a right triangle, once you have an angle and the hypotenuse.

But aren’t you curious *why* you can actually do that?

Let’s draw a circle:

The illustration above exactly depicts the situation of the asteroid orbiting around the cannon. The circle describes the path of the asteroid and the origin of the circle is the center of the cannon.

The angle starts at zero degrees but increases all the time until it ends up right back at the beginning. As you can see it, is the radius of the circle that determines how far away from the center the asteroid is placed.

So, given the angle and the radius, you can derive the X- and Y-positions using the cosine and sine, respectively:

Now let’s take a look at a plot of a sine wave and a cosine wave:

On the horizontal axis are the degrees of a circle, from 0 to 360 (or 0 to 2π radians, if you’re a mathematician). The vertical axis usually goes from -1 to +1, but if your circle has a radius that is greater than one (and they tend to) then the vertical axis really goes from –radius to +radius.

As the angle increases from 0 to 360, find the angle on the horizontal axis in the plots for the cosine and sine waves. The vertical axis then tells you what the values for x and y are:

- If the angle is 0 degrees, then cos(0) is 1 * radius but sin(0) is 0 * radius. That corresponds exactly to the (x, y) coordinate in the circle: x is equal to the radius, but y is 0.
- If the angle is 45 degrees, then cos(45) is 0.707 * radius and so is sin(45). This means x and y are both the same at this point on the circle. (Note: if you’re trying this out on a calculator, then switch it to DEG mode first. You’ll get radically different answers if it’s in RAD mode (no pun intended :])
- If the angle is 90 degrees, then cos(90) is 0 * radius and sin(90) is 1 * radius. You’re now at the top of the circle where the (x, y) coordinate is (0, radius).
- And so on, and so on. To get a more intuitive feel for how the coordinates in the circle relate to the values of the sine, cosine and even tangent functions, try out this cool interactive circle.

Make sense? Awesome. Did you also notice that the curves of the sine and cosine are very similar? In fact, the cosine wave is simply the sine wave shifted by 90 degrees. Go ahead and impress your friends and family with your knowledge of the mathematical origins of sine and cosine. :]

Back to coding. Add a call to `updateOrbiter()`

at the bottom of `update()`

:

updateOrbiter(deltaTime) |

Build and run the app. You should now have an asteroid that perpetually circles the enemy cannon.

You can also make the asteroid spin around its own axis: Add the following line to the bottom of `updateOrbiter()`

:

orbiterSprite.zRotation = orbiterAngle * DegreesToRadians |

By setting the rotation to `orbiterAngle`

, the asteroid always stays oriented in the same position relative to the cannon, much like the Moon always shows the same side to the Earth. Even though it looks like it isn’t spinning, it certainly is!

If you insert a minus sign, so that `orbiterSprite.zRotation = -orbiterAngle * DegreesToRadians`

, the Asteroid will appear to spin on its axis relative to the cannon, instead of always facing it. Pick whichever effect you like best. Build and run to play around with it for a bit.

Let’s give the orbiter a purpose. If the missile comes too close, the asteroid will destroy it before it gets a chance to do any damage to the cannon. Add the following method:

func checkMissileOrbiterCollision() { if !playerMissileSprite.hidden { let deltaX = playerMissileSprite.position.x - orbiterSprite.position.x let deltaY = playerMissileSprite.position.y - orbiterSprite.position.y let distance = sqrt(deltaX * deltaX + deltaY * deltaY) if distance < OrbiterCollisionRadius + PlayerMissileRadius { playerMissileSprite.hidden = true playerMissileSprite.removeAllActions() orbiterSprite.setScale(2) orbiterSprite.runAction(SKAction.scaleTo(1, duration: 0.5)) } } } |

And don’t forget to include a call to it at the end of `update()`

:

checkMissileOrbiterCollision() |

This should look pretty familiar; it’s basically the same thing you wrote for `checkMissileCannonCollision()`

. When the collision is detected, the missile sprite is removed. This time, you don’t play a sound, but as an added visual flourish, you increase the size of the asteroid sprite by 2X, and then immediately animate it scaling back down again. This makes it look like the orbiter “ate” the missile!

Build and run to see your new orbiting shield in action.

## Game Over, With Trig!

There is still more that you can do with sines and cosines. They’re not just useful for calculating things with triangles and creating circular paths – they also come in handy for animations.

A good place to demo such an animation is the game over screen. Add the following constant to the top of *GameScene.swift*:

let DarkenOpacity: CGFloat = 0.8 |

And add a few new properties to the top of the `GameScene`

class:

var darkenLayer: SKSpriteNode? var gameOverLabel: SKLabelNode? var gameOver = false var gameOverElapsed: CFTimeInterval = 0 |

You’ll use these properties to keep track of the game state and the nodes to show the “Game Over” information.

Next, add this method to the class:

func checkGameOver(dt: CFTimeInterval) { // 1 if playerHP > 0 && cannonHP > 0 { return } if !gameOver { // 2 gameOver = true gameOverElapsed = 0 stopMonitoringAcceleration() // 3 let fillColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1) darkenLayer = SKSpriteNode(color: fillColor, size: size) darkenLayer?.alpha = 0 darkenLayer/.position = CGPoint(x: size.width/2, y: size.height/2) addChild(darkenLayer!) // 4 let text = (playerHP == 0) ? "GAME OVER" : "Victory!" gameOverLabel = SKLabelNode(fontNamed: "Helvetica") gameOverLabel?.text = text gameOverLabel?.fontSize = 24 gameOverLabel?.position = CGPoint(x: size.width/2 + 0.5, y: size.height/2 + 50) addChild(gameOverLabel!) } else { // 5 darkenLayer?.alpha = min(DarkenOpacity, darkenLayer!.alpha + CGFloat(dt)) } } |

This method checks whether the game is done, and if so, handles the game over animation:

- The game keeps on going until either the player or cannon run out of health points.
- When the game is over, you set
`gameOver`

to true, and disable the accelerometer. - Create a new, all-black color layer and add it on top of everything else. Its alpha opacity is set to 0 initially, so that it is completely transparent. Later in this method, you’ll animate the opacity value of this layer so that it appears to fade in.
- Add a new text label and place it on the screen. The text is either “Victory!” if the player won or “Game Over” if the player lost, determined based on the player’s health points.
- The above steps only happen once to set up the game over screen – every time after that, the code enters the
`else`

clause. Here, you animate the alpha of the new color layer from 0 to 0.8 (the`DarkenOpacity`

constant) – almost completely opaque, but not quite.

Add a call to `checkGameOver()`

at the bottom of `update()`

:

checkGameOver(deltaTime) |

And add a small snippet of logic to the top of `touchesEnded()`

:

if gameOver { let scene = GameScene(size: size) let reveal = SKTransition.flipHorizontalWithDuration(1) view?.presentScene(scene, transition: reveal) return } |

This restarts the game when the user taps on the game over screen.

Build and run, then try it out. Shoot at the cannon or collide your ship with it until one of you runs out of health. The screen will fade to black and the game over text will appear. The game no longer responds to the accelerometer, but the animations still keep going:

This is all fine and dandy, but where are the sine and cosines? As you may have noticed, the fade in animation of the black layer was very linear. It just goes from transparent to opaque at a consistent rate.

We can do better than this – we can use `sin()`

to alter the timing of the fade. This is known as “easing” and the effect you will apply here is known as an “ease out”.

*Note:* You could just use `runAction()`

to do the alpha fade, as it supports various easing modes. Again, the purpose of this tutorial is not to learn Sprite Kit; it’s to learn the math behind it, including easing!

Add a new constant at the top of *GameScene.swift*:

let DarkenDuration: CFTimeInterval = 2 |

Next, change the single line in the `else`

statement in `checkGameOver()`

to:

gameOverElapsed += dt if gameOverElapsed < DarkenDuration { var t = CGFloat(gameOverElapsed / DarkenDuration) t = sin(t * Pi / 2) // ease out darkenLayer.alpha = DarkenOpacity * t } |

`gameOverElapsed`

keeps track of how much time has passed since the game ended. It takes two seconds to fade in the black layer (`DarkenDuration`

). The variable `t`

determines how much of that duration has passed by. It always has a value between 0.0 and 1.0, regardless of how long `DarkenDuration`

really is.

Then you perform the magic trick:

t = sin(t * Pi / 2) // ease out |

This converts `t`

from a linear interpolation into one that breathes a bit more life into things:

Build and run to see the new “ease out” effect. If you find it hard to see the difference, then try it with the “ease out” line commented out, or change the duration of the animation. The effect is subtle, but it’s there.

*Note:* If you want to play with the values and test the effect quickly, try setting `cannonHP`

to 10 so you can end the game with a single shot.

Easing is a subtle effect, so let’s wrap up with a much more obvious bounce effect – because things that bounce are always more fun!

Inside that `else`

clause in `checkGameOver()`

, add the following after the previous code:

// label position let y = abs(cos(CGFloat(gameOverElapsed) * 3)) * 50 gameOverLabel.position = CGPoint(x: gameOverLabel.position.x, y: size.height/2 + y) |

OK, what’s happening here? Recall what a cosine looks like:

If you take the absolute value of `cos()`

– using `abs()`

– then the section that would previously go below zero is flipped. The curve already looks like something that bounces, don’t you think?

Because the output of these functions lies between 0.0 and 1.0, you multiply it by 50 to stretch it out to 0-50. The argument to `cos()`

is normally an angle, but you’re giving it the `gameOverElapsed`

time to make the cosine move forward through its curve.

The factor of 3 is just to make it go a bit faster. You can tinker with these values until you have something that you think looks cool.

Build and run to check out the bouncing text:

You’ve used the shape of the cosine to describe the bouncing motion of the text label. These cosines are useful for all sorts of things!

One last thing you can do is let the bouncing motion lose amplitude over time. You do this by adding a damping factor. Create a new property in `GameScene`

:

var gameOverDampen: CGFloat = 0 |

The idea here is when the game ends, you’ll need to reset this value to 1.0 so the damping takes effect. Over time as the text bounces, the damping will slowly fade off to 0 again.

In `checkGameOver()`

, find the `if`

block where you set `gameOver`

to `true`

and add the following line right after you set that property:

gameOverDampen = 1 |

In the `else`

block, change the code underneath the “// label position” comment to be the following:

let y = abs(cos(CGFloat(gameOverElapsed) * 3)) * 50 * gameOverDampen gameOverDampen = max(0, gameOverDampen - 0.3 * CGFloat(dt)) gameOverLabel.position = CGPoint(x: gameOverLabel.position.x, y: size.height/2 + y) |

It’s mostly the same as before, but you multiply the y-value by the damping factor and, simultaneously, you reduce this damping factor slowly from 1.0 back to 0.0 (but never less than 0; that’s what the `max()`

prevents). Build and run, then try it out!

## Where to Go from Here?

Here is the full TrigBlasterPart2 from this Trigonometry for Game Programming tutorial series.

Congratulations, you have delved into the depths of sine, cosine and tangent, and you have witnessed some examples of how they can be applied in a real game. I hope you’ve seen how handy Trigonometry really is for games!

Note that we didn’t talk much about arcsine and arccosine. They are much less useful in practice than arctangent, although a common use for arccosine is to find the angle between two arbitrary vectors – for example, to model the reflection of a light beam in a mirror, or to calculate how bright an object should be depending on its angle to a light source.

You can find another great example of the usefulness of trigonometric functions in the Tiny Wings tutorial. It uses cosine to give the hills from the game nicely curved shapes.

If you fancy using your new-found skills for more game development, but don’t know where to start, then why not try out our book iOS Games by Tutorials. It will certainly kick start your development!

Drop by the forums to share your successes and agonies with trig. And use your new powers wisely!

Credits: The graphics for this game are based on a free sprite set by Kenney Vleugels. The sound effects are based on samples from freesound.org.

Trigonometry for Games – Sprite Kit and Swift Tutorial: Part 2/2 is a post from: Ray Wenderlich

The post Trigonometry for Games – Sprite Kit and Swift Tutorial: Part 2/2 appeared first on Ray Wenderlich.

## Comments