Чтобы сохранить угол на перекрестии, вам нужно округлить угол до интервала пи / 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)
}