0
\$\begingroup\$

I would like to move a joystick, and be able to go beyond the limit of the circle, and the joystick should follow the angle from the touch (the touch is moving), but it should stay on the circle. It should not go beyond the circle.

I calculate the angle with atan2, then place the joystick at a specific radius from a starting point.

The problem is that the values are positive only, so the joystick only stays in the top right quarter : when the touch goes down, the joystick goes until y=0, then it goes up, whereas the touch is still going down.

Would you know how to fix this? The joystick should follow the same angle as the touch, around a starting point :

Here is the code :

func moveJoystick(touch:CGPoint){
    let invY : Float = Float(self.view!.frame.size.height) - Float(touch.y)
    let dy : Float = Float( fabs( invY - Float(startPosFrontJoystick.y) ) )
    let dx : Float = Float ( fabs( touch.x - startPosFrontJoystick.x ) )

    //find angle when more than limit of radius //** HERE **
    let radWhenBeyondLimit = atan2(dy, dx)
    let newX : Float = cos(radWhenBeyondLimit)
    let newY : Float = sin(radWhenBeyondLimit)

    //place front joystick on circle
    let yPos : Float = Float(newY) * radiusForFront + Float(startPosFrontJoystick.y)
    let xPos : Float = Float(newX) * radiusForFront + Float(startPosFrontJoystick.x)
    frontJoystick.position = CGPoint( x:CGFloat(xPos), y:CGFloat(yPos) )
}

Thanks

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

You're only getting angles in the top-right quadrant because you're taking the absolute value of dy & dx. The sign information is important for determining what quadrant atan2 should return.

What I'd recommend instead is using vector normalization, rather than trigonometry.

dx = touch.x - startPosFrontJoystick.x;
dy = invY - startPosFrontJoystick.y;

squaredMagnitude = dx * dx + dy * dy;

if(squaredMagnitude > radiusForFront * radiusForFront)
{
    scale = radiusForFront/sqrt(squaredMagnitude);
    dx *= scale;
    dy *= scale;
}

xPos = startPosFrontJoystick.x + dx;
yPos = startPosFrontJoystick.y + dy;

For touches that are inside the radius, this puts the joystick at the touch location. For touches beyond the radius, this puts the joystick at the edge of the circle defined by that radius, in the same direction as the touch.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This method also ensures there is no issue when dx and dy are both 0. \$\endgroup\$ Commented Apr 30, 2015 at 6:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .