#12 桌球計分板(Scoreboard)

rjjq
彼得潘的 Swift iOS / Flutter App 開發教室
9 min readJul 20, 2022

實作 Simple Table Tennis Scoreboard 這個 APP 的功能

實作步驟

  1. 先安裝 Simple Table Tennis Scoreboard 並了解這個 APP 的操作功能
  2. 開始規畫程式需要利用到的參數
var leftScoresValue = 0  // 目前左邊的分數
var rightScoresValue = 0 // 目前右邊的分數
var leftWinsValue = 0 // 目前左邊贏的局數
var rightWinsValue = 0 // 目前右邊贏的局數
var played = 0 // 目前已比完的局數
var states = Stack() // 可以回溯的 Stack 裡面可以存下每一個狀態 State (快照)
var leftName = "player 1" // 目前左邊的玩家名稱
var rightName = "player 2" // 目前右邊的玩家名稱
struct State {
let leftScoresValue: Int
let rightScoresValue: Int
let leftWinsValue: Int
let rightWinsValue: Int
let played: Int
let leftServeLabelValue: Bool
let rightServeLabelValue: Bool
let leftName: String
let rightName: String
}

3. 規畫畫面並拉出元件的IBOutlet

@IBOutlet weak var leftScores: UIButton!
@IBOutlet weak var rightScores: UIButton!
@IBOutlet weak var leftWins: UIButton!
@IBOutlet weak var rightWins: UIButton!
@IBOutlet weak var leftServeLabel: UILabel!
@IBOutlet weak var rightServeLabel: UILabel!
@IBOutlet weak var leftNameText: UITextField!
@IBOutlet weak var rightNameText: UITextField!

4. 拉出元件的IBAction,分別對應畫面上按下元件的動作

@IBAction func rewind(_ sender: Any) {
if states.peek() != nil {
let state = states.pop()

leftScoresValue = state.leftScoresValue
rightScoresValue = state.rightScoresValue
leftWinsValue = state.leftWinsValue
rightWinsValue = state.rightWinsValue
played = state.played

leftServeLabel.isHidden = state.leftServeLabelValue
rightServeLabel.isHidden = state.rightServeLabelValue

leftNameText.text = state.leftName
rightNameText.text = state.rightName

updateAllScores()
}
}
@IBAction func changeSide(_ sender: Any) {
snapshot()

swapName()
toggleServe()

(leftWinsValue, rightWinsValue) = (rightWinsValue, leftWinsValue)
(leftScoresValue, rightScoresValue) = (rightScoresValue, leftScoresValue)

updateAllScores()
}
@IBAction func reset(_ sender: Any) {
played = 0

leftServeLabel.isHidden = false
rightServeLabel.isHidden = true

leftScoresValue = 0
rightScoresValue = 0
leftWinsValue = 0
rightWinsValue = 0

leftNameText.text = leftName
rightNameText.text = rightName

updateAllScores()
}
@IBAction func addLeftScore(_ sender: Any) {
snapshot()

played += 1
leftScoresValue += 1
updateAllScores()
checkStatus()
}
@IBAction func addRightScore(_ sender: Any) {
snapshot()

played += 1
rightScoresValue += 1
updateAllScores()
checkStatus()
}
@IBAction func addLeftWin(_ sender: Any) {
snapshot()

leftWinsValue += 1
updateAllScores()
}
@IBAction func addRightWin(_ sender: Any) {
snapshot()

rightWinsValue += 1
updateAllScores()
}
@IBAction func updateLeftName(_ sender: Any) {
leftName = leftNameText.text ?? ""
}
@IBAction func updateRightName(_ sender: Any) {
rightName = rightNameText.text ?? ""
}

5. 依桌球比賽的規則,寫下每次動作需要檢查的函式 checkStatus()

func checkStatus() {
if leftScoresValue == 11 && rightScoresValue < 10 {
leftWinsValue += 1
updateAllScores()
clearScores()
return
}

if rightScoresValue == 11 && leftScoresValue < 10 {
rightWinsValue += 1
updateAllScores()
clearScores()
return
}

if (leftScoresValue < 10 && rightScoresValue < 10) ||
(leftScoresValue >= 10 && rightScoresValue < 10) ||
(leftScoresValue < 10 && rightScoresValue >= 10) {
if played % 2 == 0 {
toggleServe()
}
} else if leftScoresValue >= 10 && rightScoresValue >= 10 {

if (leftScoresValue - rightScoresValue) > 1 {
leftWinsValue += 1
updateAllScores()
clearScores()
return
}

if (rightScoresValue - leftScoresValue) > 1 {
rightWinsValue += 1
updateAllScores()
clearScores()
return
}

toggleServe()
}
}

6. 存下每次狀態的快照函式 snapshot(),以便在呼叫 rewind 時可以回復前一個狀態

func snapshot() {
let state = State(leftScoresValue: leftScoresValue, rightScoresValue: rightScoresValue, leftWinsValue: leftWinsValue, rightWinsValue: rightWinsValue, played: played, leftServeLabelValue: leftServeLabel.isHidden, rightServeLabelValue: rightServeLabel.isHidden, leftName: leftName, rightName: rightName)
states.push(state)
}

7. 設定啟始畫面為橫向顯示

override func viewDidLoad() {
super.viewDidLoad()

let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")

reset(0)
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscapeLeft
}
override var shouldAutorotate: Bool {
return true
}

成果

GitHub

參考

心得

實作出來的程式跟 Simple Table Tennis Scoreboard 已經功能幾乎都達到成了,而且還比它多了可以 寫上玩家名字 的功能,唯獨少了可了更換顏色的功能而已。整個開發都只有從原本的程式,直接復刻出來的,在開發過程中,一直不斷地增刪參數/規畫各類函式,也歡迎大家能回報問題給我。

--

--