Swift:如何为我的游戏处理视图控制器

时间:2016-08-22 17:16:40

标签: ios swift uiviewcontroller sprite-kit

我有一个关于视图控制器的一般性问题,以及当我开发基于SpriteKit的游戏时如何以干净的方式处理它们。

到目前为止我做了什么:

  • 仅将故事板用于定义视图控制器
  • 每个视图控制器(Home,LevelSelection,Game)中的SKScene都由presentScene提供
  • 在每个视图控制器中,我使用在视图控制器之间的故事板中定义的标识符调用 performSegueWithIdentifier
  • 我在SKScene的
  • 上使用SKSpritenode等以编程方式显示的所有内容 故事板上的
  • 我只有具有segue关系和标识符定义的视图控制器
  • 我在viewDidDisappear中所做的所有事情都是因为它似乎是让我的SKScene正确消失的唯一方法

我的问题是:

  • 每当我转向另一个视图时,我的记忆就会升起,因为视图控制器被重新初始化,旧的视图控制器一直停留在堆栈中
  • 我不清楚如何处理视图控制器之间的segue,在一些教程页面上我看到人们使用导航控制器,其他人使用一些视图控制器的强引用并使用单一模式用于视图控制器命令决定是启动视图控制器还是只显示它
  • 我的视图控制器没有消失,我理解我的主视图不能,因为它是最初的视图,但是因为ios无论如何重新启动它,为什么不卸载呢?

使用SpriteKit处理视图控制器的基于Swift的游戏的正确方法是什么?下面你可以看到我的初始视图控制器(Home)显示一个带有简单播放按钮的SKScene,该按钮调用play()函数以转换到levelselection

import UIKit
import SpriteKit

class Home : UIViewController {
    private var scene : HomeScene!

    override func viewDidLoad() {
        print(self)
        super.viewDidLoad()
        self.scene = HomeScene(size: view.bounds.size)
        self.scene.scaleMode = .ResizeFill
        let skView = view as! SKView
        skView.showsFPS = true
        skView.showsNodeCount = true
        skView.ignoresSiblingOrder = true

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(play), name: Constants.Events.Home.play, object: nil)

        skView.presentScene(self.scene)
    }

    override func viewDidDisappear(animated: Bool) {
        super.viewDidDisappear(animated)
        let v = view as! SKView
        self.scene.dispose()
        v.presentScene(nil)
        NSNotificationCenter.defaultCenter().removeObserver(self)
        self.scene = nil
        self.view = nil
        print("home did disappear")
    }

    func play() {
        self.performSegueWithIdentifier("home_to_levelselection", sender: nil)
    }

    deinit {
        print("Home_VC deinit")
    }
}

2 个答案:

答案 0 :(得分:4)

从根本上呈现3个场景,你的方式似乎很复杂。它不是你应该为SpriteKit游戏做的,你只需要1个视图控制器(GameViewController)。

从GameViewController(例如HomeScene)加载你的第一个场景,没有别的。 直接在HomeScene中创建playButton和其他UI。为您的UI使用SpriteKit API(SKLabelNodes,SKNodes,SKSpriteNodes等)。

你永远不应该在SpriteKit中真正使用UIKit(UIButtons,UILabels)。这有一些例外,例如可能使用UICollectionViews进行大规模级别选择菜单,但基本UI应该使用SpriteKit API完成。

有很多关于如何创建精灵工具包按钮,如何使用SKLabelNodes等的教程.Xcode有一个SpriteKit级别编辑器,所以你可以做所有与故事板类似的视觉效果。

从HomeScene过渡到LevelSelect场景而不是GameScene,反之亦然。它非常容易做到。

/// Home Scene
class HomeScene: SKScene {

  ...

   func loadLevelSelectScene() {

       // Way 1
       // code only, no XCode/SpriteKit visual level editor used
       let scene = LevelSelectScene(size: self.size) // same size as current scene 

       // Way 2
       // with xCode/SpriteKit visual level editor
       // fileNamed is the LevelSelectScene.sks you need to create that goes with your LevelSelectScene class. 
       guard let scene = LevelSelectScene(fileNamed: "LevelSelectScene") else { return }        


       let transition = SKTransition.SomeTransitionYouLike
       view?.presentScene(scene, withTransition: transition)
    }  
}

/// Level Select Scene
class LevelSelectScene: SKScene {
   ....

     func loadGameScene() {

        // Way 1
        // code only, no XCode/SpriteKit visual level editor used
        let scene = GameScene(size: self.size) // same size as current scene 

        // Way 2
        // with xCode/SpriteKit visual level editor
        // fileNamed is the GameScene.sks you need to create that goes with your GameScene class. 
        guard let scene = GameScene(fileNamed: "GameScene") else { return }


       let transition = SKTransition.SomeTransitionYouLike
       view?.presentScene(scene, withTransition: transition)
    } 
}

/// Game Scene
class GameScene: SKScene {
   ....
}

我强烈建议你抓住你的故事板和ViewController方法,只使用不同的SKScenes和1个GameViewController。

希望这有帮助

答案 1 :(得分:0)

转到segues并在不希望将前一个视图控制器保留在堆栈中的任何位置使用Show Detail Segues。请记住,只要您返回它们,就必须在这些视图控制器中重新初始化所有内容。

如果您注意,每次看到视图时都会加载viewDidAppear,而对于您当前的设置,viewDidLoad最初只会被调用,如果您返回viewController ,只会调用viewDidAppear

当您使用segue从viewController转换出来时,prepareForSegue会被调用,但deinit()仅在您使用show detail segue(或自定义segue与特定segue)时调用关于它的属性),因为像你说的那样,视图被加载到内存中,因此可以更容易地检索它。