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時會看不到分數。
以上