@Whistler:
Nope ! it's NOT okay, because even if your resulting angles are in bounds, they are NOT ANYMORE modulo 360 versions of the original one !
it's as if you were doing
Code:
if ((angle < -180) || (angle >= 180))
angle = RANDOM_FLOAT (-180, 180);
... with a bit of exxageration, I concede
Nevertheless your code is wrong, and I can prove it.
Instead of running your test program, rather run this one:
Code:
void main (void)
{
float random_angle;
float result_angle;
int count = 0;
while (1)
{
random_angle = RANDOM_FLOAT (-100000000, 100000000);
result_angle = AngleNormalize (random_angle);
if ((result_angle < -180) || (result_angle >= 180))
{
printf ("ERROR! in=%f out=%f count=%d\n", random_angle, result_angle, count);
getchar ();
}
result_angle = AngleNormalize360 (random_angle);
if ((result_angle < 0) || (result_angle >= 360))
{
printf ("ERROR! in=%f out=%f count=%d\n", random_angle, result_angle, count);
getchar ();
}
count++;
}
}
You will see that your code fails for large values of angle.
And NOT only this, but if you add a
Code:
printf ("in=%f out=%f\n", random_angle, result_angle);
getchar ();
for each angle that is tested, and compare the input and the output, you'll notice that the output is NOT a modulo 360 representative of the input. You have an error that goes increasing with larger values.
Believe me, I've tested it all thoroughly, thanks to you pointing me that bug, and I've found the right code. It goes like this:
Code:
float WrapAngle (float angle)
{
// this function adds or substracts 360 enough times needed to the angle_to_wrap angle in
// order to set it into the range -180/+180 and returns the resulting angle. Letting the
// engine have a hand on angles that are outside these bounds may cause the game to freeze
// by screwing up the engine math code.
// check for wraparound of angle
if (angle >= 180)
angle -= 360 * abs (((int) angle + 180) / 360);
if (angle < -180)
angle += 360 * abs (((int) angle - 180) / 360);
// needs a 2nd pass to check for floating part truncation (rounded 180)
if (angle == 180.0)
angle = -180;
return (angle);
}
float WrapAngle360 (float angle)
{
// this function adds or substracts 360 enough times needed to the angle_to_wrap angle in
// order to set it into the range +0/+360 and returns the resulting angle Letting the
// engine have a hand on angles that are outside these bounds may cause the game to freeze
// by screwing up the engine math code.
// check for wraparound of angle
if (angle >= 360)
angle -= 360 * abs ((int) angle / 360);
if (angle < 0)
angle += 360 * abs (((int) angle - 360) / 360);
// needs a 2nd pass to check for floating part truncation (rounded 180)
if (angle == 360.0)
angle = 0;
return (angle);
}
And if you think about it it's perfectly logical. The function asks itself, how many times can I add OR substract 360 to the current angle to have it in the bounds ? Then, taking the absolute of this value, it either adds (if value was initially inferior) OR substract (if value was initially superior) - hence the abs(), as many times 360 as needed and the resulting angle is GUARANTEED to be in bounds, and a modulo of 360.
The only check left to do is the floating point truncation (precision error) that would make the final angle land accurately on a rounded 180 (which would be just above the limit).