Kodeco Forums

Sprite Kit Swift 2 Tutorial for Beginners

Learn how to make your first iOS game in this Sprite Kit Swift 2 tutorial for complete beginners - and yes, there are ninjas!


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/1513-sprite-kit-swift-2-tutorial-for-beginners

Thanks for the great tutorial Ray! It works well and did a good job breaking the ice with my first time using SpriteKit with Swift. Iā€™m new to iOS development, I just started to dabble in it about a month ago, and I found this tutorial explained very well even for a noob like me.

I have a couple of questions.

  1. Why does the background audio playback stop after the game scene is loaded, just after the transition animation. This only happens after finishing the first round and starting the next (after the first time the game scene loads, after the first transition animation). Note I can hear the audio for the duration of the transition animation then it stops.

  2. When I played this on my actual iPhone (5S), the audio is only heard if I have my headphones plugged in. For some unknown reason the audio doesnā€™t play over the speakers.

Hi Ray,

I want to bring up a possible issue with this tutorial. It may be changed since Swift 2.2 revision went out but when I use code such as:

let actualY = random(min: monster.size.height/2, max: size.height - monster.size.height/2)

I get an error of ā€œUse of unresolved identifier ā€˜sizeā€™ā€

I tried to append the statement with an identifier, such as monster.size.height but that saw the code as an argument and gave me another error. I also tried adding SKScene.size.height which cleared the errors, but I donā€™t think I want to be setting the monsterā€™s position based on the sceneā€™s size and height do I?ā€™

Anyway, Iā€™ll keep playing around with it, but I donā€™t wan to set a parameter thatā€™s going to make it work the way it wasnā€™t intended to for this tutorial.

Thanks!!

Hi Technickel,

can you post the code that is in your addMonster() function?

that wat its easyer to spot if theres something wrong in your code and where :slight_smile:

A great tutorial, as always. Thanks!

Just one note. I think firstBody and secondBody need to be switched in the following line: projectileDidCollideWithMonster(firstBody.node as! SKSpriteNode, monster: secondBody.node as! SKSpriteNode)
The projectile node is supposed to be passed in first, then the monster node. But the bit-wise check just above this line assigns the monster node to firstBody and the projectile to secondBody. So, as it stands now, the monster node is passed in first, followed by the projectile node.

The outcome happens to be exactly the same in this particular tutorial because both monster and the projectile are removed from the scene at the same time. But inside projectileDidCollideWithMonster(), ā€œprojectileā€ is monster, and ā€œmonsterā€ is projectile.

I love RW tutorials. They are not only insightful, but also simple to understand and fun to code. Thanks for the great work!

Regarding the comment that ā€œsizeā€ is undefined, I think addMonster should be defined inside SKScene:

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)
    self.addMonster()
}

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: self.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: self.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]))
    
}

}

func random() ā†’ CGFloat {
return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
}

func random(min min: CGFloat, max: CGFloat) ā†’ CGFloat {
return random() * (max - min) + min
}

Hi Ray,

I was wondering if this tutorial would still work if when I first created the project, I set the devices to Universal. I was also wondering if there is a way to change that without having to restart all the coding. Thank you.

Iā€™m able to get the game to crash consistently when running inside the simulator. The crash occurs when I rapid fire more than one projectile at a monster and the first projectile hits the monster.

Iā€™ve confirmed itā€™s not a mistake on my part in entering the code by running the downloadable full source thatā€™s provided and reproducing the crash.

The error message in the console window at the bottom is ā€œfatal error: unexpectedly found nil while unwrapping an Optional valueā€. In the GameScene.swift file, Xcode has highlighted in red the call to projectileDidCollideWithMonster inside the didBeginContact method. The following message is given below the highlighted text:ā€œThread 1:EXC_BAD_INSTRUCTIONā€¦ā€

Iā€™m still relatively new to programming on the Mac, so Iā€™m hoping that wiser and more experienced minds can diagnose and solve this problem.

Just wondering if youā€™ll update this tut to Swift 2.3 / Xcode 7.3.3 ??? Seems some things have changed sinceā€¦

If a projectile hits two monsters at the same time, you will get the error because projectile gets destroyed after colliding with first monster and then when it comes time to evaluate and remove projectile for second monster, the projectile does not exist.

The easiest way to handle this is to check if projectile is ā€œnilā€ā€¦if nil then dont remove it. Another modification would be to not remove projectile and let it continue to destroy monsters even after the first one.

        if (secondBody.node != nil){
            secondBody.node!.removeFromParent()
        }
        firstBody.node!.removeFromParent()

I canā€™t seem to make my projectiles destroy the monster and themselves upon impact. I believe that I have put everything where it needs to go and typed it all up correctly. I can send the code over to you if necessary.

Thanks!

Having the same problem as gijo342

If you collisions are not working, and if you are using Xcode8/Swift 3 with the Swift 2 version of this tutorial, note that the SKPhysicsContactDelegate method signatures have changed from this:

func didBeginContact(contact: SKPhysicsContact) {

to this:

func didBegin(_ contact: SKPhysicsContact) {

If you are using the old version of this contact method, it will never be called, and you wonā€™t get any kind of warning or error from Xcode that your code is wrong (because the SKPhysicsContactDelegate methods are optional)

Thanks Ray for the great tutorial! I am inspired to write a game. It involves striking a small oblong stick on the ground with a long stick to make the wedge jump and then with same long stick hit the small stick it like you a baseballā€¦The striking is collision and then there is gravity to introduce. Is there a tutorial to include force against gravity?

Thanks
Ram

Hi all, this tutorial has now been updated: hereā€™s the new one: https://www.raywenderlich.com/145318/spritekit-swift-3-tutorial-beginners

@rmasoor We have several chapters on game physics in 2D Apple Games by Tutorials. Hope that helps!

Sorry this was so late, but I picked this tutorial up again another day and it worked. Thanks though!