23
Tec de Monterrey Campus Valle Alto Prof. Daniel Márquez Sprite Kit + Swift Like Batman and Robin or Superman and Lois Lane, Sprite Kit and Swift are an amazing combination: Sprite Kit is one of the best ways to make games on iOS. It’s easy to learn, powerful, and is fully-supported by Apple. Swift is an easy language to get started with, especially if you are a beginner to the iOS platform. In this tutorial, you will learn how to create a simple 2D game using Apple’s 2D game framework, Sprite Kit – using Swift! You can either follow along with this tutorial, or just jump straight to the sample project at the end. And yes. There will be ninjas. Sprite Kit vs. Unity The most popular alternative to Sprite Kit at the moment is a game framework called Unity. Unity was originally developed as a 3D engine, but it recently got full built-in 2D support too. So before you get started, I recommend you put some thought into whether Sprite Kit or Unity is the best choice for your game. Advantages of Sprite Kit It’s built right into iOS. There is no need to download extra libraries or have external dependencies. You can also seamlessly use other iOS APIs like iAd, In-App Purchases, etc. without having to rely on extra plugins. It leverages your existing skills. If you already know Swift and iOS development, you can pick up Sprite Kit extremely quickly. It’s written by Apple. This gives you some confidence that it will be well supported moving forward on all of Apple’s new products. It’s free. Maybe one of the best reasons for small indies! You get all of Sprite Kit’s functionality at no cost. Unity does have a free version but does not have all of the features of the Pro version (you’ll need to upgrade if you want to avoid the Unity splash screen, for example).

SpriteKit Simple Game

Embed Size (px)

DESCRIPTION

Swift simple spritekit game

Citation preview

Page 1: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

Sprite Kit + SwiftLike Batman and Robin or Superman and Lois Lane, Sprite Kit and Swift are an amazing combination:

• Sprite Kit is one of the best ways to make games on iOS. It’s easy to learn, powerful, and is fully-supported by Apple.

• Swift is an easy language to get started with, especially if you are a beginner to the iOS platform.

In this tutorial, you will learn how to create a simple 2D game using Apple’s 2D game framework, Sprite Kit – using Swift!You can either follow along with this tutorial, or just jump straight to the sample project at the end. And yes. There will be ninjas.

Sprite Kit vs. UnityThe most popular alternative to Sprite Kit at the moment is a game framework called Unity. Unity was originally developed as a 3D engine, but it recently got full built-in 2D support too.So before you get started, I recommend you put some thought into whether Sprite Kit or Unity is the best choice for your game.

Advantages of Sprite Kit• It’s built right into iOS. There is no need to download extra libraries

or have external dependencies. You can also seamlessly use other iOS APIs like iAd, In-App Purchases, etc. without having to rely on extra plugins.

• It leverages your existing skills. If you already know Swift and iOS development, you can pick up Sprite Kit extremely quickly.

• It’s written by Apple. This gives you some confidence that it will be well supported moving forward on all of Apple’s new products.

• It’s free. Maybe one of the best reasons for small indies! You get all of Sprite Kit’s functionality at no cost. Unity does have a free version but does not have all of the features of the Pro version (you’ll need to upgrade if you want to avoid the Unity splash screen, for example).

Page 2: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

Advantages of Unity• Cross-platform. This is one of the big ones. If you use Sprite Kit,

you’re locked into the iOS ecosystem. With Unity, you can easily port your games to Android, Windows, and more.

• Visual scene designer. Unity makes it extremely easy to lay out your levels and test your game in realtime with the click of a button. Sprite Kit does have a very basic scene editor in iOS 8, but it is very basic compared to what Unity offers.

• Asset store. Unity comes with a built-in asset store where you can buy various components for your game. Some of these components can save you a good bit of development time!

• More powerful. In general, Unity just has more features and functionality than the Sprite Kit / Scene Kit combination.

Which Should I Choose?After this a lot of you may be thinking, “Well, which 2D framework should I choose?”The answer that depends on what your goals are. Here’s my 2c:

• If you are a complete beginner, or solely focused on iOS: Use Sprite Kit – it’s built in, easy to learn, and will get the job done.

• If you’re want to be cross-platform, or have a more complicated game: Use Unity – it’s more powerful and flexible.

Page 3: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

Hello, Sprite Kit!Let’s start by getting a simple Hello World project up and running by using the Sprite Kit Game template that comes built in to Xcode 6.Start up Xcode, select File\New\Project, choose the iOS\Application\Game template, and click Next:

!Enter SpriteKitSimpleGame for the Product Name, Swift for Language< SpriteKit for Game Technology, iPhone for Devices, and click Next:

!

Page 4: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

Choose somewhere on your drive to save the project, and click Create. Select your iPhone 6 simulator, then click the play button to run the project as-is. After a brief splash screen, you should see the following:

!Sprite Kit is organised into the concept of scenes, which are kind of like “levels’ or “screens” for a game. For example, you might have a scene for the main gameplay area, and another scene for the world map between levels.If you take a look at your project, you’ll see the template has already created a scene for you by default – GameScene. Open GameScene.swift

Page 5: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

and you’ll see that it contains some code to put a label on the screen, and add a rotating spaceship when you tap somewhere.In this tutorial, you’ll mainly be working within GameScene. But before you begin, you have to make a few tweaks because this game needs to run in landscape instead of portrait.

Initial SetupThe template provided to you has two issues. First, it’s set up the game to be Portrait, but you want landscape. Second, it is currently using Sprite Kit’s scene editor, which you don’t need for this tutorial. Let’s fix these issues.First, open your target setting by clicking your SpriteKitSimpleGame project in the Project Navigator, selecting the SpriteKitSimpleGame target. Then, in the Deployment Info section, uncheck Portrait so only Landscape Left and Landscape Right are checked, as shown below:

!Second, delete GameScene.sks and choose Move to Trash when prompted. This file allows you to lay out sprites and other components of a scene visually, however for this game it’s just easier to create things programmatically, so you don’t need it.

Page 6: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

Next, open GameViewController.swift and replace the contents with the following:

import UIKitimport SpriteKit class GameViewController: UIViewController {  override func viewDidLoad() { super.viewDidLoad() let scene = GameScene(size: view.bounds.size) let skView = view as SKView skView.showsFPS = true skView.showsNodeCount = true skView.ignoresSiblingOrder = true scene.scaleMode = .ResizeFill skView.presentScene(scene) }  override func prefersStatusBarHidden() -> Bool { return true }}

GameViewController is a normal UIViewController, except that its root view is a SKView, which is a view that contains a Sprite Kit scene.Here, you’ve implemented viewDidLoad() to create a new instance of the GameScene on startup, with the same size of the view itself.That’s it for the initial setup – now let’s get something on the screen!

Adding a SpriteFirst, download the resources for this project and drag them into your Xcode project. Make sure that “Copy items into destination group’s folder (if needed)” is checked, and that your SpriteKitSimpleGame target is selected.

Page 7: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

Next, open GameScene.swift and replace the contents with the following:

import SpriteKit class GameScene: SKScene {  // 1 let player = SKSpriteNode(imageNamed: "player")  override func didMoveToView(view: SKView) { // 2 backgroundColor = SKColor.whiteColor() // 3 player.position = CGPoint(x: size.width * 0.1, y: size.height * 0.5) // 4 addChild(player) }}

Let’s go over this step-by-step.1 Here you declare a private constant for the player (i.e. the ninja),

which is an example of a sprite. As you can see, creating a sprite is easy – simply pass in the name of the image to use.

2 Setting the background color of a scene in Sprite Kit is as simple as setting the backgroundColor property. Here you set it to white.

3 You position the sprite to be 10% across vertically, and centered horizontally.

4 To make the sprite appear on the scene, you must add it as a child of the scene. This is similar to how you make views children of other views.

Page 8: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

Build and run, and voila – ladies and gentlemen, the ninja has entered the building!

!

Page 9: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

Moving MonstersNext you want to add some monsters into your scene for your ninja to combat. To make things more interesting, you want the monsters to be moving – otherwise there wouldn’t be much of a challenge! So let’s create the monsters slightly off screen to the right, and set up an action for them telling them to move to the left.Add the following methods to GameScene.swift:func random() -> CGFloat { return CGFloat(Float(arc4random()) / 0xFFFFFFFF)} func random(#min: CGFloat, max: CGFloat) -> CGFloat { return random() * (max - min) + min} func addMonster() {  // Create sprite let monster = SKSpriteNode(imageNamed: "monster")  // Determine where to spawn the monster along the Y axis let actualY = random(min: monster.size.height/2, max: size.height - monster.size.height/2)  // Position the monster slightly off-screen along the right edge, // and along a random position along the Y axis as calculated above monster.position = CGPoint(x: size.width + monster.size.width/2, y: actualY)  // Add the monster to the scene addChild(monster)  // Determine speed of the monster let actualDuration = random(min: CGFloat(2.0), max: CGFloat(4.0))  // Create the actions let actionMove = SKAction.moveTo(CGPoint(x: -monster.size.width/2, y: actualY), duration: NSTimeInterval(actualDuration)) let actionMoveDone = SKAction.removeFromParent() monster.runAction(SKAction.sequence([actionMove, actionMoveDone])) }

Page 10: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

The first part should make sense based on what we’ve discussed so far: you do some simple calculations to determine where you want to create the object, set the position of the object, and add it to the scene the same way you did for the player sprite.

The new element here is adding actions. Sprite Kit provides a lot of extremely handy built-in actions that help you easily change the state of sprites over time, such as move actions, rotate actions, fade actions, animation actions, and more. Here you use three actions on the monster:

• SKAction.moveTo(_:duration:): You use this action to direct the object to move off-screen to the left. Note that you can specify the duration for how long the movement should take, and here you vary the speed randomly from 2-4 seconds.

• SKAction.removeFromParent(): Sprite Kit comes with a handy action that removes a node from its parent, effectively “deleting it” from the scene. Here you use this action to remove the monster from the scene when it is no longer visible. This is important because otherwise you’d have an endless supply of monsters and would eventually consume all device resources.

• SKAction.sequence(_:): The sequence action allows you to chain together a sequence of actions that are performed in order, one at a time. This way, you can have the “move to” action perform first, and once it is complete perform the “remove from parent” action.

One last thing. You need to actually call the method to create monsters! And to make things fun, let’s have monsters continuously spawning over time.

Simply add the following code to the end of didMoveToView():runAction(SKAction.repeatActionForever( SKAction.sequence([ SKAction.runBlock(addMonster), SKAction.waitForDuration(1.0) ])))

Page 11: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

Here you run a sequence of actions to call a block of code (you can seamlessly pass in your addMonster() method here thanks to the power of Swift), and then wait for 1 second. You then repeat this sequence of actions endlessly.That’s it! Build and run the project, now you should see monsters happily moving across the screen:

!

Shooting ProjectilesAt this point, the ninja is just begging for some action – so let’s add shooting! There are many ways you could implement shooting, but for this game you are going to make it so when the user taps the screen, it shoots a projectile from the player in the direction of the tap.I want to use a “move to” action to implement this to keep things at a beginner level, but in order to use this you have to do a little math.This is because the “move to” action requires you to give a destination for the projectile, but you can’t just use the touch point because the touch point represents just the direction to shoot relative to the player. You actually want to keep the bullet moving through the touch point until the bullet goes off-screen.

Page 12: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

Here’s a picture that illustrates the matter:

!So as you can see, you have a small triangle created by the x and y offset from the origin point to the touch point. You just need to make a big triangle with the same ratio – and you know you want one of the endpoints to be off the screen.To run these calculations, it really helps if you have some basic vector math routines you can call (like methods to add and subtract vectors). However, Sprite Kit doesn’t have any by default so you’ll have to write your own.Luckily they are very easy to write thanks to the power of Swift operator overloading. Add these functions to the top of your file, right before the GameScene class:func + (left: CGPoint, right: CGPoint) -> CGPoint { return CGPoint(x: left.x + right.x, y: left.y + right.y)} func - (left: CGPoint, right: CGPoint) -> CGPoint { return CGPoint(x: left.x - right.x, y: left.y - right.y)} func * (point: CGPoint, scalar: CGFloat) -> CGPoint { return CGPoint(x: point.x * scalar, y: point.y * scalar)} func / (point: CGPoint, scalar: CGFloat) -> CGPoint {

Page 13: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

return CGPoint(x: point.x / scalar, y: point.y / scalar)} #if !(arch(x86_64) || arch(arm64))func sqrt(a: CGFloat) -> CGFloat { return CGFloat(sqrtf(Float(a)))}#endif extension CGPoint { func length() -> CGFloat { return sqrt(x*x + y*y) }  func normalized() -> CGPoint { return self / length() }}These are standard implementations of some vector math functions. If you’re confused about what’s going on here or are new to vector math, check out this quick vector math explanation.Next, add a new method to the file:override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {  // 1 - Choose one of the touches to work with let touch = touches.first as! UITouch let touchLocation = touch.locationInNode(self)  // 2 - Set up initial location of projectile let projectile = SKSpriteNode(imageNamed: "projectile") projectile.position = player.position  // 3 - Determine offset of location to projectile let offset = touchLocation - projectile.position  // 4 - Bail out if you are shooting down or backwards if (offset.x < 0) { return }  // 5 - OK to add now - you've double checked position addChild(projectile)  // 6 - Get the direction of where to shoot let direction = offset.normalized()  // 7 - Make it shoot far enough to be guaranteed off screen let shootAmount = direction * 1000  // 8 - Add the shoot amount to the current position let realDest = shootAmount + projectile.position 

Page 14: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

// 9 - Create the actions let actionMove = SKAction.moveTo(realDest, duration: 2.0) let actionMoveDone = SKAction.removeFromParent() projectile.runAction(SKAction.sequence([actionMove, actionMoveDone])) }There’s a lot going on here, so let’s review it step by step.

1 One of the cool things about SpriteKit is that it includes a category on UITouch with locationInNode(_:) and previousLocationInNode(_:) methods. These let you find the coordinate of a touch within a SKNode’s coordinate system. In this case, you use it to find out where the touch is within the scene’s coordinate system.

2 You then create a projectile and place it where the player is to start. Note you don’t add it to the scene yet, because you have to do some sanity checking first – this game does not allow the ninja to shoot backwards.

3 You then subtract the projectile’s current position from the touch location to get a vector from the current position to the touch location.

4 If the X value is less than 0, this means the player is trying to shoot backwards. This is is not allowed in this game (real ninjas don’t look back!), so just return.

5 Otherwise, it’s OK to add the projectile to the scene. 6 Convert the offset into a unit vector (of length 1) by calling

normalized(). This will make it easy to make a vector with a fixed length in the same direction, because 1 * length = length.

7 Multiply the unit vector in the direction you want to shoot in by 1000. Why 1000? It will definitely be long enough to go past the edge of the screen :]

8 Add the shoot amount to the current position to get where it should end up on the screen.

9 Finally, create moveTo(_:, duration:) and removeFromParent() actions like you did earlier for the monster.

Page 15: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

Build and run, and now your ninja should be able to fire away at the oncoming hordes!

!

Collision Detection and Physics: OverviewSo now you have shurikens flying everywhere – but what your ninja really wants to do is to lay some smack down. So let’s add in some code to detect when your projectiles intersect your targets.One of the nice things about Sprite Kit is it comes with a physics engine built right in! Not only are physics engines great for simulating realistic movement, but they are also great for collision detection purposes.Let’s set up the game to use Sprite Kit’s physics engine to determine when monsters and projectiles collide. At a high level, here’s what you’re going to do:

• Set up the physics world. A physics world is the simulation space for running physics calculations. One is set up on the scene by default, and you might want to configure a few properties on it, like gravity.

• Create physics bodies for each sprite. In Sprite Kit, you can associate a shape to each sprite for collision detection purposes, and set certain properties on it. This is called a physics body. Note that the physics body does not have to be the exact same shape as the sprite. Usually it’s a simpler, approximate shape rather than pixel-perfect, since that is good enough for most games and performant.

Page 16: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

• Set a category for each type of sprite. One of the properties you can set on a physics body is a category, which is a bitmask indicating the group (or groups) it belongs to. In this game, you’re going to have two categories – one for projectiles, and one for monsters. Then later when two physics bodies collide, you can easily tell what kind of sprite you’re dealing with by looking at its category.

• Set a contact delegate. Remember that physics world from earlier? Well, you can set a contact delegate on it to be notified when two physics bodies collide. There you’ll write some code to examine the categories of the objects, and if they’re the monster and projectile, you’ll make them go boom!

Now that you understand the battle plan, it’s time to put it into action!

Collision Detection and Physics: ImplementationStart by adding this struct to the top of GameScene.swift:struct PhysicsCategory { static let None : UInt32 = 0 static let All : UInt32 = UInt32.max static let Monster : UInt32 = 0b1 // 1 static let Projectile: UInt32 = 0b10 // 2}This is setting up the constants for the physics categories you’ll need in a bit – no pun intended! :]Note: You may be wondering what the fancy syntax is here. Note that the category on Sprite Kit is just a single 32-bit integer, and acts as a bitmask. This is a fancy way of saying each of the 32-bits in the integer represents a single category (and hence you can have 32 categories max). Here you’re setting the first bit to indicate a monster, the next bit over to represent a projectile, and so on.Next, mark GameScene as implementing the SKPhysicsContactDelegate protocol:class GameScene: SKScene, SKPhysicsContactDelegate {Then inside didMoveToView(_:) add these lines after adding the player to the scene:physicsWorld.gravity = CGVectorMake(0, 0)physicsWorld.contactDelegate = selfThis sets up the physics world to have no gravity, and sets the scene as the delegate to be notified when two physics bodies collide.

Page 17: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

Inside the addMonster() method, add these lines right after creating the monster sprite:monster.physicsBody = SKPhysicsBody(rectangleOfSize: monster.size) // 1monster.physicsBody?.dynamic = true // 2monster.physicsBody?.categoryBitMask = PhysicsCategory.Monster // 3monster.physicsBody?.contactTestBitMask = PhysicsCategory.Projectile // 4monster.physicsBody?.collisionBitMask = PhysicsCategory.None // 5Let’s go over what this does line by line.

1 Creates a physics body for the sprite. In this case, the body is defined as a rectangle of the same size of the sprite, because that’s a decent approximation for the monster.

2 Sets the sprite to be dynamic. This means that the physics engine will not control the movement of the monster – you will through the code you’ve already written (using move actions).

3 Sets the category bit mask to be the monsterCategory you defined earlier.

4 The contactTestBitMask indicates what categories of objects this object should notify the contact listener when they intersect. You choose projectiles here.

5 The collisionBitMask indicates what categories of objects this object that the physics engine handle contact responses to (i.e. bounce off of). You don’t want the monster and projectile to bounce off each other – it’s OK for them to go right through each other in this game – so you set this to 0.

Next add some similar code to touchesEnded(_:withEvent:), right after the line setting the projectile’s position:projectile.physicsBody = SKPhysicsBody(circleOfRadius: projectile.size.width/2)projectile.physicsBody?.dynamic = trueprojectile.physicsBody?.categoryBitMask = PhysicsCategory.Projectileprojectile.physicsBody?.contactTestBitMask = PhysicsCategory.Monsterprojectile.physicsBody?.collisionBitMask = PhysicsCategory.Noneprojectile.physicsBody?.usesPreciseCollisionDetection = true

As a test, see if you can understand each line here and what it does. If not, just refer back to the points explained above!

As a second test, see if you can spot two differences. Answer below!

Page 18: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

What Are the Differences?

1 You’re using a circle shaped body instead of a rectangle body. Since the projectile is a nice circle this makes for a better match.

2 You also set usesPreciseCollisionDetection to true. This is important to set for fast moving bodies (like projectiles), because otherwise there is a chance that two fast moving bodies can pass through each other without a collision being detected.

Next, add a method that will be called when the projectile collides with the monster. Note that nothing calls this automatically, you will be calling this later.

func projectileDidCollideWithMonster(projectile:SKSpriteNode, monster:SKSpriteNode) { println("Hit") projectile.removeFromParent() monster.removeFromParent()}

All you do here is remove the projectile and monster from the scene when they collide. Pretty simple, eh?Now it’s time to implement the contact delegate method. Add the following new method to the file:func didBeginContact(contact: SKPhysicsContact) {  // 1 var firstBody: SKPhysicsBody var secondBody: SKPhysicsBody if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask { firstBody = contact.bodyA secondBody = contact.bodyB } else { firstBody = contact.bodyB secondBody = contact.bodyA }  // 2 if ((firstBody.categoryBitMask & PhysicsCategory.Monster != 0) && (secondBody.categoryBitMask & PhysicsCategory.Projectile != 0)) { projectileDidCollideWithMonster(firstBody.node as SKSpriteNode, monster: secondBody.node as SKSpriteNode) } 

Page 19: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

}Since you set the scene as the contactDelegate of the physics world earlier, this method will be called whenever two physics bodies collide (and their contactTestBitMasks are set appropriately).There are two parts to this method:

1 This method passes you the two bodies that collide, but does not guarantee that they are passed in any particular order. So this bit of code just arranges them so they are sorted by their category bit masks so you can make some assumptions later.

2 Finally, it checks to see if the two bodies that collide are the projectile and monster, and if so calls the method you wrote earlier.

Give it a build and run, and now when your projectiles intersect targets they should disappear!

Finishing TouchesYou’re pretty close to having a workable (but extremely simple) game now. You just need to add some sound effects and music (since what kind of game doesn’t have sound!) and some simple game logic.Sprite Kit does not come with an audio engine like Cocos2D does, but the good news it does come with a simple way to play sound effects via actions, and that you can play background music pretty easily with AVFoundation.You already have some cool background music I made and an awesome pew-pew sound effect in your project, from the resources for this tutorial you added to your project earlier. You just need to play them!To do this, add the following code to the top of GameScene.swift:import AVFoundation var backgroundMusicPlayer: AVAudioPlayer! func playBackgroundMusic(filename: String) { let url = NSBundle.mainBundle().URLForResource( filename, withExtension: nil) if (url == nil) { println("Could not find file: \(filename)") return }  var error: NSError? = nil backgroundMusicPlayer = AVAudioPlayer(contentsOfURL: url, error: &error) if backgroundMusicPlayer == nil { println("Could not create audio player: \(error!)")

Page 20: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

return }  backgroundMusicPlayer.numberOfLoops = -1 backgroundMusicPlayer.prepareToPlay() backgroundMusicPlayer.play()}This is some AVFoundation code to play some music endlessly.To try this out, simply add this line to the beginning of didMoveToView(_:):playBackgroundMusic("background-music-aac.caf")As for the sound effect, add this line to the top of touchesEnded(_:withEvent:):runAction(SKAction.playSoundFileNamed("pew-pew-lei.caf", waitForCompletion: false))Pretty handy, eh? You can play a sound effect with one line!Build and run, and enjoy your groovy tunes!

Game Over, Man!Now, let’s create a new scene that will serve as your “You Win” or “You Lose” indicator. Create a new file with the iOS\Source\Swift File template, name the file GameOverScene and click Create.Then replace GameOverScene.swift with the following:import Foundationimport SpriteKit class GameOverScene: SKScene {  init(size: CGSize, won:Bool) {  super.init(size: size)  // 1 backgroundColor = SKColor.whiteColor()  // 2 var message = won ? "You Won!" : "You Lose :["  // 3 let label = SKLabelNode(fontNamed: "Chalkduster") label.text = message label.fontSize = 40 label.fontColor = SKColor.blackColor() label.position = CGPoint(x: size.width/2, y: size.height/2) addChild(label)  // 4 runAction(SKAction.sequence([ SKAction.waitForDuration(3.0),

Page 21: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

SKAction.runBlock() { // 5 let reveal = SKTransition.flipHorizontalWithDuration(0.5) let scene = GameScene(size: size) self.view?.presentScene(scene, transition:reveal) } ]))  }  // 6 required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }}There are five parts to point out here

1 Sets the background color to white, same as you did for the main scene.

2 Based on the won parameter, sets the message to either “You Won” or “You Lose”.

3 This is how you display a label of text to the screen with Sprite Kit. As you can see, it’s pretty easy – you just choose your font and set a few parameters.

4 Finally, this sets up and runs a sequence of two actions. I’ve included them all inline here to show you how handy that is (instead of having to make separate variables for each action). First it waits for 3 seconds, then it uses the runBlock action to run some arbitrary code.

5 This is how you transition to a new scene in Sprite Kit. First you can pick from a variety of different animated transitions for how you want the scenes to display – you choose a flip transition here that takes 0.5 seconds. Then you create the scene you want to display, and use the presentScene(_:transition:) method on the self.view property.

6 If you override an initializer on a scene, you must implement the required init(coder:) initializer as well. However this initializer will never be called, so you just add a dummy implementation with a fatalError(_:) for now.

Page 22: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

So far so good, now you just need to set up your main scene to load the game over scene when appropriate.

Switch back to GameScene.swift, and inside addMonster(), replace the last line that runs the actions on the monster with the following:let loseAction = SKAction.runBlock() { let reveal = SKTransition.flipHorizontalWithDuration(0.5) let gameOverScene = GameOverScene(size: self.size, won: false) self.view?.presentScene(gameOverScene, transition: reveal)}monster.runAction(SKAction.sequence([actionMove, loseAction, actionMoveDone]))This creates a new “lose action” that displays the game over scene when a monster goes off-screen. See if you understand each line here, if not refer to the explanation for the previous code block.Also, another pop-quiz for you: why do you run the loseAction before actionMoveDone? Try reversing them to see what happens if you don’t know.

Why is Lose Action First?

As soon as you remove a sprite from its parent, it is no longer in the scene hierarchy so no more actions will take place from that point on. So you don’t want to remove the sprite from the scene until you’ve transitioned to the lose scene. Actually you don’t even need to call to actionMoveDone anymore since you’re transitioning to a new scene, but I’ve left it here for educational purposes.

Now you should handle the win case too – don’t be cruel to your players! :] Add a new property to the top of GameScene, right after the declaration of player:var monstersDestroyed = 0And add this to the bottom of projectile(_:didCollideWithMonster:):monstersDestroyed++if (monstersDestroyed > 30) { let reveal = SKTransition.flipHorizontalWithDuration(0.5) let gameOverScene = GameOverScene(size: self.size, won: true) self.view?.presentScene(gameOverScene, transition: reveal)}Go ahead and give it a build and run, and you should now have win and lose conditions and see a game over scene when appropriate!

Page 23: SpriteKit Simple Game

Tec de MonterreyCampus Valle Alto

Prof. Daniel Márquez

!

References:

Deitel, P., & Deitel, H. (n.d.). IOS 8 for programmers: An app-driven approach with Swift. (Third ed.).

Apple, C. (2014, January 1). Swift - Apple Developer. Retrieved April 28, 2015, from http://developer.apple.com/swift/

Developer.apple.com,. 'Swift/Adventure'. N.p., 2015. Web. 28 Apr. 2015.

Ray Wenderlich,. 'Sprite Kit Swift'. N.p., 2015. Web. 28 Apr. 2015.