正當山姆思考結界問題的同時,啪嗒!啪嗒!雨落了下來。
「下雨了!」山姆趕緊找尋遮蔽物,跑到了一棵大樹下。
「呼,好險。」山姆喘了一口氣,還好背包沒有濕掉。
山姆蹲下繫緊因奔跑而鬆脫的鞋帶,抬起頭時,出現了一雙眼睛緊盯著。
四目交對之下,山姆快速掃遍腦中的資料庫...
「那是...雪人?這個季節裡居然有雪人!?」
PS. 這裡是開發 iOS 手機遊戲的系列文,如果還沒看過之前
劇情文章的朋友,歡迎先點這邊回顧唷!
依照我們的遊戲設計規劃,怪物共有四種:
以下先設計好怪物的樣子,每種怪物都先分別設計兩張動畫序列圖,我們先製作一種方向 (往下走的正面),並將圖片拖移進專案中
下雨 (Rain):
暴風雨 (Storm):
閃電 (Lightning):
雪人 (Snow):
先前已經定義過主角的一些設定值,我們先將怪物的設定值也加進專案中
在之前主角篇新增的 Role
列舉,再多加入四種怪物名稱 RAIN
、STORM
、LIGHTNING
、SNOW
enum Role: String {
case NONE = "none"
case SAM = "sam"
case RAIN = "rain"
case STORM = "storm"
case LIGHTNING = "lightning"
case SNOW = "snow"
}
將怪物在迷宮中的起始位置定義在之前宣告的 gridMapping
結構 (struct) 中,方便一起管理
struct gridMapping {
...
struct rainStart {
static let x = 7
static let y = 8
}
struct stormStart {
static let x = 8
static let y = 10
}
struct lightningStart {
static let x = 6
static let y = 10
}
struct snowStart {
static let x = 9
static let y = 8
}
}
接著,請新增一個 swift 檔案,命名為 Weather.swift
點選新增檔案
選擇 Swift File -> Next
將檔案命名為 Weather,點擊 Create 按鈕,完成 .swift 檔的新增
請先 import SpriteKit
import SpriteKit
在這邊我們先定義好怪物將會進行的移動模式種類,將會在未來的章節實做移動的方式
enum Mode {
case ATTACK
case ESCAPE
case PLAY
case REBIRTH
}
將怪物類別 (Weather) 繼承角色類別 (GameCharacter)
接著加上怪物專有的一些屬性:
.ATTACK
true
接著在建構子 (init) 寫上初始化時需帶入的參數:
在 super.init 的時候帶入的參數:
"\(role.rawValue)_down"
,對應到前面加入的圖片檔名,例如 rain_down。在 GameCharacter 類別中,先前已經在 init 寫好播放動畫序列圖的程式碼,帶入圖檔名就可以產生序列動畫了ZPosition.WEATHER
,在先前的章節已經加好的怪物層級並且將 sam
主角的資料存起來
class Weather: GameCharacter {
var mode: Mode = .ATTACK
var isTrace: Bool = true
var targetGridX = 0
var targetGridY = 0
var sam: Sam?
init(gridWH: Int, startGridX: Int, startGridY: Int, role: Role, sam: Sam) {
super.init(gridWH: gridWH, startGridX: startGridX, startGridY: startGridY, imageName: "\(role.rawValue)_down", zPosition: CGFloat(ZPosition.WEATHER), role: role)
self.sam = sam
}
}
回到 GameScene,我們新增怪物的實體,將怪物新增到遊戲中
weathers
,準備儲存所有的怪物didMove
裡分別新增四個怪物:rain
、storm
、lightning
、snow
,並將它們的 node
加到 mapNode
裡面,以及將實體加進 weathers
陣列中class GameScene: SKScene {
...
var weathers: [Weather] = []
override func didMove(to view: SKView) {
...
let rain = Weather(gridWH: self.gridWH, startGridX: gridMapping.rainStart.x, startGridY: gridMapping.rainStart.y, role: .RAIN, sam: self.sam!)
self.mapNode!.addChild(rain.node)
self.weathers.append(rain)
let storm = Weather(gridWH: self.gridWH, startGridX: gridMapping.snowStart.x, startGridY: gridMapping.snowStart.y, role: .SNOW, sam: self.sam!)
self.mapNode!.addChild(storm.node)
self.weathers.append(storm)
let lightning = Weather(gridWH: self.gridWH, startGridX: gridMapping.lightningStart.x, startGridY: gridMapping.lightningStart.y, role: .LIGHTNING, sam: self.sam!)
self.mapNode!.addChild(lightning.node)
self.weathers.append(lightning)
let snow = Weather(gridWH: self.gridWH, startGridX: gridMapping.stormStart.x, startGridY: gridMapping.stormStart.y, role: .STORM, sam: self.sam!)
self.mapNode!.addChild(snow.node)
self.weathers.append(snow)
}
}
來看一下執行的成果吧!
目前我們有主角
(Sam) 及怪物
(Weather) 兩種類別了,同樣都繼承角色
(GameCharacter) 父類別,而透過繼承類別的好處是省略了一些重複的程式碼,像是初始化的地方,已經可以不用再多寫一次播放序列動畫的程式碼,並且也能依照特殊需求,再多加入特別的參數,使我們能更快速建立不同種類的角色。
聰明的各位應該也猜到了,接下來一樣可以遵循前面建立好的移動協定 Move
,明日就來帶著大家一起實作讓怪物動起來吧!