本文適合SpriteKit初心者 原始碼:https://github.com/jamesdouble/JDGamePaddle
虛擬搖桿
16年,MOBA手遊市場打得可火熱(這裡我們不幫任何遊戲背書),擼瑟如我也是在16年開始玩SpriteKit,也就是蘋果自制的2D遊戲框架。 有玩過MOBA手遊的,一定十分熟悉遊戲裡我們是如何移動主人公的吧?沒玩過的......我們們不囉唆,先上圖。
這樣想不起來的也想起來了唄,因為SpriteKit本身並沒有提供像搖桿這樣元件(有提供反而奇怪),為了以防朋友們採坑(也沒有很多坑),我就寫了一個簡易的搖桿Lib,SKScene,SKView(SpriteKit的UIView), UIView皆可直接加上。
簡單的出發
一開始若把問題想得太複雜,那歪路肯定會走的特別的多,我們就照著上面的圖來刻吧,外面一個圓圈,嗯,裡面一個小圓.....好,結束了 ,就從拉出兩個圓來出發吧!!
元件1:SKShapeNode
For SpriteKit初心者: UIKit裡每個元件幾乎都是UIView的子類別,而SpriteKit裡的每個元件幾乎都是SKNode的子類別。
那SKShapeNode又是什麼?它是SKNode的子類別,若是你不是要用圖片來初始化一個物件而是純幾何形狀或是線條的話,使用它來做Node會快上許多,看它的建構值就能知道,真的很“幾何”。
來吧!第一步!兩個圓形!
MovingPing = SKShapeNode(circleOfRadius: paddleSize.width * 0.18)
MovingPing?.fillColor = UIColor.black //內圓黑色實心
PaddleBorder = SKShapeNode(circleOfRadius: paddleSize.width * 0.5 )
PaddleBorder?.fillColor = UIColor.clear //外圓中間空心
PaddleBorder?.strokeColor = UIColor.black
複製程式碼
元件2:點選、滑動
Hmm.... We almost here, right? 不過現在你不管怎麼撥弄它,它都不會移動的,在SpriteKit裡常做的處理點選方式是實作覆寫UIResponder大家常見的Method。
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
touching = true
let position = touch.location(in: self)
if((PaddleBorder!.contains(position))) //若是手指還在邊界內
{
MovingPing?.position = touch.location(in: self) //內圓移到手指位置
}
didMove()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
let postion = touch.location(in: self)
if((PaddleBorder!.contains(postion)))
{
MovingPing?.position = postion
}
/*
略
*/
}
複製程式碼
結束了嗎?執行起來試試吧。看起來聽生硬的對吧,若是有MOBA手遊只做到這邊,主人公一定是腳抽了筋。會發生這樣的杯具是在touchesMoved只判斷是否手指在外圈內,而忽略了若是使用者從內圈滑到外圈的情況。
讓我們把上面那段註解換成 else{
movingpaddleSmoothly(position: postion)
}
//算出邊界外手指跟中心連成一線後,跟邊界的交點。
func movingpaddleSmoothly(position:CGPoint)
{
let centerPoint = PaddleBorder!.position
let radius = self.frame.width * 0.5
var distance:CGFloat = 0
let diffx:CGFloat = (centerPoint.x - position.x) * (centerPoint.x - position.x)
let diffy:CGFloat = (centerPoint.y - position.y) * (centerPoint.y - position.y)
distance = sqrt(diffx + diffy)
let ratio:CGFloat = radius/distance
let newPostition:CGPoint = CGPoint(x: position.x * ratio, y: position.y * ratio)
MovingPing?.position = newPostition
}
複製程式碼
最後我們再每次移動搖桿時,回傳一個經過正規化的CGVector出去給委任,以便使用者能隨著滑動搖桿,做出適當的迴應。