iOS桌球計分板

在接到這個任務之前,其實根本不懂桌球,也不知道怎麼記分,印象中唸書時體育課有玩過,在那個熱血的年代….

好像歪樓了…. 囧“

先秀一下成果:

研究一下主要的任務目標:

  • 每局 11 分制,輸流發球,發球時每 2 球輪替一次。
  • 點選數字會增加分數,上方的小數字代表雙方獲勝的局數,下方的大數字代表目前局數的比分。
  • 目前的發球方下方顯示 Serve。
  • 點選 Reset 會將比數清空,大數字和小數字都清成 0。
  • 其中一方達到 11 分時獲勝,上方獲勝的局數更新。
  • 點選 Change Side 將讓左右的分數互換。
  • 10 比 10 平手後(deuce),發球改成每 1 球輪替一次,先多得 2 分的獲勝。

次要目標:更換背景圖片、可輸入選手名的欄位、rewind倒帶功能…等下一版改寫再來研究了~(拖稿)

先拉出畫面的必要元件,Label和按鈕:

然後想一下怎麼取名字,以目視計分板左側為a,右側為b,分數就是score,贏的局數稱為best:

    var aBest: Int = 0

var bBest: Int = 0

var aScore: Int = 0

var bScore: Int = 0

var tempBest: Int = 0

var tempScore: Int = 0

var serveIndex: Int = 2 //開啟app預設左側先serve設2 右設4

任務列表中有一個左右互換的功能,先設一個temp暫存用,後面會說明。

serveIndex是發球的總次數,每發一次球就+1

IBOutlet的部分拉一拉,原先在score的部分是用Button,可是後來遇到要讓Button的action按的時候title也跟著+1,字就會變小。查詢了網路上前輩分享的文件,要解決這問題好像要另外寫程式,感覺有點麻煩….

<當時原文找不到了QQ 有遇到再候補….>

只好用最土砲的方式,在兩個scroe和兩個best上另外做Label顯示分數,Button用透明的浮貼在Label上,這樣以後要分開來也可以。

重頭戲是目標功能,要寫function:

//reset 這部分不用多說,就是設為0

func resetBest() {
aBest=0
bBest=0
aBestLabel.text = "\(aBest)"
bBestLabel.text = "\(bBest)"

}

func resetScore() {
aScore=0
bScore=0
aScoreLabel.text = "\(aScore)"
bScoreLabel.text = "\(bScore)"
}

//changeSide

兩邊互換,因此需要有一個暫存空間temp,有玩大風吹的感覺。

func changeSide() {
tempBest = bBest
bBest = aBest
aBest = tempBest
tempScore = bScore
bScore = aScore
aScore = tempScore
aBestLabel.text = "\(aBest)"
bBestLabel.text = "\(bBest)"
aScoreLabel.text = "\(aScore)"
bScoreLabel.text = "\(bScore)"
serveIndex += 2
whoServe()

}

兩邊互換時,serve也是互換,因此serveIndex+2,後面會說明

//誰發球?

研究了一下serve規則,發現不論是誰得分,反正就是一邊輪兩次,由此找出它的規律。

關於duece模式,再科普一下,我的理解是,當兩邊選手得分進入10:10,serve改為一次一輪。簡單來說用邏輯判斷就是a≥10 && b≥10的條件成立

func whoServe() {
if aScore >= 10 && bScore >= 10 { //duece ?
if serveIndex % 2 == 0 {
aServeLabel.isHidden = true
bServeLabel.isHidden = false
}else {
aServeLabel.isHidden = false
bServeLabel.isHidden = true
}

} else {

if serveIndex % 4 <= 1 {
aServeLabel.isHidden = true
bServeLabel.isHidden = false
}else {
aServeLabel.isHidden = false
bServeLabel.isHidden = true
}
}
}

如果不成立,就走else。也就是一般的模式兩次一輪

用serveIndex % 4 來判斷誰serve,如果是duece就% 2

剛剛提到的changeSide,可以比照duece來解決,反正按下去就兩邊互換,意思一樣。

再補充一下duece,它的邏輯是after 10:10,看誰先能領先2分即獲勝,但是如果一直沒有任一方能領先到兩分的差距呢?

//鹿死誰手?寫在button裏

整個比賽的進程就是用button來控制,誰發球?誰得分?都要按這個score button。這裡的邏輯也分為兩個計分模式,duece or not ?

 @IBAction func pressaScore(_ sender: UIButton) {
serveIndex += 1 //開球+1
whoServe() //先判斷誰發球
if aScore >= 10 && bScore >= 10 { //是否duece?
aScore += 1
aScoreLabel.text = "\(aScore)"
if abs(aScore - bScore) == 2 { //如果雙方分數差>2 則結束比賽
endAlarm()
}
} else {

if aScore < 11 {
aScore += 1
aScoreLabel.text = "\(aScore)"
}
if aScore == 11 { //非duece模式,看誰先得11分,則結束比賽
aBest += 1
aBestLabel.text = "\(aBest)"
endAlarm()
}
}
}

//勝負已分

這裡寫一個當勝負條件符合時要發生的事,達到符合邏輯的比數,則會自動跳出alarm,結束比賽:

    func endAlarm() {
let controller = UIAlertController(title: "鹿死誰手", message: "勝負已分", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default) { _ in
self.resetScore() //要放這裡
}
controller.addAction(okAction)
present(controller, animated: true)
// self.resetScore() 不能放這裡!
}

同時用這顆alarm的按鈕來reset score繼續下一局。

要放在UIAlarmAction{ }裏面,如果放在endAlarm{ }下面,跳出alarm時會看不到分數。

以上

--

--