Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
743 views
in Technique[技术] by (71.8m points)

ios - Swift: How to handle view controllers for my game

i have a general question about view controllers and how to handle them in a clean way when i develop a SpriteKit based game.

What i did so far:

  • Use storyboard only for defining view controllers
  • SKScene's are presented in each view controller (Home, LevelSelection, Game) by presentScene
  • in each view controller i call performSegueWithIdentifier with the identifier i defined in the storyboard between the view controllers
  • all the content i show programmatically using SKSpritenode etc. on the SKScene's
  • on the storyboard i only have view controllers with segue relations and identifiers defined
  • all the stuff i do in viewDidDisappear is because it seems to be the only way to get my SKScene deinited correctly

My problems are:

  • everytime i segue to another view, my memory raises, because the view controller is re-initialized, the old one keeps staying in the stack
  • it is not clear for me how to handle the segue's between the view controllers, on some tutorial pages i see people using the navigation controller, others are using strong references of some view controllers and using the singleton pattern for the view controller in order to decide either to init the view controller or just show it
  • my view controllers are not deiniting, i understand my home view can't because it is the initial one, but since ios is reiniting it anyways, why then not unloading it?

What is the correct way for a Swift based game using SpriteKit to handle the view controller? Below you can see my initial view controller (Home) showing an SKScene with a simple play button which calls the play() function to segue to the 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")
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Your way seems very complicated to essentially present 3 scenes. Its not what you are supposed to do for SpriteKit games, you only really need 1 view controller (GameViewController).

Load your first scene from GameViewController (e.g HomeScene) and nothing else. Create your playButton and other UI directly in HomeScene. Use SpriteKit APIs for your UI (SKLabelNodes, SKNodes, SKSpriteNodes etc).

You should never really use UIKit (UIButtons, UILabels) in SpriteKit. There are some exceptions to this, like maybe using UICollectionViews for massive level select menus, but basic UI should be done with SpriteKit APIs.

There is plenty tutorials to google on how to create sprite kit buttons, how to use SKLabelNodes etc. Xcode has a SpriteKit level editor so you can do all that visually similar to storyboards.

Than from HomeScene transition to the LevelSelect Scene and than to the GameScene and vice versa. Its super easy to do.

/// 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 {
   ....
}

I strongly recommend you scratch your storyboard and ViewController approach, and just use different SKScenes and 1 GameViewController.

Hope this helps


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...