「呀!呀!」一隻烏鴉飛了過去,因為視線不明,讓移動的黑影更加引人遐想。
在這諾大的森林裡,就只有山姆一個人,登山杖插進土裡的聲音清楚迴盪在空氣中。
山姆調整了一下背包,深深吸了一口氣,再次提起腳步前進。
PS. 這裡是開發 iOS 手機遊戲的系列文,如果還沒看過之前
劇情文章的朋友,歡迎先點這邊回顧唷!
我們新增一個共用的角色類別,可以讓主角繼承,未來也能讓怪物繼承。
首先新增一個 swift 檔案,將程式碼區開,比較方便管理。
首先點選新增檔案
選擇 Swift File -> Next
將檔案命名為 GameCharacter,點擊 Create 按鈕,完成 .swift 檔的新增
記得萬事先 import
import SpriteKit
先建立一個列舉,加入 NONE
及主角山姆 SAM
enum Role: String {
case NONE = "none"
case SAM = "sam"
}
我們希望能記錄角色的一些屬性:
我們在建構子 (init) 寫上初始化時需帶入的參數:
在建構子中,儲存帶入的參數值,並且新增一個 SKSpriteNode
,將定位點 (anchorPoint)、尺寸 (size)、位置 (position)、層級 (zPosition) 都設定好。
class GameCharacter {
var role: Role = .NONE
var node: SKSpriteNode
var gridWH: Int
var gridX: Int
var gridY: Int
var startGridX: Int
var startGridY: Int
var imageName: String
init(gridWH: Int, startGridX: Int, startGridY: Int, imageName: String, zPosition: CGFloat, role: Role) {
self.role = role
self.gridWH = gridWH
self.gridX = startGridX
self.gridY = startGridY
self.startGridX = startGridX
self.startGridY = startGridY
self.imageName = imageName
self.node = SKSpriteNode(imageNamed: imageName)
self.node.anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.node.size.width = CGFloat(gridWH)
self.node.size.height = CGFloat(gridWH)
self.node.position = CGPoint(x: gridWH * startGridX + (gridWH/2), y: -gridWH * startGridY - (gridWH/2))
self.node.zPosition = zPosition
}
}
我們的遊戲畫面就像是個畫布層層堆疊,放在上面的物體都是有層級的,數字越高的在越上方
而 SpriteKit 會幫我們預設定為:0.0
先試想遊戲會出現幾種交疊在一起的物體:收集品、主角、壞天氣怪物、能隱身的樹,分別幫他們先定義好正確的層級。其中一種是隱藏 (-1),當設定為此種類型,則會有消失在畫面中的效果。
請先定義好 ZPosition
enum ZPosition {
static let HIDE = -1
static let COLLECTION = 1
static let SAM = 2
static let WEATHER = 3
static let PURPLE_TREE = 4
}
新增一個主角類別檔案:Sam.swift,繼承 GameCharacter
類別。
imageName 帶入主角的圖檔名稱 sam
zPosition 帶入 ZPosition.SAM
role 帶入 .SAM
(因為父類別已經有定義 role 的型態為 Role,所以可將 Role.SAM 省略為 .SAM)
import SpriteKit
class Sam: GameCharacter {
init(gridWH: Int, startGridX: Int, startGridY: Int) {
super.init(gridWH: gridWH, startGridX: startGridX, startGridY: startGridY, imageName: "sam", zPosition: CGFloat(ZPosition.SAM), role: .SAM)
}
}
考慮到未來會有不同種類的角色,分別會有不同的起始點 (這邊提的起始點是指位於迷宮格子中的位置),可以先新增一個結構 (struct),定義不同種類位置的 (x, y) 常數值,方便未來管理。請先新增一個 samStart
的 x 及 y 值。
struct gridMapping {
struct samStart {
static let x = 1
static let y = 1
}
}
在 didMove 中,創建一個 Sam 類別的實體,並將起始位置帶入。
接著將實體的 node 添加到 mapNode 中。
class GameScene: SKScene {
...
var sam: Sam?
override func didMove(to view: SKView) {
...
self.sam = Sam(gridWH: self.gridWH, startGridX: gridMapping.samStart.x, startGridY: gridMapping.samStart.y)
self.mapNode!.addChild(self.sam!.node)
}
}
主角出現在畫面中了
如果只有一張貼圖,遊戲會比較不生動,加入動畫可以提升精緻度。
我們試著製作兩張主角手部舉起登山杖的連續圖,面朝下的方向,分別取名為:
回到角色類別,找到設定圖片的地方,將原本建立 SKSpriteNode 的地方做調整。
SKTexture
新增兩張序列圖SKAction.animate
建立圖片序列動畫,timePerFrame
代表每張圖片的持續時間(秒)SKAction.repeatForever
,帶入原本的圖片序列動畫,讓它重複播放.run
,讓它播放動畫// self.node = SKSpriteNode(imageNamed: imageName)
let sequence1 = SKTexture(imageNamed: imageName + "_1")
let sequence2 = SKTexture(imageNamed: imageName + "_2")
let ani = SKAction.animate(with: [sequence1, sequence2], timePerFrame: 0.4)
let aniRepeat = SKAction.repeatForever(ani)
self.node = SKSpriteNode(texture: sequence1)
self.node.run(aniRepeat, withKey: "sequence")
將圖檔名稱改為 sam_down
super.init(gridWH: gridWH, startGridX: startGridX, startGridY: startGridY, imageName: "sam_down", zPosition: CGFloat(ZPosition.SAM), role: .SAM)
執行後就可以看到主角有動畫了!
我們發現主角在地圖中看起來似乎有點小,想要將角色圖片調整大一點。
因為角色的 anchorPoint 是定在 (0.5, 0.5),因此我們可以直接將 node 的 size 調大,不會影響到定位。
將寬高各加上 13 微調
self.node.size.width = CGFloat(gridWH + 13)
self.node.size.height = CGFloat(gridWH + 13)
主角在畫面上能顯示序列動畫囉!
明日來控制主角移動吧!