數字方塊合併遊戲 — Number Merge App

ytchao
海大 SwiftUI iOS / Flutter App 程式設計
6 min readApr 24, 2022

功能需求

  • 5 * 5 的格子。
  • 以 SwiftUI 製作
  • 畫面下方顯示下一個擺放的物品,數字可能有 1,2,3 三種。
  • 數字一樣的東西放在一起時會合併成新的東西,1 + 1 變成 2,2 + 2 會變成 3,3 + 3 會變成 4,其他以此類推
  • 多重合併。
  • 每合併一次會加一分。
  • 格子全滿時 Game Over。
func laydown(_ idx: Int, item: Grid) -> Bool {
// 空白處才可以置放方塊
if self.property.board[idx].number != 0 {
// 若未能置放方塊,則不更改下一個方塊的內容
return false
}
// 置放後需等待動畫效果,完成動畫前點按棋盤無反應
self.property.disable = true
// 置放所需方塊
self.property.board[idx] = item

// 如果置放的方塊上數字小於最大數字 6,則判斷是否需要合併方塊
if item.number < Grid.typeNumber {
self.judge(idx)
}
// 否則此次置放結束,棋盤恢復反應
else {
self.property.disable = false
}

// 若成功置放方塊,則更改下一個方塊的內容
return true
}
=========================
func judge(_ idx: Int) {
var toMerge = false // 判斷是否需要合併方塊
var target = idx // 計算相鄰方塊的陣列索引
var mergeList = [Int]() // 記錄需要合併的方塊的陣列索引
let number = self.property.board[idx].number // 此次點按目標的方塊數字
// 判斷相鄰方塊的陣列索引是否合理
func isValid(dir: Game.DIRECTION, idx: Int, target: Int) -> Bool {
// 相鄰方塊須在棋盤內
if target < 0 || target >= Game.size {
return false
}

// 因使用一維陣列,需額外判斷左相鄰及右相鄰
// 棋盤中左上角為 0, 右下角為 24
// 若計算後相鄰方塊確實為左相鄰或右相鄰,則其與被點按方塊所在 column 相差恰為 1
if (dir == .LEFT || dir == .RIGHT)
&& abs(idx % Game.column - target % Game.column) != 1 {
return false
}

return true
}
// 對上下左右四個方向計算
for (i, dir) in Game.DIRECTION.allCases.enumerated() {
// 相鄰方塊的陣列索引
target = idx + dir.rawValue
// 若索引合法且方塊數字與被點按方塊相同
if isValid(dir: dir, idx: idx, target: target)
&& self.property.board[target].number == number {
// 則判斷此次需要進行方塊合併
toMerge = true
// 更改需被合併的相鄰方塊的 offset,用於製作合併動畫
self.property.offset[target] = Game.offsetType[i]
// 記錄需被合併的相鄰方塊的陣列索引,用於還原 offset
mergeList.append(target)
}
}
// 若判斷需要進行合併
if toMerge {
// 分數加一分
self.property.score += 1
// 合併動畫結束後
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
// 被合併的相鄰方塊變為空格,offset 還原
for target in mergeList {
self.property.board[target] = Grid()
self.property.offset[target] = CGSize.zero
}
// 將合併後的方塊變為空格
// 原位放上數字加一後的方塊,laydown 中會再判斷是否需要 judge,可達成多重合併
self.property.board[idx] = Grid()
self.laydown(idx, item: Grid(number + 1))
}
}
// 如果不需要合併
else {
// 此次置放結束,棋盤恢復反應
self.property.disable = false
// 如果棋盤滿了,遊戲結束
if self.property.isFull() {
self.property.gameOver = true
}
}
}
  • 記錄玩家的最高分。

--

--