GameplayKit的GKStateMachine用法與例項
阿新 • • 發佈:2018-12-14
玩家進入GameScene場景中 -> 通過GKStateMachine進入到指定的遊戲狀態GKState
在GameScene場景中 -> 根據不同的邏輯呼叫GKStateMachine -> 在各個不同的遊戲狀態GKState之間進行切換
原始碼如下:
一、GameScene.swft
import SpriteKit import GameplayKit class GameScene: SKScene,SKPhysicsContactDelegate { //MARK: - StateMachine 場景中各個舞臺State lazy var stateMachine:GKStateMachine = GKStateMachine(states: [ WaitingState(scene: self), PlayState(scene: self), GameOverState(scene: self)]) override func didMove(to view: SKView) { stateMachine.enter(MenuState.self) // 進入MenuState } func restartGame(){ let newScene = GameScene(fileNamed: "GameScene")! newScene.size = CGSize(width: SCENE_WIDTH, height: SCENE_HEIGHT) newScene.anchorPoint = CGPoint(x: 0, y: 0) newScene.scaleMode = .aspectFill let transition = SKTransition.crossFade(withDuration: TimeInterval(0.5)) view?.presentScene(newScene, transition:transition) //reload GameScene 直接進入遊戲狀態; newScene.stateMachine.enter(PlayState.self) } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touch = touches.first else { return } // 當 physicsWorld.body(at: touchLocation)為nil時 // 採用atPoint 取得場景中的的精靈 let touchLocation = touch.location(in: self) ///獲得點選的位置 let nodeAtPoint = self.atPoint(touchLocation) //返回SKNode /// 判斷目前的GameScene場景舞臺是哪個state switch stateMachine.currentState { case is WaitingState: /// 判斷是否是點選了PlayButton if nodeAtPoint.name == "playButton" { stateMachine.enter(PlayState.self) } if nodeAtPoint.name == "learnTemp" { print("weird") UIApplication.shared.open(URL(string: "http://www.iFIERO.com")!, options: convertToUIApplicationOpenExternalURLOptionsKeyDictionary([:]), completionHandler: { (error) in print("jump to http://www.iFiero.com") }) } case is PlayState: //挑戰:判斷是否是點選了暫停按鈕 PauseButton // if nodeAtPoint.name == "pauseButton" { // stateMachine.enter(PauseState.self) // } break; case is GameOverState: if nodeAtPoint.name == "tapToPlay" { restartGame() } default: break; } } //MARK: - 時時更新 override func update(_ currentTime: TimeInterval) { /// 獲取時間差 if lastUpdateTimeInterval == 0 { lastUpdateTimeInterval = currentTime } dt = currentTime - lastUpdateTimeInterval lastUpdateTimeInterval = currentTime stateMachine.update(deltaTime: dt) // 呼叫所有State內的update方法 } }
二、MenuState.swft
// // MenuState.swift // Copyright © 2018 iFiero. All rights reserved. // import SpriteKit import GameplayKit class MenuState:GKState { // 必須引入場景(如:GameScene) unowned let scene:GameScene // 執行didEnter前,可在init()初始化程式碼 init(scene:SKScene){ self.scene = scene as! GameScene super.init() print("Menu State") } // 進入當前狀態時觸發 override func didEnter(from previousState: GKState?) { } // 離開當前狀態時觸發 override func willExit(to nextState: GKState) { } /* 返回一個布林值 * 該值指示當前處於該狀態的狀態機是否允許轉換到指定狀態 * 通俗點講就是:如果stateMachine(狀態機)的狀態是PlayState,那麼就從MenuState狀態轉到PlayState狀態 */ override func isValidNextState(_ stateClass: AnyClass) -> Bool { return stateClass is PlayState.Type } // Execute Update Per Frame,遊戲執行過程中的每一幀都會執行 // 但須在GameScene update內呼叫stateMachine.update() override func update(deltaTime seconds: TimeInterval) { } }
三、PlayingState.swft
import SpriteKit import GameplayKit class PlayState:GKState { unowned let scene:GameScene init(scene:SKScene){ self.scene = scene as! GameScene super.init() print("Play State") } override func didEnter(from previousState: GKState?) { } // 挑戰:建立遊戲暫停GKState狀態 PauseState.swift // return (stateClass == PauseState.self) || (stateClass == GameOverState.self) override func isValidNextState(_ stateClass: AnyClass) -> Bool { return stateClass is GameOverState.Type } // Excute Update Per Frame override func update(deltaTime seconds: TimeInterval) { // update 用於判斷球的速度是否過快,如果太快了則設定linearDamping的阻力 } }
四、GameOverState.swft
import SpriteKit
import GameplayKit
class GameOverState:GKState {
unowned let scene:GameScene
init(scene:SKScene){
self.scene = scene as! GameScene
super.init()
}
override func didEnter(from previousState: GKState?) {
print("GameOver State 遊戲結束")
}
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
return stateClass is PlayState.Type
// return (stateClass == PlayState.self) || (stateClass == MenuState.self)
}
}