Tuesday, July 31, 2012

Programming: AI for Following a Target

Recently, I changed my code used in an enemy that follows the player. Apparently I did a huge mistake by using cross and dot products. There are simpler way to do it by using angle values. Here is how it works.

The first thing I did is to find the current enemy angle from the provided rotation matrix. There's nothing too fancy about this. It can be achieved by a simple trigonometry. I also need the angle between the enemy and the player.

m_targetDirection = m_p_target->m_position - m_position;
m_targetAngle = atan2f(m_targetDirection.y, m_targetDirection.x);

Since now that I have both the angle, I can simply find the difference by subtracting them.

l_diffAngle = m_currentAngle - m_targetAngle;

We have to be careful in treating the difference. There are cases when the difference could be larger than PI or smaller than -PI. In that case, we have to convert the value so it will fall between -PI and PI. This can be done with this simple if-else statement.

if (fabsf(l_diffAngle) > M_PI )
   l_diffAngle = 2 * M_PI - l_diffAngle;

Since there is a limit how far the object can turn per second, we also have to handle if the difference is smaller than the object's rotation speed. In that case, we use the difference instead of rotation speed.

if (fabsf(l_diffAngle) < m_rotationSpeed)
   l_change = fabsf(l_diffAngle);
   l_change = m_rotationSpeed;

The most important part is to decide whether to turn left or turn right. The object must not turn right more than 180 degree (PI) since its shorter to turn left, and vica versa. This kind of decision can be done by calculating the value of the difference of the angle. If the difference is positive, turn right (clockwise, minus). Turn left (counter clockwise, positive) otherwise. It can be done by using this simple if-else statement.

if ( l_diffAngle > 0 ) {
   l_change = -l_change;

The last part is to add the value to our current angle.

m_currentAngle = m_currentAngle + l_change;
if (m_currentAngle < 0)
   m_currentAngle = M_PI * 2.0f + m_currentAngle;

This is a very basic concept in Artificial Intelegence, yet there are a few things that need to be concerned to create a good one. I'm not sure if this one is faster than using dot and cross products since we use trigonometric functions (atan2f) in this method. I'll try to benchmark both ways and check which one is the best way to do it.

No comments: