【问题标题】:iOS unpausing game after didBecomeActive在 didBecomeActive 之后 iOS 取消暂停游戏
【发布时间】:2016-09-02 01:33:01
【问题描述】:

前段时间我在didBecomeActive 时遇到暂停游戏的问题,然后我找到了一个我认为有效的解决方案,直到现在。
我发现当我离开而不是终止游戏时,iOS会自动暂停我的游戏(全部);当回来(didBecomeActive)时,它会取消暂停。因为我的意思是暂停一个单一层 (gameLayer),所以我创建了一个布尔变量和一个 if 条件来检查我的游戏是否暂停。

如果checkPause == false (not paused) -> 回到游戏时它会调用一个暂停函数(效果很好)(片刻之后?!被系统取消暂停)
如果checkPause == true (paused) -> 它将设置gameLayer.paused = false(系统取消暂停)为true(一旦在离开游戏前暂停)

基本上gameLayer 回来时不会被暂停。看起来 iOS 在 didBecomeActive 函数之后取消暂停我的游戏。


我用下面的代码制作了一个示例项目(它都被注释了,并且是最简单的)

如果需要,可以下载here

import SpriteKit

class GameScene: SKScene {

    //Declarations
    var gameLayer = SKNode()
    var pauseLayer = SKNode()

    var checkPause = Bool() //checkPause == true -> gameLayer is paused | checkPause == false -> gameLayer is not paused

    var enemy = SKSpriteNode()

    var pauseButton = SKSpriteNode()
    var playButton = SKSpriteNode()



    //"Cage" objects in the screen
    func cageObjects(){

        //"caging" every object
        let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
        borderBody.friction = 0
        self.physicsBody = borderBody
    }

    //Setup
    func setupPauseButton(){

        //Pause
        pauseButton = SKSpriteNode (imageNamed: "pause")
        pauseButton.setScale(1)
        pauseButton.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 1.2)
    }
    func setupPlayButton(){

        //Play
        playButton = SKSpriteNode (imageNamed: "play")
        playButton.setScale(1)
        playButton.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 1.2)
    }
    func setupEnemy(){

        //Enemy
        enemy = SKSpriteNode(imageNamed: "enemy")
        enemy.position = CGPointMake(self.frame.width / 1, self.frame.height / 2)
        enemy.name = "enemy"
        enemy.setScale(0.5)

        enemy.physicsBody?.affectedByGravity = false
    }

    //Layers
    func createGameLayer(){

        //pauseButton
        setupPauseButton()
        gameLayer.addChild(pauseButton) //add pauseButton to gameLayer
    }
    func createPauseLayer(){

        //playButton
        setupPlayButton()
        pauseLayer.addChild(playButton) //add playButton to pauseLayer
    }

    //Spawn
    func spawnEnemy(){

        //Start spawning, moving and removing
        let spawnEnemy = SKAction.runBlock({
            () in

            //Spawn enemy
            self.setupEnemy()
            self.gameLayer.addChild(self.enemy)

            //Move left and remove when go off screen
            let frameWidth = CGFloat(self.frame.width)
            let moveEnemy = SKAction.moveByX(-frameWidth - 50, y: 0, duration: NSTimeInterval(0.0028 * frameWidth)) //duration: faster or slower
            let removeEnemy = SKAction.removeFromParent()

            var moveAndRemove = SKAction()
            moveAndRemove = SKAction.sequence([moveEnemy, removeEnemy])

            self.enemy.runAction(moveAndRemove)
        })

        //Spawn enemy each 2 seconds
        let spawnEnemyDuration = SKAction.repeatActionForever(SKAction.sequence([spawnEnemy, SKAction.waitForDuration(2.0)]))
        gameLayer.runAction(spawnEnemyDuration)
    }

    override func didMoveToView(view: SKView) {
        /* Setup your scene here */

        print ("didMoveToView")

        registerAppTransitionObservers()

        cageObjects()

        checkPause = false

        createGameLayer()
        createPauseLayer()

        self.addChild(gameLayer)

        spawnEnemy()
    }

    //Game states
    func pauseState(){

        //Pause game
        pauseButton.hidden = true //hide pauseButton
        gameLayer.paused = true //pause gameLayer
        checkPause = true //game is paused

        self.addChild(pauseLayer) //add pauseLayer
    }
    func playState(){

        pauseLayer.removeFromParent() //remove pauseLayer

        //Resume game
        checkPause = false //game is not paused
        gameLayer.paused = false //unpause gameLayer
        pauseButton.hidden = false //show pauseButton
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
       /* Called when a touch begins */

        //When touch buttons/screen
        for touch in touches{

            let location = touch.locationInNode(self)
            let node = nodeAtPoint(location)

            if node == pauseButton{
                pauseState()
            }
            else if node == playButton{
                playState()
            }
        }
    }



    //Functions from AppDelegate
    func registerAppTransitionObservers(){
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameScene.applicationDidBecomeActive), name: UIApplicationDidBecomeActiveNotification, object: nil)
    }

    //Just launched
    func applicationDidBecomeActive(){
        print("DidBecomeActive")

        //gameLayer unpausing problem solving attempt
        if checkPause == true{
            gameLayer.paused = true
        }
        //Pause when game is not paused and user leave the screen OR when game is launched
        else if checkPause == false{
            pauseState()
        }
    }
}

【问题讨论】:

    标签: ios swift sprite-kit


    【解决方案1】:

    现在我有了你的来源,我看到了你的问题。

    您需要保留暂停状态:

    class GameScene : SKScene
    {
        ...
        override var paused: Bool
        {
            get{
                return super.paused;
            }
            set{
                let value = self.gameLayer.paused
                super.paused = newValue;
                self.gameLayer.paused = value;
    
            }
    
        }
    }
    

    由于某种原因,场景暂停正在决定取消暂停其下的所有节点

    此外,您应该在离开应用时暂停游戏,而不是在您回来时。

    //Functions from AppDelegate
    func registerAppTransitionObservers(){
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameScene.applicationWillResign), name: UIApplicationWillResignActiveNotification, object: nil)
    }
    
    func applicationWillResign(){
        print("WillResignActive")
        pauseState()
    }
    

    你可以去掉那个 check paused 变量,那是多余的膨胀代码。

    【讨论】:

    • 顺便说一下,我基本上是复制/粘贴的,因为我(还)不知道这些 get/set 做什么,但我肯定会(现在)查找。
    • 它被称为属性,你场景中的paused变量是一个属性,因为真正的变量位于SKNode,所以本质上GameScene.paused真正是var paused: Bool { get{ return super.paused; } set{ super.paused = newValue; } }它告诉超类我们正在改变价值。我正在做的是保留 gameLayer 的暂停状态,因为在层次结构(SKNode)的某个地方,paused 属性将发送给所有子节点并取消暂停,
    • 它确实不应该这样做,但这可能是 swift 暂停和取消暂停所有节点的方式,而不是只检查父节点(祖父节点)
    • 所以在 iOS 更改 super.paused(这会更改所有 .paused 值??)值后,您将 gameLayer.paused 值更改回 true(?!)?
    • 那我明白了!!再次感谢您=)
    猜你喜欢
    • 2016-01-15
    • 2015-06-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-09
    • 1970-01-01
    • 1970-01-01
    • 2015-03-19
    • 1970-01-01
    相关资源
    最近更新 更多