Can someone explain this function for me please?

I'm reading a book about steering behaviours, I've come across this function but I can't understand the parts with (?) symbol next to them. Specifically, the way the author is getting the turning angles, smallest angles and turning direction is what I don't understand. I know it's simple math but what exactly is going on here? Can someone please explain how they're making the triangle steer around the map please?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
void TrianglePlayer::Steer(const vector<Vector2D>& Enemy, float deltaTime)
{
	float fAngle = 0.0f, AngleMax = 0.0f;
	Vector2D repulsion = Evade(Enemy, deltaTime);

	// Get possible turning angles
	Vector2D bearing = DesiredPosition - position + repulsion;
	float angleToBearing = velocity.angleTo(bearing);

	SteerForce = DesiredPosition - velocity;
	SteerForce.Normalize();
	SteerForce *= 13.0f;  
	SteerForce = SteeringLimit(25.0f);
	AngleMax = SteerForce.m_y * deltaTime;

	// Get turning direction (?)
	if (velocity.CrossProduct(bearing) < 0.0f)
	{
		angleToBearing *= -1;
		AngleMax *= -1;
	}

	// Get smallest angle (?)
	if (angleToBearing < 0.0f)
	{
		fAngle = max(angleToBearing, AngleMax);
	}
	else if (angleToBearing > 0.0f)
	{
		fAngle = min(angleToBearing, AngleMax);
	}

	velocity.Normalize();
	velocity *= speed * deltaTime;
	velocity.rotate(fAngle);
	position += velocity;
}


EDIT: Some code in vector class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
float angleTo(const Vector2D& other) const
    {
        return acos(DotProduct(other) / (length() * other.length()));
    }

    float CrossProduct(const Vector2D& other) const
    {
        // Cz = ax * by - ay * bx
        return m_x * other.m_y - m_y * other.m_x;
    }

    void rotate(float angle)
    {
        float tempX = m_x * cos(angle) - m_y * sin(angle);
        float tempY = m_x * sin(angle) + m_y * cos(angle);

        m_x = tempX;
        m_y = tempY;
    }
Last edited on
On line 8 of the first code, member function angleTo inverts the dot product to find the angle between velocity vector and the bearing. This uses the inverse cosine to determine the angle. However, there are two possible angles between -180 degrees and +180 degrees that have the same cosine and acos will return the one between 0 and 180 degrees (actually its radians equivalent). Line 17 uses the vector cross product (which depends on the sine of the angle) to distinguish them: if the sine, and hence cross product z component, is negative then it actually requires the negative (ie clockwise) angle of turn instead, so it reverses the sign of angleToBearing by multiplying by -1.

The if blocks starting on line 24 are supposed to limit the size of fAngle so that its magnitude is not bigger than the magnitude of AngleMax. However, I'm not entirely sure that they will work, since they require AngleMax on line 14 to be evaluated as positive, and I can't see why that is guaranteed.

I'm afraid that the abuse of basic physics on lines 10, 34 and 36 made me choke.
Last edited on
> Get turning direction
you want to know if turn right or turn left, if the bearing makes you go left or right.

the cross product may be defined as
(a x b)_z = |a| |b| sin \theta_{ab}
what you're looking with velocity.CrossProduct(bearing) < 0.0f is the sign of the sine (note that both |a| and |b| are >= 0, non-negative)

https://en.wikipedia.org/wiki/Cross_product#Computational_geometry
(¿does the DesiredPosition lies to the left or right of where I'm going?)


> Get smallest angle
you can't turn as much as you want, you are limited by the machine. So there exists a MaxAngle and there you want to know if you can make the turn or end up going to MaxAngle.
the conditional is because you may turn right, making the angles negative, so you need the max then (the one closer to 0)
Thank you guys, I get it now. Just a question, why do we get the inverted dot product? Would it work if I use return cos(DotProduct(other) / (length() * other.length())); instead of acos?
No it won't work. You are trying to find the angle in member function angleTo()

From the definition of dot product:
a•b=|a||b|cos(θ)
whence
cos(θ) = a•b/|a||b|
and so
θ=arccos(a•b/|a||b|)

You need the inverse cosine function acos() on the rhs of that equation, not the cosine cos() itself.

The reason that the vector product is appealed to as well is to distinguish between positive and negative angles. Since cos(x)=cos(-x), both x and -x have the same cosine: the acos() function can only return one of them, so it returns the positive one. However, they don't have the same sine, so use of the vector product, which (intrinsically) involves sine, allows you to distinguish them.
Last edited on
Okay, I understand how this works now, thanks guys. :)
Topic archived. No new replies allowed.