Advertisement

How Would You Make This Rotate To Target Script Better? (C++)

Started by April 20, 2011 04:43 AM
1 comment, last by haegarr 13 years, 7 months ago
I'm currently working on AI for my game engine and the AI is really simple, when I mean really simple, I mean the AI can only move around in one room and the CPU controlled AI simply picks a random vector in the room for the AI to go to so it seems like the AI wonders around. Though there is a slight issue getting my AI to rotate to the fastest direction to where it should walk.

Here is my script:


double cx = (double)NPC_list.pos.m_X - (double)NPC_list.GoalPos.m_X;
double cy = (double)NPC_list.pos.m_Y - (double)NPC_list.GoalPos.m_Y;

float Radians = (float)atan2(cy, cx);
float Degree = Radians * 180 / 3.14159265f;

bool TurnedLeft = false, TurnedRight = false;

if(NPC_list.rotation != Degree)
{
if(Degree > NPC_list.rotation)
{
NPC_list.rotation += 200.0f * TimeDelta;
TurnedLeft = true;
}

if(Degree < NPC_list.rotation)
{
NPC_list.rotation -= 200.0f * TimeDelta;
TurnedRight = true;
}

if(TurnedLeft && TurnedRight)
{
NPC_list.rotation = Degree;
}
}


There are a couple of problems with this script.

1. I know this isn't the best way to have a object to rotate to aim at a position or "goal position". (My opinion, I just know there are maybe different ways to write this type of script coming from experience of people writing scripts differently then me.)

2. The AI doesn't always rotate to the quickest direction in certain places in positions such as if the AI or goal position has a negative or positive value. (Example: Lets say your going to pick up a can of soda thats to the right of you and instead or turning right you turn left to get to the soda)

So I was wondering how someone would write a script like this where the AI would rotate to a position maybe using my script as a template or using their own.

Thank you, Ajm.
Check out my open source code projects/libraries! My Homepage You may learn something.
You miss the modulo in the angles.

You should normalize the difference between target angle and current angle,
and then check if you should turn right or left.

That way -179° vs 179° should turn like 181° vs 179°.
Advertisement

You mentioned there there are other ways of solving the problem; here comes one of them (a big part of this post is an explanation; the solution comes at the end):


The cross-product of 2 (not vanished) vectors

v := a x b

results in a vector v that is perpendicular to the plane that is spanned by the 2 argument vectors a and b. If you exchange the both argument vectors you'll get the negated result:

b x a = -v

This feature can be used to determine the shortest way in your use case.


First, you have just angles but no vectors where the NPCs are facing. This can be changed by computing the facing vector f[sub]i[/sub] of NPC i as

f[sub]i[/sub] := [ cos( a[sub]i[/sub] ) sin( a[sub]i[/sub] ) 0 ][sup]t[/sup]

where a[sub]i[/sub] denotes the said rotation angle of NPC i. Those facing vector will be in direction of the cardinal x axis if the angle is 0, and will be in direction of the cardinal y axis if the angle is 90 degree. It further never points in z direction.


The prescription to compute the cross-product of 2 vectors can be found on the internet. For your use case it is sufficient to compute the z co-ordinate:

v[sub]z[/sub] = a[sub]x[/sub] * b[sub]y[/sub] - a[sub]y[/sub] * b[sub]x[/sub]

where the indices x, y, z denote the x, y, or z component, resp. In your case a and b are the both facing vectors, so you get

v[sub]z [/sub]= cos( a[sub]i[/sub] ) * sin( a[sub]j[/sub] ) - sin( a[sub]i[/sub] ) * cos( a[sub]j[/sub] )

where a[sub]i[/sub] denotes the angle of the one NPC and a[sub]j[/sub] the angle of the other NPC. If this v[sub]z[/sub] is a positive number, then the shorter arc of the 1st NPC to the 2nd is in CCW direction. If it is a negative number, then the shorter arc is in CW direction.


There is a caveat: Assume that the both angles have an identical value, say a. Then the situation is

cos( a ) * sin( a ) - sin( a ) * cos( a ) == 0

and you cannot distinct a negative / positive v[sub]z[/sub].


But there is a 2nd caveat: Assume that the both angles differ by 180 degrees. Then the situation is

cos ( a ) * sin( a + 180 ) - sin( a ) * cos( a + 180 ) = cos( a ) * ( -sin( a ) ) - sin( a ) * ( -cos( a ) ) == 0

and you cannot distinct a negative / positive v[sub]z[/sub].


Here comes the dot-product to your rescue. It shows a correspondence

a . b = |a| * |b| * cos( <a,b> )

what means that its value is equal to the product of the length of both vectors and the cosine of the angle between the both vectors. Well, the length will a or b will be 1 due to the way we've computed them, because

cos( a )[sup]2[/sup] + sin( a )[sup]2[/sup] + 0[sup]2[/sup] == 1


Now, if the angle between them is 0 as given by the first caveat, then its cosine is 1. If the angle between them is 180 degree as is given by the 2nd caveat, then its cosine is -1. So the dot-product will be (close to) 1 if the angle is (close to) 0, and it will be (close to) -1 if the angle is (close to) 180 degree.





So, in summary, do this:


For the both facing vectors


f[sub]1[/sub] = [ cos( a[sub]1[/sub] ) sin( a[sub]1[/sub] ) 0 ][sup]t[/sup]

[sup]

f[sub]2[/sub] = [ cos( a[sub]2[/sub] ) sin( a[sub]2[/sub] ) 0 ][sup]t[/sup]

[sup]

[/sup][/sup]

[sup]
[/sup]

[sup]

[sup][/sup]where f[sub]1[/sub] is for the NPC that should rotate, and f[sub]2[/sub] for the NPC to rotate to (the order is important).

[sup]

[/sup]

1. Compute the dot-product

d = f[sub]1[/sub] . f[sub]2[/sub] = cos( a[sub]1[/sub] ) * cos( a[sub]2[/sub] ) + sin( a[sub]1[/sub] ) * sin( a[sub]2[/sub] )

and do nothing if d is close to +1, but choose either CW or CCW if it is close to -1. Otherwise continue with 2.

2. Compute the cross-product's z component

v[sub]z[/sub] = ( f[sub]1[/sub] x f[sub]2[/sub] )[sub]z [/sub]= cos( a[sub]1[/sub] ) * sin( a[sub]2[/sub] ) - sin( a[sub]1[/sub] ) * cos( a[sub]2[/sub] )

and choose CCW if it is positive, but CW if it is negative.

That's it. Hopefully I haven't confused positive and negative signs.

EDIT: I hope that the editor will be updated soon...

[/sup]

This topic is closed to new replies.

Advertisement