Swift with Spritekit - 带旋钮的操纵杆教程
Swift with Spritekit - Joystick with knob Tutorial
这些天我正在与 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)
}}
这是教程中的图片:
但现在我想做一些不同的事情。
我希望旋钮只能像十字一样在 X 轴和 Y 轴上移动 - 就像在导轨上向上、向下、向左、向右移动。
我确实理解代码 - 我认为它更像是一道数学题:)
有人能告诉我如何在 rails 上移动十字内的旋钮吗?
因此您希望将 angle
限制为 .pi / 2
的倍数(90 度)。 atan2
函数 returns 范围 -.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
}
为了保持你的角度在十字线上,你需要将角度四舍五入到 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)
}
这些天我正在与 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)
}}
这是教程中的图片:
但现在我想做一些不同的事情。
我希望旋钮只能像十字一样在 X 轴和 Y 轴上移动 - 就像在导轨上向上、向下、向左、向右移动。
我确实理解代码 - 我认为它更像是一道数学题:)
有人能告诉我如何在 rails 上移动十字内的旋钮吗?
因此您希望将 angle
限制为 .pi / 2
的倍数(90 度)。 atan2
函数 returns 范围 -.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
}
为了保持你的角度在十字线上,你需要将角度四舍五入到 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)
}