Rotate Towards Point

Ya, fair point. That line is all wrong anyway as I’m comparing an angle to the (non-normalised) sine of an angle! ::slight_smile:

Use the angle of the direction the character is facing (a1) and atan2 to get the angle of the vector from the character to the target (a2). Adjust the angle (a2 - a1) using:

while(angle <= -180.0) angle += 360.0;
while(angle > 180.0) angle -= 360.0;

(Use radians in the real code.)

if(Math.abs(angle) < turn)
{
  character.setAngle(a2);
}
else if(angle > 0)
{
  character.setAngle(a1 - turn);
}
else // No need to test for -180 deg.
{
  character.setAngle(a1 + turn);
}

If you do it correctly, I don’t even think the whiles are needed.


double angle = Math.toDegrees(Math.atan2(target.x - this.x, target.y - this.y));

That will return an angle between -180 and 180 with the angle starting on the II quadrant along the X-axis. You just have to add 180 to it and everything will be resolved to an angle resulting in a positive number. I just did it right now. :smiley:

You could get 180 - -180 = 360 or -180 - 180 = -360 or anything in between. You don’t need while loops either, but it gets the point across for the general case.

Using a complex number/vectors instead you have: the sign of the cross product (orthogonal direction) tells you which direction is the minimal angular path. A constant angular velocity (for fixed simulation timesteps) is a fixed complex number. Multiple the current rotation (identical to unit direction vector) performs the rotation. Re cross product and if the sign has changed you have overshot the target direction…set to target. No trig, inverse trig or any explicit angles.

If you do that, you will continuously overshoot the target when the angle between them is less than the angular velocity. I tried to solve the problem of all three cases of the if, else if, else block without using only multiplications. You could avoid trig if you stored cos(maxTurn) (because it is constant.) I could not do away with both square roots and inverse trig functions.

Who are you talking to? I note that if the sign changes you’ve overshot.

I’m really confused, sorry, but this is maths all beyond my ability. Could anybody clarify how to actually practically implement this, ideally with minimal advanced vector manipulation (advanced for me)! Thanks

The simplest solution (in terms of being easy to understand mathematically) is probably this - just a small modification to your previous code:


// NOTE: atan2 takes y first, then x!
playerAngle = (float) Math.toDegrees(Math.atan2(player.y - y, player.x - x));
turnAngle = playerAngle - rotation;

// Bound range of turn between -180 and +180 degrees
// Can also use while's instead of if's, if turnAngle ends up outside range of -360 to +360
if (turnAngle < -180) turnAngle += 360;
if (turnAngle > 180) turnAngle -= 360;

turnSpeed = 2;
						
if(Math.abs(turnAngle) < turnSpeed)
	{
		rotation = playerAngle;
	}
	else if(turnAngle > 0)
	{
		rotation += turnSpeed;
	}
	else
	{
		rotation -= turnSpeed;
	}

Make sure you check your code carefully. There were some bugs there (y/x being swapped in atan2, decreasing rotation when the angle was > 0) which you can spot yourself if you take the time to look through.

Solution

I’ve finally reached a perfect solution, although I can’t say this code is as efficient as can be. The real problem ended up the different way rotations were being stored. For the entities rotation, it run counterclockwise 0-360. The result of atan2 gave me something running clockwise and -180-180. The key turned out to be converting to counterclockwise 0-360, after which it was a trivial solution, although code posted earlier on here helped out, particulary in ensuring there isn’t jerky movement when the entity is pointing towards the ship out by only a fraction of a degree.

I’m not sure if this solution would apply to anyone else’s code, but hopefully it could be of help to somebody. Either way, there is plenty of reading material on this post, and I’d like to thank everybody who contributed and helped solve my issue!


playerAngle = (float) (Math.toDegrees((MathUtils.atan2(player.y-y, player.x-x)))+270)%360;
shipRotation = Math.abs(rotation%360);
turnSpeed = 2;
angle = playerAngle-shipRotation;
			
	if(Math.abs(angle)<turnSpeed){
		rotation = playerAngle;
	}else if(angle<0){
		rotation -= turnSpeed;
	}else{
		rotation += turnSpeed;
	}