iT邦幫忙

2021 iThome 鐵人賽

DAY 18
0
Mobile Development

從零開始的8-bit迷宮探險!Swift SpriteKit 遊戲開發實戰系列 第 18

從零開始的8-bit迷宮探險【Level 18】為什麼他們開始亂跑?捉摸不定的怪物移動模式

「誒,好累喔。」
「天氣這麼好,要不要去玩水啊?」喜歡玩耍的 Snow 提議著。
忘記要趕走山姆的使命感,四個可愛的反派角色跑走了!?
黑森林的天氣,又漸漸晴朗起來。

今日目標

  • 新增不同的移動模式:玩耍模式 (不再以主角為追蹤目標)
  • 遊戲開始後,取得一個隨機時間,啟動玩耍模式

PS. 這裡是開發 iOS 手機遊戲的系列文,如果還沒看過之前 劇情 文章的朋友,歡迎先點這邊回顧唷!


設定模式

  • 新增 setMode 方法:
    • 可讓外部呼叫並帶入 mode 參數,調整該怪物當前的移動模式
    • 呼叫 updateMode 方法,更新當前模式設定
    • 呼叫 playAnimation,設定當前模式下的圖片序列圖動畫 (目前玩耍模式不會改變怪物樣貌)
  • 調整 updateMode 方法:
    • 新增 .PLAY case,設定他的目標點為 gridMapping.lakeCorner.xgridMapping.lakeCorner.y
    • 移動速度:這邊我們也可以讓不同模式的移動速度有些差異,分別在 .ATTACK.PLAY case 中設定 moveInterval 的值,讓攻擊時的移動速度較快,而玩耍時的移動速度較慢
  • Weather.swift
class Weather: GameCharacter, Move {
    ...
    func setMode(mode: Mode) {
        self.mode = mode
        self.updateMode()
        self.playAnimation(imageName: "\(self.mode.getImage(role: self.role))_\(self.direction.rawValue)", num: 2)
    }
    func updateMode() {
        switch mode {
        case .ATTACK:
            ...
            self.moveInterval = 0.3
        case .PLAY:
            self.setTarget(targetX: gridMapping.lakeCorner.x, targetY: gridMapping.lakeCorner.y)
            self.moveInterval = 0.4
        default:
            break
        }
    }
}

Timer

設定在隨機的一段時間後,讓怪物們進入玩耍模式,玩耍模式維持 10 秒後,再讓怪物回復到攻擊模式

啟動 Timer,進入玩耍模式

  • 使用 Int.random(in:) 隨機取得 10 到 50 的整數
  • 使用 scheduledTimer 新增一個 Timer:
    • timeInterval:帶入我們取得的隨機秒數
    • selector:帶入要執行的方法 attackToPlayModeAction,將會在 timeInterval 秒數後執行
    • repeats:false 不重複執行
  • 玩耍模式 attackToPlayModeAction
    • 將所有的怪物模式設定為玩耍模式 setMode(mode: .PLAY)

啟動 Timer,回到攻擊模式

  • attackToPlayModeAction
    • 設定另一個 Timer playModeTimer,讓玩耍模式維持 10 秒後,執行回到攻擊模式方法 palyToAttackModeAction
  • 回到攻擊模式 palyToAttackModeAction
    • 將所有的怪物模式設定為攻擊模式 setMode(mode: .ATTACK)

停止 Timer

啟動了 Timer 後,為了避免 Timer 還沒結束時就離開遊戲畫面,而 Timer 還在繼續倒數的問題,我們在離開場景時要停止 Timer

  • 新增 stopTimer 方法,使用 invalidate() 停止 timer
  • 在場景將要被移除時 willMove(from: SKView),呼叫 stopTimer
  • GameScene.swift
class GameScene: SKScene {
    ...
    var randomTimer: Timer? = nil
    var playModeTimer: Timer? = nil
    
    override func didMove(to view: SKView) {
        ...
        let randomTime = Int.random(in: 10...50)
        self.randomTimer = Timer.scheduledTimer(timeInterval: TimeInterval(randomTime), target: self, selector: #selector(attackToPlayModeAction), userInfo: nil, repeats: false)
    }
    ...
    // 攻擊->玩耍
    @objc func attackToPlayModeAction() {
        print("玩耍中")
        self.randomTimer = nil
        self.playModeTimer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(palyToAttackModeAction), userInfo: nil, repeats: false)
        for weather in self.weathers {
            if weather.mode == .ATTACK {
                weather.setMode(mode: .PLAY)
            }
        }
    }
    
    // 玩耍->攻擊
    @objc func palyToAttackModeAction() {
        print("不玩了")
        self.playModeTimer = nil
        for weather in self.weathers {
            if weather.mode == .PLAY {
                weather.setMode(mode: .ATTACK)
            }
        }
    }
    
    func stopTimer() {
        if let randomTimer = self.randomTimer {
            randomTimer.invalidate()
            self.randomTimer = nil
        }
        if let playModeTimer = self.playModeTimer {
            playModeTimer.invalidate()
            self.playModeTimer = nil
        }
    }
    
    override func willMove(from: SKView) {
        self.stopTimer()
    }
}

執行結果

可以觀察到,經過一段時間後,怪物突然移動變得較慢,且目標點變成湖邊,並且漸漸移動過去,10秒後又回到攻擊模式,藍色的 Rain 又開始往主角追擊

https://imgur.com/ut7WQf7.gif


今日小結

怪物追擊主角的移動路徑跟模式,到今天就會稍微告一個段落囉!
大家可以再自由發揮,加入其他有趣的模式讓移動路徑更難以捉摸。
之後會有專門講解主角反擊怪物的章節,請敬請期待~


參考來源:
random(in:)
scheduledTimer


上一篇
從零開始的8-bit迷宮探險【Level 17】稻草人也想要智慧大腦,給怪物一點靈魂跟一點點個性
下一篇
從零開始的8-bit迷宮探險【Level 19】這個相遇我等了一輩子了-偵測主角與怪物接觸
系列文
從零開始的8-bit迷宮探險!Swift SpriteKit 遊戲開發實戰30

尚未有邦友留言

立即登入留言