Video game programming requires extensive use of mathematics and physics. Some typical examples are the following: controlling the motion of objects in space, drawing geometric shapes on the scene, computing the effects after a collision of objects in accordance with Newton’s laws of classical mechanics, etc.
Geometry plays a fundamental role. The classic geometric shapes (circles, squares, polygons, cubes, spheres,…) are used frequently. The description of the scene is simply a set of triangles and colors. Even the most complicated objects like curved surfaces, NURBS and others, are actually generated and approximated with a set of triangles. The basic geometric shapes can be manipulated on the scene through operations of translation, rotation and change of scale, obtaining an infinite variety of geometric and spatial configurations.
Vector calculus is one of the most frequently used branches of mathematics, in particular to simulate the movement of rigid bodies in space, according to the laws of mechanics.
1) Definition of vector
A vector in the plane (2D) or in the space (3D) is an oriented segment that links a point (called origin or starting point) with another point (called terminal point). A vector from a point \(P\) to a point \(Q\) is represented with the symbol \( \overrightarrow{PQ}\).
A vector has 3 fundamental properties:
- size (or magnitude), represented by the length of the segment, with respect to a predetermined unit of measurement
- direction, which coincides with the (geometric) line on which the segment lies
- sense, which specify the orientation of the segment that defines the vector
We can also define the null vector, which is reduced to a point and is represented with the symbol \(\textbf{0}\).
Vectors are used in physics to represent the position of a body in the plane or space, speed, acceleration, applied force, etc.
By introducing a Cartesian reference system, a vector can be represented by the coordinates of its terminal point, assuming that the initial point is at the origin of the reference system.
Two vectors coincide if they have the same magnitude, direction and sense; to check if two vectors are equal, simply move one parallel to itself so that the starting points coincide and check if the end points of the two vectors also coincide.
The size of a vector \( \overrightarrow{PQ}\), indicated with the symbol \({\left \| {PQ}\right \|}\) can be computed using the Pythagorean Theorem:
A normalized vector is a vector whose norm is equal to \( 1 \). Given a vector \( \mathbf{v}\), it is enough to divide by its norm to obtain a normalized vector \( \mathbf{w}\):
\[ \mathbf{w} = \dfrac {\mathbf{v}} {\left\| {\mathbf{v}}\right\|} \]2) Vector Algebra
2.1) Sum and difference of vectors
The sum of two vectors \( \mathbf{u},\mathbf{v}\) can be obtained by applying the parallelogram rule of Euclidean geometry. The end point of the vector \(\mathbf{u}\) coincides with the starting point of the vector \( \mathbf{v}\). The sum vector \( \mathbf{u+v}\) has as its origin the starting point of \( \mathbf{u}\) and as its term the end point of \(\mathbf{v}\). Practically the sum vector coincides with the diagonal of the parallelogram generated by two vectors.
The sum of the two vectors \(\overrightarrow{OA}\) e \( \overrightarrow{OB} \) is represented by the vector \(\overrightarrow{OC}\):
Another way to compute the sum vector is to carry out the algebraic sum of the respective Cartesian coordinates of the two vectors. To perform the subtraction of two vectors, it is sufficient to first invert the second vector (changing the sign of the coordinates) and then make the sum with the first.
2.2) Multiplication of a vector by a real number (scalar)
The multiplication of a vector by a scalar consists in multiplying each of the components for the scalar. In geometric terms it is equivalent to an expansion or contraction of the vector.
2.3) The scalar product of two vectors
The scalar product of two vectors \( \mathbf{u},\mathbf{v}\) in two dimensions (2D space) is the real number
\[ \mathbf{u} \bullet \mathbf{v}= u_{1}v_{1} + u_{2} v_{2} \]It can be shown that an equivalent definition of a scalar product is the following:
\[ \mathbf{u} \bullet \mathbf{v}=\left\| {\mathbf{u}} \right\| \left\| {\mathbf{v}} \right\| cos(\alpha) \]where \( \alpha \) is the angle between the two vectors.
Putting together the two definitions, we obtain the following formula:
This formula allows to determine the angle between the two vectors, computing the scalar product starting from the components of the two vectors.
2.4) The vector product of two vectors
The vector product of two vectors \( \mathbf{u, v}\) is a new vector so defined:
\[ \mathbf{w}= \mathbf{u} \times \mathbf{v} = |\mathbf{u}| |\mathbf{v}|\mathbf{\hat{n}} \sin \alpha \]where \( \alpha \) is the angle between the two vectors \( \mathbf{u,v}\) and \(\mathbf{\hat{n}}\) is the unit vector (versor) perpendicular to the plane identified by the two vectors \( \mathbf{u,v}\). The sense of the produced vector is determined with the right hand rule. The vector product module is equal to the area of the parallelogram generated by the two vectors.
For a more in-depth study of vector algebra and game programming see for example [1] or [2].
3) Vectors in Unity 3D and the Transform component
Unity3D uses the Vector3 and Vector2 structures to represent vector information in 3D or 2D environments. The Vector3 structure is the most used one. The Vector2 structure is used in 2D games and in other special situations, for example to memorize the texture coordinates of a Mesh.
The Vector3 structure provides various properties and methods for performing normal vector calculus operations; these include the following (see the guide Vector3):
- Vector3.Normalize – provides a new vector with unitary norm
- Vector3.Dot – scalar product of two vectors
- Vector3.Cross – vector product of two vectors
- Vector3.MoveTowards – moves a point towards a target object
- Vector3.RotateTowards – rotates a vector by a certain angle towards a target
Every object (GameObject) in Unity has a Transform component, which stores and manipulates information about position, rotation, and scale factor.
More precisely, the transform component keeps track of the following information:
- position coordinates of the object, stored with the Vector3 structure
- rotation with respect to the coordinate axes, stored internally with the Hamilton quaternions (Quaternion structure), but displayed in the Inspector with the Euler angles that are simpler to interpret
- the scale factor in the three directions, stored with the Vector3 structure
For an in-depth study of the Unity development environment, see for example the Unity tutorials.
4) Examples of vector applications in Unity
Example 4.1 – Motion of an object
There are several ways to move an object on the scene. In Unity the position of an object is available with the Transform component. The easiest way to move an object to a given space position is as follows:
transform.position = new Vector3(10f, 4f, 12f);
This instruction instantly moves the object to its new position.
To move an object along a direction, with a continuous change of coordinates, you can also use the translate method:
transform.Translate(new Vector3(2f, 0f, 0f));
The parameters that are passed in this function correspond to the change of coordinates on the 3 axes. The transform.Translate function does not use the physical engine and therefore does not handle collisions. To obtain movement in the presence of obstacles, walls and collisions it is necessary to use the Collider component and the Rigidbody component, which allow to simulate the behaviour according to the laws of physics.
To move an object in the direction of another object, you need to make a rotation:
public Transform target; Vector3 posRelative = target.position - transform.position; transform.rotation = Quaternion.LookRotation(posRelative);
Example 4.2 – Compute the position of an object that moves at a constant speed
As it is known, the scene of each game is displayed through a sequence of discrete frames, one after the other, at a suitable frequency (e.g. 30 frames per second). The status of the various objects on the scene is continuously updated through the game loop.
The preparation of each frame involves the execution of the Update function present in the scripts attached to the various objects. If the position coordinates of an object are changed, we’ll have the illusion of the movement of the object itself. The Time.deltaTime parameter contains the information on the time elapsed between one frame and another.
// previous position position = (0, 5, 10) // speed (for example expressed in cm/s) speed = (2, 3, 0) // position update position += speed * Time.deltaTime
Example 4.3 – Determine the rotation angle to track another object
A typical situation in 2D games is the following: suppose that a character (A) must follow an enemy who is in a fixed situation (B). If the character is moving in the direction \( \overrightarrow{OA} \), then to get to point B we need to compute the angle between the two vectors \( \mathbf{u}= \overrightarrow{OA}\) and \( \mathbf{v}=\overrightarrow{OB} \). The formula of the scalar product allows to find the cosine of the angle:
\[ cos(\alpha) = \dfrac {\mathbf{u} \bullet \mathbf{v}} {\left\| {\mathbf{u}} \right\| \left\| {\mathbf{v}} \right\|} \]Then we have
\[ \alpha= \arccos \left(\dfrac {\mathbf{u} \bullet \mathbf{v}} {\left\| {\mathbf{u}} \right\| \left\| {\mathbf{v}} \right\|}\right) \]where \( \arccos() \) is the inverse of the cosine function.
Example 4.4 – Check if an object is in front of or behind another
Remember that in Unity we have two different coordinate systems:
- Global (World space) – the only valid system for all objects, with the origin fixed in the center of the scene
- Local (Local space) – one for each object in the scene, with the origin fixed in the object
To switch from one system to another, Unity provides the following methods (see Transform):
- TransformDirection
- TransformPoint
- TransformVector
- InverseTransformDirection
- InverseTransformPoint
- InverseTransformVector
The first three transform the local coordinates into global ones, the following do the vice versa.
To solve the example with the scalar product, it is necessary to transform the constant local coordinates of the Vector3.forward vector into the global correspondents.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
public Transform otherObject;
void Update() {
if (otherObject) {
Vector3 forward = transform.TransformDirection(Vector3.forward);
Vector3 toOtherObject = otherObject.position - transform.position;
if (Vector3.Dot(forward, toOtherObject) < 0)
print("The other object is behind");
}
}
}
In a similar way you can check if an object is above or below you.
Example 4.5 – Circular motion
To manage the circular motion of an object around another object (for example the Earth around the Sun), the following instructions can be used:
using UnityEngine;
using System.Collections;
public class CircularMotion : MonoBehaviour {
public Transform center;
Vector3 radiusVector; // radius vector sun --> earth
public float speed = 30.0f; // degrees/second
private float x;
private float y;
private void Start() {
radiusVector = transform.position - center.position;
}
private void Update() {
// compute new radius vector
radiusVector = Quaternion.AngleAxis(speed * Time.deltaTime, Vector3.forward) * radiusVector;
// update Earth position
transform.position = center.position + radiusVector;
}
}
Example 4.6 – Objective tracking (steering algorithm)
In games where he has to chase a target, the player has at his disposal a control device that adjusts his speed at each frame, in order to reach the target position. The applied correction force allows the character to continuously change its old direction and point to the direction of the target. Graphically the situation can be represented as follows:
where point (D) represents the object to be pursued (target) and:
- \(\overrightarrow{AB}\) : current velocity;
- \(\overrightarrow{AD}\) : desired velocity;
- \(\overrightarrow{BC}\) : steering force;
- \(\overrightarrow{AC}\) : new current velocity;
In each frame the computed corrective force is added to the speed of the chasing character, allowing a continuous adjustment of the path towards the goal. The strength of the force is divided by the mass, so that different motions will result depending on the mass of the character.
A very simplified scheme to adjust the speed direction, starting from the current position of a given target, is the following:
using UnityEngine;
using System.Collections;
public class ChaseTarget: MonoBehaviour {
private float speed = 10.0f;
private float mass = 4.0f;
private float currentSpeed;
private Vector3 positionTarget;
private Vector3 velocityPlayer;
private Vector3 desiredVelocity;
private void Start() {
velocityPlayer = transform.forward;
}
private void Update() {
positionTarget = target.transform.position;
currentSpeed = speed * Time.deltaTime;
// compute new direction
velocityPlayer += AdjustDirection(positionTarget);
// update player position and direction
transform.position += velocityPlayer;
transform.rotation = Quaternion.LookRotation(velocityPlayer);
}
// function for computing steering force and acceleration
public Vector3 AdjustDirection(Vector3 posTarget) {
// compute desired velocity
desiredVelocity = (posTarget - transform.position);
desiredVelocity.Normalize();
desiredVelocity *= currentSpeed;
// compute force and acceleration
Vector3 steeringForce = desiredVelocity - velocityPlayer;
Vector3 acceleration = steeringForce / mass;
return acceleration;
}
}
Obviously a real implementation of the algorithm must handle many complex situations, such as the variable movement of the target, the presence of obstacles, the possibility of collisions with other objects, the behavior to follow when the distance with the target is below a given threshold, etc.
Conclusion
Mathematics is the fundamental tool for the development of video games. In addition to vector calculus, many other areas of mathematics have an indispensable role (geometry, trigonometry, differential equations, probability calculus,…). In the most interesting games the characters are immersed in a scene that tries to simulate the real world. To make the behaviour of characters of the game realistic, it is necessary to simulate the laws of physics and thus to solve complex mathematical equations. The computing of the trajectory of an aircraft, the driving of a car at high speed, the descent along a snow track, the jump of an obstacle, would not be possible without the aid of mathematical tools.
Bibliography
[1]E. Lengyel – Foundations of Game Engine Development, Vol. I (Terathon Software LLC)
[2]L. Bishop, J. Van Verth – Essential Mathematics for Games and Interactive Applications (AK Peters/CRC Press)
0 Comments