iT邦幫忙

2021 iThome 鐵人賽

DAY 22
0
Mobile Development

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

從零開始的8-bit迷宮探險【Level 22】奧義隱身術 & 時間靜止術

山姆開始發現這座森林裡還有一些奇妙的情況。
偶而時間會變得緩慢,寧靜的像是只有自己一個人在行走。
彷彿和森林處在兩種平行時空中...

今日目標

  • 在迷宮中加上香菇,主角吃到後會使怪物停止移動一段時間
  • 主角移動到能隱身的樹的位置時,可以防止怪物的攻擊

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


在迷宮中加上香菇

地圖陣列加上香菇

在先前的章節已經設定過我們地圖上要畫的圖片代號,想複習的朋友可以點這邊

  • 我們使用 + 代號代表這個位置要畫上香菇
  • GameScene.swift
let mapDraw = [
    "ccccccccpccccccci",
    "   .....e*......b",
    "aam.1ji.s.11.zy.b",
    "  d.3gh....1.wx.b",
    "jcl.....ji.1....b",
    "d*...11.gh...rt.b",
    "d.11.nm....2....b",
    "d..1.kl.22.1.naah",
    "ot...       .b   ",
    "d..1.jcu vci.b   ",
    "d.12.d     b.kccc",
    "d+...gaaaaah.    ",
    "gaam.       .11.n",
    "   d.rt.1#.q....b",
    "   d....21.e.ji.b",
    "cccl.ji....e.gh.b",
    "    .gh.13.s....b",
    "aaam....1....21.b",
    "   d...23.rt.1..b",
    "   d.1.........3b",
    "jccl.1.rft.3.1.1b",
    "d*.............*b",
    "gaaaaaaaaaaaaaaah",
]

準備香菇圖片

請準備好圖片,並且拖拉進專案中
https://imgur.com/f7DWyiz.png

加上香菇

  • 先宣告香菇陣列的變數 mushrooms,雖然目前遊戲只設定有一個香菇,但用陣列的好處是未來還可以再擴充
  • 在先前的 drawMap 方法裡,再加上 "+" 的 case
  • 新增收集物類別 Collection 的實體 mushroom,將需要的參數帶入
  • mapNode 裡加入香菇的 node
  • 將香菇的實體存在 mushrooms 陣列中
  • GameScene.swift
class GameScene: SKScene {
    ...
    var mushrooms: [Collection] = []
    ...
    func drawMap() {
        for i in 0..<gridYCount {
            let mapRowArr = Array(mapDraw[i]);
            for j in 0..<gridXCount {
                let mapKeys = wallMapping.keys
                switch mapRowArr[j] {
                ...
                case "+":
                    let mushroom = Collection(gridWH: self.gridWH, gridX: j, gridY: i, imageName: "mushroom")
                    self.mapNode!.addChild(mushroom.node);
                    self.mushrooms.append(mushroom)
                default:
                    break
                }
            }
        }
    } 
}

執行結果

畫面上出現一個香菇了!
https://imgur.com/VWjgqeG.gif


收集到香菇後,時間暫停

  • update 方法裡,再加上主角跟香菇之間的位置判斷,這邊的方式與先前的其他收集物判斷方式一樣,當香菇還沒有被收集、並且位置跟主角一樣時,做以下動作:
    • 將香菇設定為已收集 setGotten(isGotten: true)
    • 將所有怪物都設定為不能移動 setCanMove(isCanMove: false)
    • 新增 stopWeatherTimer,設定 10 秒過後執行 stopWeatherAction
  • stopWeatherAction
    • 讓所有怪物恢復成可以移動 setCanMove(isCanMove: true)
    • 讓所有怪物開始自動移動 startMove(direction: .NONE)
  • stopTimer 方法中,將 stopWeatherTimer 停止
  • GameScene.swift
class GameScene: SKScene {
    ...
    var stopWeatherTimer: Timer? = nil
    ...
    override func update(_ currentTime: TimeInterval) {
        ...
        for mushroom in self.mushrooms where !mushroom.isGotten && mushroom.gridX == sam.gridX && mushroom.gridY == sam.gridY {
            mushroom.setGotten(isGotten: true)
            for weather in self.weathers {
                weather.setCanMove(isCanMove: false)
            }
            self.stopWeatherTimer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(stopWeatherAction), userInfo: nil, repeats: false)
        }
    }
    @objc func stopWeatherAction() {
        self.stopWeatherTimer = nil
        for weather in self.weathers {
            weather.setCanMove(isCanMove: true)
            weather.startMove(direction: .NONE)
        }
    }
    func stopTimer() {
        if let stopWeatherTimer = self.stopWeatherTimer {
            stopWeatherTimer.invalidate()
            self.stopWeatherTimer = nil
        }
    }
}

來看一下成果吧

吃到香菇後,怪物們暫停了 10 秒鐘,之後又恢服原樣
https://imgur.com/JWdyaph.gif


能隱身的樹

我們在先前製作迷宮的章節已經加上能隱身的樹 (紫色的樹),現在我們來製作它的效果吧!

調整層級

  • 首先,先回憶一下之前已經加好的層級,紫色的樹是在最上方,由於他不屬於真正的牆壁,所以主角跟怪物都可以移動到這一格的位置
  • GameScene.swift
enum ZPosition {
    static let HIDE = -1
    static let COLLECTION = 1
    static let SAM = 2
    static let WEATHER = 3
    static let PURPLE_TREE = 4
}
  • 回到之前畫地圖的方法,加上判斷字元為 #,則將 zPosition 調整為 ZPosition.PURPLE_TREE
  • GameScene.swift
class GameScene: SKScene {
    func drawMap() {
        for i in 0..<gridYCount {
            let mapRowArr = Array(mapDraw[i]);
            for j in 0..<gridXCount {
                let mapKeys = wallMapping.keys
                switch mapRowArr[j] {
                case _ where mapKeys.contains(mapRowArr[j]):
                    let spriteItem = SKSpriteNode(imageNamed: wallMapping[mapRowArr[j]]!);
                    spriteItem.anchorPoint = CGPoint(x: 0.5, y: 0.5);
                    spriteItem.size.width = CGFloat(gridWH);
                    spriteItem.size.height = CGFloat(gridWH);
                    spriteItem.position = CGPoint(x: gridWH * j + (gridWH/2), y: -gridWH * i - (gridWH/2));
                    if mapRowArr[j] == "#" {
                        spriteItem.zPosition = CGFloat(ZPosition.PURPLE_TREE)
                    }
                    self.mapNode!.addChild(spriteItem)
                ...
                }
            }
        }
    }
}

讓主角與怪物在這格碰觸時,沒有反應

  • 定義紫色的樹的格子位置
  • GameScene.swift
struct gridMapping {
    ...
    struct purpleTree {
        static let x = 9
        static let y = 13
    }
}
  • 將偵測怪物與主角碰觸的判斷,再加上主角不位於紫色的樹的位置時,才做後續的動作
    • 判斷 gridMapping.purpleTree.x 不等於主角的格子 x 且 gridMapping.purpleTree.y 不等於主角的格子 y
  • GameScene.swift
class GameScene: SKScene {
    override func update(_ currentTime: TimeInterval) {
        ...
        for weather in self.weathers where (weather.gridX == sam.gridX && abs(weather.node.position.y - sam.node.position.y) <= CGFloat(self.gridWH + 6) || weather.gridY == sam.gridY && abs(weather.node.position.x - sam.node.position.x) <= CGFloat(self.gridWH + 6)) && (gridMapping.purpleTree.x != sam.gridX && gridMapping.purpleTree.y != sam.gridY)
        {
            ...
        }
    }
}

執行結果

https://imgur.com/EJYTik2.gif


今日小結

大家可以發揮個人創意,新增更多種類的道具在遊戲中喔!/images/emoticon/emoticon69.gif


上一篇
從零開始的8-bit迷宮探險【Level 21】進擊的主角!暴風雨來吶,你坐啊!
下一篇
從零開始的8-bit迷宮探險【Level 23】長老,這個水晶值多少錢?
系列文
從零開始的8-bit迷宮探險!Swift SpriteKit 遊戲開發實戰30

尚未有邦友留言

立即登入留言