Angle turning code

Discuss programming in the QuakeC language.
Post Reply
Wazat
Posts: 771
Joined: Fri Oct 15, 2004 9:50 pm
Location: Middle 'o the desert, USA

Angle turning code

Post by Wazat »

I don't know who, but somebody posted this code on the old forums a while back:
void() meet_new_dir =
{
if (vlen(self.new_way - self.angles) > 2)
self.angles = self.angles + normalize(self.new_way - self.angles) * 2;
else
self.angles = self.new_way;
};

I'd like to know who it is so I can give them credit. Anyway, at first it didn't work, because there is a specific condition needed in order for the code to operate: the angles need to range from -180 to 180, instead of 0-360 or some other system.

So, I've since modified the function to be more general-purpose. Here are the results:

Code: Select all

/*
-----------------------------------------
frik_anglemod (part of FrikBot)

faster version of id's anglemod
-----------------------------------------
*/

float(float v) frik_anglemod =
{
	return v - floor(v/360) * 360;
};

/*
-----------------------------------------
capangle (by Wazat)

Quick little function to save time.
Makes sure an angle's 3 floats range from 0-360
-----------------------------------------
*/

vector(vector ang) capangle =
{
	ang_x = frik_anglemod(ang_x);
	ang_y = frik_anglemod(ang_y);
	ang_z = frik_anglemod(ang_z);

	return ang;
};


/*
-----------------------------------------
nangle (by Wazat)

Basically makes an angle range from -180 to 180.
-----------------------------------------
*/

vector(vector ang) nangle =
{
	ang = capangle(ang);

	if (ang_x > 180)
		ang_x = ang_x - 360;
	else if (ang_x < -180)
		ang_x = ang_x + 360;

	if (ang_y > 180)
		ang_y = ang_y - 360;
	else if (ang_y < -180)
		ang_y = ang_y + 360;

	if (ang_z > 180)
		ang_z = ang_z - 360;
	else if (ang_z < -180)
		ang_z = ang_z + 360;

	return ang;
};


/*
-----------------------------------------
angle_turn (by... actually I forget who wrote this one)
Modified by Wazat to be more general-purpose.

Turns oldang toward newang in 'turnrate' increments.
-----------------------------------------
*/

vector(vector oldang, vector newang, float turnrate) angle_turn =
{
	newang = nangle(newang);
	oldang = nangle(oldang);

	if (vlen(newang - oldang) > turnrate)
		return oldang + normalize(newang - oldang) * turnrate;
	else
		return newang;
};
The new function, renamed to angle_turn, is a lot more general-purpose, allowing any angle to turn toward an ideal angle, and any turn rate specified. I use it for the mini-turrets in Conquest, so that I don't have to rely on ChangeYaw(). Here is the code I use:

Code: Select all

		newang = vectoangles(dir);
		self.angles_z = newang_z; // don't modify roll
		newang = self.angles = angle_turn(self.angles, newang, self.ammo_nails);
		self.angles_z = 0; // stay level (0 roll)
		// set self.movedir so turret will know what direction to fire later on
		newang_x = newang_x * -1; // x angle is always backward for some reason
		makevectors(newang);
		self.movedir = v_forward;
I hope this code comes in handy for someone here... And I hope I can find out who posted the original so I can give them credit.
When my computer inevitably explodes and kills me, my cat inherits everything I own. He may be the only one capable of continuing my work.
Wazat
Posts: 771
Joined: Fri Oct 15, 2004 9:50 pm
Location: Middle 'o the desert, USA

Post by Wazat »

I forgot to mention, I'm having one problem with this code: it often turns in the wrong way. In other words, if the enemy is just to the right of the turret, it will turn left all the way around to hit it.

Can anyone help me fix that?
When my computer inevitably explodes and kills me, my cat inherits everything I own. He may be the only one capable of continuing my work.
Urre
Posts: 1109
Joined: Fri Nov 05, 2004 2:36 am
Location: Moon
Contact:

Post by Urre »

Wazat wrote:I forgot to mention, I'm having one problem with this code: it often turns in the wrong way. In other words, if the enemy is just to the right of the turret, it will turn left all the way around to hit it.

Can anyone help me fix that?
Sorry, no, I was just going to mention that I've experienced the very same problem. Ticks one off, for sure.
I was once a Quake modder
IceDagger
Posts: 25
Joined: Fri Nov 19, 2004 10:43 am

Post by IceDagger »

You have to check which is the smaller angle, the one on the right, or the one on the left.

I think this is what's causing your problem:

If the turret were facing 160 degrees, and was told to turn to -160 degrees, your code might be rotating 160 down to 0, down to -160, when it would be faster to rotate from 160 up to 200 (which is the same as -160).

If you've done some C programming, you might want to take a look at the QER frame interpolation tutorial (Specifically, the rotation interpolation code). Essentially you want to interpolate the turret's rotation along the smaller angle, which is what is done in frame interpolation when an entity's angle changes.


Hope this helps. :D
Wazat
Posts: 771
Joined: Fri Oct 15, 2004 9:50 pm
Location: Middle 'o the desert, USA

Post by Wazat »

Hurray, it works!

Here's the new function:

Code: Select all

/*
-----------------------------------------
angle_turn (by Wazat)

Turns oldang toward newang in 'turnrate' increments.
-----------------------------------------
*/

vector(vector oldang, vector newang, float turnrate) angle_turn =
{
	local vector ang, dir;
	local float dist;
	newang = nangle(newang);
	oldang = nangle(oldang);

	if (vlen(newang - oldang) > turnrate)
	{
		//dir = normalize(newang - oldang);
		//ang = oldang + dir * turnrate;

		dist = frik_angcomp(newang_x, oldang_x);
		if(dist > 0 && dist > turnrate)
			dist = turnrate;
		else if(dist < 0 && dist < turnrate * -1)
			dist = turnrate * -1;
		ang_x = oldang_x + dist;

		dist = frik_angcomp(newang_y, oldang_y);
		if(dist > 0 && dist > turnrate)
			dist = turnrate;
		else if(dist < 0 && dist < turnrate * -1)
			dist = turnrate * -1;
		ang_y = oldang_y + dist;

		dist = frik_angcomp(newang_z, oldang_z);
		if(dist > 0 && dist > turnrate)
			dist = turnrate;
		else if(dist < 0 && dist < turnrate * -1)
			dist = turnrate * -1;
		ang_z = oldang_z + dist;

		return ang;
	}
	else
		return newang;
};
When my computer inevitably explodes and kills me, my cat inherits everything I own. He may be the only one capable of continuing my work.
Post Reply