Sunteți pe pagina 1din 23

Tec de Monterrey

Campus Valle Alto

Prof. Daniel Mrquez

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. Its 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
Apples 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


Its 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.
Its written by Apple. This gives you some confidence that it will be
well supported moving forward on all of Apples new products.
Its free. Maybe one of the best reasons for small indies! You get all
of Sprite Kits functionality at no cost. Unity does have a free version
but does not have all of the features of the Pro version (youll need to
upgrade if you want to avoid the Unity splash screen, for example).

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

Advantages of Unity
Cross-platform. This is one of the big ones. If you use Sprite Kit,
youre 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. Heres my 2c:
If you are a complete beginner, or solely focused on iOS: Use Sprite
Kit its built in, easy to learn, and will get the job done.
If youre want to be cross-platform, or have a more complicated
game: Use Unity its more powerful and flexible.

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

Hello, Sprite Kit!


Lets 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:

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

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, youll see the template has already
created a scene for you by default GameScene. Open GameScene.swift

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

and youll 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, youll 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 Setup
The template provided to you has two issues. First, its set up the game to
be Portrait, but you want landscape. Second, it is currently using Sprite
Kits scene editor, which you dont need for this tutorial. Lets 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 its just easier to create things
programmatically, so you dont need it.

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

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


following:
import UIKit
import 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, youve implemented viewDidLoad() to create a new instance of the
GameScene on startup, with the same size of the view itself.

Thats it for the initial setup now lets get something on the screen!

Adding a Sprite
First, download the resources for this project and drag them into your
Xcode project. Make sure that Copy items into destination groups folder
(if needed) is checked, and that your SpriteKitSimpleGame target is
selected.

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

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)
}
}

Lets 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.

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

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

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

Moving Monsters
Next 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 wouldnt be much of a challenge! So lets 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]))

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

The first part should make sense based on what weve 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 youd 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, lets 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)
])
))

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

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.
Thats it! Build and run the project, now you should see monsters happily
moving across the screen:

Shooting Projectiles
At this point, the ninja is just begging for some action so lets 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 cant 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.

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

Heres 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 doesnt have any by default so youll 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 {

Tec de Monterrey
Campus Valle Alto
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()
}
}

Prof. Daniel Mrquez

These are standard implementations of some vector math functions. If


youre confused about whats 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

Tec de Monterrey
Prof. Daniel Mrquez
Campus Valle Alto
// 9 - Create the actions
let actionMove = SKAction.moveTo(realDest, duration: 2.0)
let actionMoveDone = SKAction.removeFromParent()
projectile.runAction(SKAction.sequence([actionMove, actionMoveDone]))

Theres a lot going on here, so lets 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
SKNodes coordinate system. In this case, you use it to find out
where the touch is within the scenes coordinate system.
2 You then create a projectile and place it where the player is to start.
Note you dont 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 projectiles 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 dont look
back!), so just return.
5 Otherwise, its 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.

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

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

Collision Detection and Physics: Overview


So now you have shurikens flying everywhere but what your ninja really
wants to do is to lay some smack down. So lets 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.
Lets set up the game to use Sprite Kits physics engine to determine when
monsters and projectiles collide. At a high level, heres what youre 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
its a simpler, approximate shape rather than pixel-perfect, since that
is good enough for most games and performant.

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

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, youre 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 youre 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 youll write some code to examine the
categories of the objects, and if theyre the monster and projectile,
youll make them go boom!
Now that you understand the battle plan, its time to put it into action!

Collision Detection and Physics:


Implementation
Start 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 youll 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 youre
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 = self

This sets up the physics world to have no gravity, and sets the scene as the
delegate to be notified when two physics bodies collide.

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

Inside the addMonster() method, add these lines right after creating the
monster sprite:
monster.physicsBody = SKPhysicsBody(rectangleOfSize: monster.size) // 1
monster.physicsBody?.dynamic = true // 2
monster.physicsBody?.categoryBitMask = PhysicsCategory.Monster // 3
monster.physicsBody?.contactTestBitMask = PhysicsCategory.Projectile // 4
monster.physicsBody?.collisionBitMask = PhysicsCategory.None // 5

Lets 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 thats 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
youve 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 dont want the monster and projectile to bounce off each
other its 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 projectiles position:
projectile.physicsBody = SKPhysicsBody(circleOfRadius: projectile.size.width/2)
projectile.physicsBody?.dynamic = true
projectile.physicsBody?.categoryBitMask = PhysicsCategory.Projectile
projectile.physicsBody?.contactTestBitMask = PhysicsCategory.Monster
projectile.physicsBody?.collisionBitMask = PhysicsCategory.None
projectile.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!

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

What Are the Differences?


1
2

Youre using a circle shaped body instead of a rectangle body. Since


the projectile is a nice circle this makes for a better match.
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 its 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)
}

Tec de Monterrey
Campus Valle Alto
}

Prof. Daniel Mrquez

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 Touches
Youre 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 doesnt 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!)")

Tec de Monterrey
Campus Valle Alto
return
}

backgroundMusicPlayer.numberOfLoops = -1
backgroundMusicPlayer.prepareToPlay()
backgroundMusicPlayer.play()
}

Prof. Daniel Mrquez

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, lets 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 Foundation
import 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),

Tec de Monterrey
Campus Valle Alto
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")
}
}

Prof. Daniel Mrquez

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, its pretty easy you just choose your font and set a
few parameters.
4 Finally, this sets up and runs a sequence of two actions. Ive 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.

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

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 dont
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
dont want to remove the sprite from the scene until youve transitioned to
the lose scene. Actually you dont even need to call to actionMoveDone
anymore since youre transitioning to a new scene, but Ive left it here for
educational purposes.
Now you should handle the win case too dont be cruel to your
players! :] Add a new property to the top of GameScene, right after the
declaration of player:
var monstersDestroyed = 0

And 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!

Tec de Monterrey
Campus Valle Alto

Prof. Daniel Mrquez

!
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.

S-ar putea să vă placă și