Reputation: 22317
I have a character in my game that must rotate smoothly to get to a desired angle. Consider angle
as the current angle and touchAngle
as the desired angle which is always between 0 to 360. I want to add +1/-1 to current angle in every game update to get to the desired touchAngle
. The problem is first it must chose direction and it must be between 0 to 360. this is my pseudo code:
int touchAngle;
float angle;
public void update()
{
if ((int)angle != touchAngle) angle += ???
}
Upvotes: 6
Views: 7896
Reputation: 551
Since you have values that are always normalized in the interval [0 360]
this should not be too hard.
You just need to distinguish two different cases:
angle < touchAngle
angle > touchAngle
in the first case we want to rotate counterclockwise so the update has to be angle =+ 1
(assuming that you want to turn of 1 every update cycle).
In the second case we want to turn clockwise so the update should be angle -= 1
.
The problem is that this is not always the shortest way to rotate. For instance if:
angle == 359
touchAngle == 1
we don't want to make all the way 358, 357, 356...instead we want to rotate counterclockwise for just 2 units: 360, 1.
This can be achieved comparing the distance between the angles abs(angle - touchAngle)
.
If this value is bigger than 180
it means we are going the wrong way, so we have to do the way around so
if(angle < touchAngle) {
if(abs(angle - touchAngle)<180)
angle += 1;
else angle -= 1;
}
else {
if(abs(angle - touchAngle)<180)
angle -= 1;
else angle += 1;
}
of course all of this until ((int)angle != touchAngle)
.
I might have made mistakes with the cases but this is the principle.
Upvotes: 11
Reputation: 315
Generally you want to bring in time to the equation, so that you can smoothly change the angle over time
. Most setups have a way to get a time it took to render the previous frame and the typical way to do this is to say..
int touchAngle;
float angle;
float deltaTime; //Time it took to render last frame, typically in miliseconds
float amountToTurnPerSecond;
public void update()
{
if((int)angle != touchAngle) angle += (deltaTime * amountToTurnPerSecond);
}
This will make it so that each second, your angle is changed by amountToTurnPerSecond
, but changed slowly over each frame the correct amount of change so that it is smooth. Something to note about this is that you wont evenly end up at touchAngle
most of the time, so checking to see if you go over and instead setting to touchAngle
would be a good idea.
Edit to follow up on comment:
I think the easiest way to attain the correct direction for turn is actually not to use angles at all. You need to get the relative direction from your touch to your character in a 2d space. Typically you take the touch from screen space to world space, then do the calculations there (at least this is what I've done in the past). Start out by getting your touch into world space, then use the vector cross product to determine direction. This looks kind of like the following...
character position = cx, cy
target position = tx, ty
current facing direction of character = rx, ry
First we take the distance between the character and the target position:
dx = tx - cx
dy = ty - cy
This not only gives us how far it is from us, but essentially tells us that if we were at 0, 0, which quadrant in 2d space would the target be?
Next we do a cross product:
cross_product = dx * ry - dy * rx
If this is positive you go one way, if it's negative you go the other. The reason this works out is that if the distance is for instance (-5, 2)
then we know that if we are facing directly north, the point is to our left 5 and forward 2. So we turn left.
Upvotes: -1