Swift with Spritekit - 带旋钮的操纵杆教程

时间:2018-05-04 15:20:06

标签: ios sprite-kit skspritenode touchesmoved

我现在正在使用Swift进行SpriteKit教程。

我用一个旋钮对操纵杆进行了编程,旋钮可以在操纵杆圈内的任何位置移动。

以下是相关的代码段:

for touch in touches {
let position = touch.location(in: joystick)

let length = sqrt(pow(position.y, 2) + pow(position.x, 2))
let angle = atan2(position.y, position.x)

if knobRadius > length {
    joystickKnob.position = position
} else {
    joystickKnob.position = CGPoint(x: cos(angle) * knobRadius, y: sin(angle) * knobRadius)
}}

以下是教程中的图片:

enter image description here

但现在我想这样做有点不同。

我希望旋钮只能在X和Y轴上像十字架一样移动 - 如上,下,左,右在轨道上。

enter image description here

我真的理解代码 - 我认为它更像是一个数学问题:)

有人能告诉我如何在铁轨上的十字架内移动旋钮吗?

2 个答案:

答案 0 :(得分:1)

因此,您希望将angle约束为.pi / 2(90度)的倍数。 atan2函数返回-.pi ... +.pi范围内的值。将它从弧度转换为四分之一转(直角)单位,舍入为整数,然后转换回弧度。

let touchAngle = atan2(position.y, position.x) // -.pi ... +.pi
let quarterTurns = touchAngle * 2 / .pi // -2 ... +2
let integralQuarterTurns = quarterTurns.rounded() // -2, -1, 0, +1, or +2
let angle = integralQuarters * .pi / 2

或者,查看abs(position.x)abs(position.y)中哪一个更大,并使用它来确定angle

let angle: CGFloat
switch abs(position.x) > abs(position.y) {
case true where position.x > 0: angle = 0
case true where position.x < 0: angle = .pi
case false where position.y > 0: angle = .pi / 2
case false where position.y < 0: angle = .pi / -2
default: angle = 0 // position == .zero so joystick is actually centered
}

答案 1 :(得分:1)

要使角度保持在十字准线上,您需要将角度四舍五入到pi / 2

的间隔

这样做,只需:

angle = (angle * 2 / CGFloat.pi).rounded() * (CGFloat.pi / 2)

下面我修改了你的代码以便更好地工作,并允许你避免分支。

我使用的是基本半径而不是旋钮半径,因此您永远不会超过基数。

for touch in touches {
    let position = touch.location(in: joystick)

    let radius = min(baseRadius,sqrt(pow(position.y, 2) + pow(position.x, 2))
    // a nicer way to get radius
    //let radius = min(baseRadius,position.distance(to:CGPoint.zero)) 
    let angle = atan2(position.y, position.x)
    if crossHairStick
    {
        angle = (angle * 2 / CGFloat.pi).rounded() * (CGFloat.pi / 2)
    }
    joystickKnob.position = CGPoint(x: cos(angle) * radius, y: sin(angle) * radius)
}

如果要将旋钮保持在底座内,请减去旋钮半径。 (这假设两个半径都是正的,否则使用半径的绝对值)

for touch in touches {
    let position = touch.location(in: joystick)

    let radius = min(baseRadius - knobRadius,sqrt(pow(position.y, 2) + pow(position.x, 2))
    let angle = atan2(position.y, position.x)
    if crossHairStick
    {
        angle = (angle * 2 / CGFloat.pi).rounded() * (CGFloat.pi / 2)
    }
    joystickKnob.position = CGPoint(x: cos(angle) * radius, y: sin(angle) * radius)
}