Why isn't func motionEnded not working in GameScene?

| | August 10, 2015

I have a title screen on a game I’m trying to learn making and want to add a feature that responds to a user shaking. The function works when put standalone but not on this page. By not working I mean it appears to do nothing (won’t even print to the logs).

The function in question is motionEnded func.

import SpriteKit
import AVFoundation
import iAd

class GameScene: SKScene {

    //loud soundfiles
    var titleMusic = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Loping Sting", ofType: "mp3")!)
    var audioPlayer = AVAudioPlayer()

    let playButton = SKSpriteNode(imageNamed: "PlayNow")
    let titleScreen = SKSpriteNode(imageNamed: "Title")
    let titleOrange = SKSpriteNode(imageNamed: "hero")

    override func didMoveToView(view: SKView) {

        //stop music from game
        musicPlayer.stop()

        //play sound file
        audioPlayer = AVAudioPlayer(contentsOfURL: titleMusic, error: nil)
        audioPlayer.prepareToPlay()
        audioPlayer.play()

        self.titleScreen.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
        self.playButton.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 100)
        self.addChild(self.titleScreen)
        self.addChild(self.playButton)

        //animate button
        let pulseUp = SKAction.scaleTo(1.1, duration: 0.9)
        let pulseDown = SKAction.scaleTo(0.7, duration: 0.9)
        let pulse = SKAction.sequence([pulseDown, pulseUp])
        let repeatPulse = SKAction.repeatActionForever(pulse)
        self.playButton.runAction(repeatPulse)

        //show hero
        titleOrange.position = CGPointMake(CGRectGetMidX(self.frame), 363)
        self.addChild(titleOrange)
    }

    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
        for touch: AnyObject in touches {
            let location = touch.locationInNode(self)
            if self.nodeAtPoint(location) == self.playButton {
                var scene = PlayScene(size: self.size)
                let skView = self.view as SKView?
                scene.scaleMode = .ResizeFill
                scene.size = skView!.bounds.size
                skView?.presentScene(scene)
            }
        }
    }

    override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent) {
        if motion == .MotionShake {
            println("Shake")
        }
    }

    override func update(currentTime: CFTimeInterval) {
    }
}

One Response to “Why isn't func motionEnded not working in GameScene?”

  1. Since you had it working previously, I presume you have applicationSupportsShakeToEdit set to true (this is the default anyway).

    You then need to ensure that your scene GameScene becomes the first responder – the first responder will (as the name implies) be the first to be given the opportunity to respond to motion events, and after that it progresses up the responder chain. SKScene conforms to the UIResponder protocol, so you just need to allow it to become first responder by overriding a method, and then call a couple of responder methods when the scene appears/disappears:

    override func canBecomeFirstResponder() -> Bool {
        return true
    }
    
    override func didMoveToView(view: SKView) {
        // ...
        becomeFirstResponder()
    }
    
    override func willMoveFromView(view: SKView) {
        // ...
        resignFirstResponder()
    }
    

    Note that making your scene the first responder may affect other event handling code elsewhere in your app, depending on your app’s structure.

Leave a Reply