Deciding which way to rotate

This topic is 5388 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

I'm writing a small "game" that will let people write AIs for robots, and I'm currently having a problem with getting a robot to turn towards an enemy. My AI currently looks like this:
closestEnemy = self.getClosestEnemy()
side = self.whichSide(closestEnemy.posX, closestEnemy.posY)
if side == 1:
self.rotate("counterclockwise")
else:
self.rotate("clockwise")


The whichSide method looks like this:
def whichSide(self, posX, posY):
# "self" is the method's instance of the  object
c = math.cos(self.heading * math.pi / 180)
s = math.sin(self.heading * math.pi / 180)
if c == 0: c = 0.01
if s == 0: s = 0.01
func = (posX - self.posX) / c - (posY - self.posY) / s

if func > 0: return 1
elif func == 0: return 0
else: return -1


which SHOULD return 1 if the robot is to the left of the robot (i.e. the robot should turn counter clockwise), 0 if it is straight ahead and -1 if it is to the right of the robot. I got this from the Core Techniques and Algoritms book, so I hope it is correct. Then, each frame I call this for each robot:
	def updateInterpolation(self, frametime = 1.0):

else:
pass

self.posX += self.speed * math.cos(self.heading * math.pi / 180)
self.posY += self.speed * math.sin(self.heading * math.pi / 180)


The problem? Well, sometimes it seems to work ok, but most of the time the robot just doesn't rotate. When I print out the result of the whichSide() method, I see that it alternates like this: -1, 1, -1, 1, ... I don't really know now what the error is, and I was hoping that someone here could see what it is I do wrong..

Share on other sites
I'm not sure where the problem is in your code, but if you ask me, that 'if c == 0, c = .01' stuff is bad news! There has to be a better way to do it. So I propose the following. This is how I did it in my flocking demo (i.e. birds need to know how to 'turn toward' other birds in 3d), and it worked very well.

If you already know all about matrices and stuff this might be kind of redundant, but... From your robot's heading, you can construct a 2x2 matrix that represents his orientation. Any good 3d math book will show you how to construct such a matrix.

Any good 3d math book will also show you how to multiply a vector by a matrix, which is what you need to do here. You also need to translate the vector, and for this you can either use a separate step or use a 3x3 matrix with the translation in the bottom row or right column.

Now there are a lot of details here - left or right handed, row or column major - and I admit I spent a while getting that all sorted in my math library. So if you don't have those components in place yet, you might have a little work ahead of you.

But, once you have those tools, you're golden! What you want to do is transform the position of the closest enemy into the 'local space' of the robot. In 'local space' the x or y axis is forward, and the other axis is left or right (which is which depends on your convention and the handedness of the coordinate system).

Once you have the enemy's position in 'local robot space', you have all the information you need. For the following examples let's say y is forward and x is right.

If the dot product between the robot's forward vector and the normalized vector to the enemy is < some value (.7 for 45 degrees, 0 for 90), the enemy is outside of the robot's field of view and the robot can't see it.

If the enemy's local x is negative, the robot must turn left to face it. If positive, it must turn right. If the enemy's x is zero or within some tolerance, the robot goes straight ahead.

The length of the vector to the enemy gives the distance to the enemy, which you can use to determine visibility, accuracy, etc.

You can even use the information to determine turning rate, i.e. the robot turns faster when he has farther to turn to face the enemy.

That probably wasn't exactly the answer you were looking for, and it admittedly might take some work to get up and running if you don't have a math library in place. But I think you'd be happier with this method, and that it's worth looking into.

Share on other sites
Thanks for the reply, but I managed to find another way which is way easier. I just compare the headings between the two robots:

	def whichSide(self, angleToEnemy):		if angleToEnemy < self.heading:			if abs(angleToEnemy - self.heading) < 180:				return "clockwise"			else:				return "counterclockwise"		else:			if abs(angleToEnemy - self.heading) < 180:				return "counterclockwise"			else:				return "clockwise"

Share on other sites
There's a really simple solution to this - the dot product. The dot product is defined as:
|a|.|b|.cos (theta) (1)
where theta is the angle between the two vectors, the vector a is perpendicular to the forward vector and b is the vector to the other robot. But, it's also defined as:
axbx + ayby (2)
In (1) the only thing affecting the sign of the result is the cos (theta) term (magnitudes are positive), so the sign of (2) implies the sign of the cos (theta) term which then implies the direction to turn.

Skizz

P.S. One thing to watch out for is oscillation due to overshooting the target direction when turning.

Share on other sites
Yeah, the perp-dot works as well. And your new method is certainly superior to your old one.

However, although the methods you're using seem a lot easier than all the matrix stuff, keep in mind that by computing the forward and perpendicular vectors for your robot, you've actually already computed its orientation matrix. So you're not that far away from being able to perform matrix operations after all.

However, as long as you have the forward and side vectors and the dot product at your disposal, you should be able to do pretty much everything you want to do.

• 21
• 13
• 9
• 17
• 13