GameplayKit的GKStateMachine用法與實(shí)例

GKStateMachine

玩家進(jìn)入GameScene場景中 -> 通過GKStateMachine進(jìn)入到指定的游戲狀態(tài)GKState

在GameScene場景中 -> 根據(jù)不同的邏輯調(diào)用GKStateMachine -> 在各個(gè)不同的游戲狀態(tài)GKState之間進(jìn)行切換

源碼如下:

一、GameScene.swft

import SpriteKit
import GameplayKit

class GameScene: SKScene,SKPhysicsContactDelegate {
    
    //MARK: - StateMachine 場景中各個(gè)舞臺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) // 進(jìn)入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 直接進(jìn)入游戲狀態(tài);
        newScene.stateMachine.enter(PlayState.self)
    }

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else {
            return
        }
        // 當(dāng) physicsWorld.body(at: touchLocation)為nil時(shí)
        // 采用atPoint 取得場景中的的精靈
        let touchLocation = touch.location(in: self) ///獲得點(diǎn)擊的位置
        let nodeAtPoint = self.atPoint(touchLocation) //返回SKNode
        /// 判斷目前的GameScene場景舞臺是哪個(gè)state
        switch stateMachine.currentState {
        case is WaitingState:
            
            /// 判斷是否是點(diǎn)擊了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:
            //挑戰(zhàn):判斷是否是點(diǎn)擊了暫停按鈕 PauseButton
            //            if nodeAtPoint.name == "pauseButton" {
            //                stateMachine.enter(PauseState.self)
            //            }
            break;
        case is GameOverState:
            
            if nodeAtPoint.name == "tapToPlay" {
                restartGame()
            }
            
        default:
            break;
        }
    }

  //MARK: - 時(shí)時(shí)更新
    override func update(_ currentTime: TimeInterval) {
        /// 獲取時(shí)間差
        if lastUpdateTimeInterval == 0 {
            lastUpdateTimeInterval = currentTime
        }
        dt = currentTime - lastUpdateTimeInterval
        lastUpdateTimeInterval = currentTime
        stateMachine.update(deltaTime: dt)  // 調(diào)用所有State內(nèi)的update方法
    }

}

二石抡、MenuState.swft

//
//  MenuState.swift
//  Copyright ? 2018 iFiero. All rights reserved.
//

import SpriteKit
import GameplayKit

class MenuState:GKState {
    
    // 必須引入場景(如:GameScene)
    unowned let scene:GameScene

    // 執(zhí)行didEnter前,可在init()初始化代碼
    init(scene:SKScene){
        self.scene = scene as! GameScene
        super.init()
        print("Menu State")
    }
    // 進(jìn)入當(dāng)前狀態(tài)時(shí)觸發(fā)
    override func didEnter(from previousState: GKState?) {
        
    }
    // 離開當(dāng)前狀態(tài)時(shí)觸發(fā)
    override func willExit(to nextState: GKState) {
        
    }
    /* 返回一個(gè)布爾值
     * 該值指示當(dāng)前處于該狀態(tài)的狀態(tài)機(jī)是否允許轉(zhuǎn)換到指定狀態(tài)
     * 通俗點(diǎn)講就是:如果stateMachine(狀態(tài)機(jī))的狀態(tài)是PlayState,那么就從MenuState狀態(tài)轉(zhuǎn)到PlayState狀態(tài)
    */
    override func isValidNextState(_ stateClass: AnyClass) -> Bool {
        return stateClass is PlayState.Type
    }
    
    // Execute Update Per Frame,游戲運(yùn)行過程中的每一幀都會執(zhí)行
    // 但須在GameScene update內(nèi)調(diào)用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?) {
        
    }

    // 挑戰(zhàn):創(chuàng)建游戲暫停GKState狀態(tài) 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 用于判斷球的速度是否過快,如果太快了則設(shè)置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 游戲結(jié)束")
    }
    
    override func isValidNextState(_ stateClass: AnyClass) -> Bool {
        return stateClass is PlayState.Type
       // return (stateClass == PlayState.self) || (stateClass == MenuState.self)
    }
}

更多游戲教學(xué):http://www.iFIERO.com -- 為游戲開發(fā)深感自豪

源碼傳送門:https://github.com/apiapia/BreakOutGameVansVTutorial

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末弃揽,一起剝皮案震驚了整個(gè)濱河市睛藻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌碍侦,老刑警劉巖粱坤,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隶糕,死亡現(xiàn)場離奇詭異,居然都是意外死亡站玄,警方通過查閱死者的電腦和手機(jī)枚驻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來株旷,“玉大人再登,你說我怎么就攤上這事×榔剩” “怎么了锉矢?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長齿尽。 經(jīng)常有香客問我沽损,道長,這世上最難降的妖魔是什么循头? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任绵估,我火速辦了婚禮,結(jié)果婚禮上卡骂,老公的妹妹穿的比我還像新娘国裳。我一直安慰自己,他們只是感情好偿警,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布躏救。 她就那樣靜靜地躺著,像睡著了一般螟蒸。 火紅的嫁衣襯著肌膚如雪盒使。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天七嫌,我揣著相機(jī)與錄音少办,去河邊找鬼。 笑死诵原,一個(gè)胖子當(dāng)著我的面吹牛英妓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播绍赛,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蔓纠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了吗蚌?” 一聲冷哼從身側(cè)響起腿倚,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蚯妇,沒想到半個(gè)月后敷燎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體暂筝,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年硬贯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了焕襟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡饭豹,死狀恐怖鸵赖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情墨状,我是刑警寧澤卫漫,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站肾砂,受9級特大地震影響列赎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜镐确,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一包吝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧源葫,春花似錦诗越、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至荣堰,卻和暖如春床未,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背振坚。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工薇搁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人渡八。 一個(gè)月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓啃洋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親屎鳍。 傳聞我的和親對象是個(gè)殘疾皇子宏娄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,106評論 25 707
  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料逮壁? 從這篇文章中你...
    hw1212閱讀 12,723評論 2 59
  • This article is a record of my journey to learn Game Deve...
    蔡子聰閱讀 3,781評論 0 9
  • 1. 太陽真的好大,晃得人睜不開眼睛十饥,心都被曬慌了。 立陽今天準(zhǔn)備回趟娘家祖乳。離家三年來逗堵,她一直不敢跟家里聯(lián)系。她害...
    梨笑閱讀 929評論 28 26
  • 春來眷昆,遍山桃李花開 一瓣一瓣, 開成 開成誘惑的形狀 夏至蜒秤,數(shù)池嫩荷出水 一卷一卷, 散發(fā) 散發(fā)水鄉(xiāng)的芬芳 雨霽...
    湘水碧波閱讀 246評論 2 5