© Sebastiano M. Cossu 2021
S. M. CossuBeginning Game AI with Unityhttps://doi.org/10.1007/978-1-4842-6355-6_2

2. The Basics

Sebastiano M. Cossu1  
(1)
LONDON, UK
 

As cleverly explained in the book Flatland by Edwin Abbott, reality is made by many dimensions, and depending on your perception skills, you can see and act only on some of them. This is true also in video games: video games can be set in 3D or 2D worlds, and this distinction determines the way in which agents can perceive the surrounding world and so their ability to move and act.

An N-dimensional space is a geometrical setting in which a point in space is identified by N values or parameters, commonly named after the last letters of the alphabet.

In a two-dimensional space (2D space or plane), a point in space is defined by two values called width and height (commonly referred to as x and y). The objects you can represent in a 2D space are points, lines, and all the plane geometrical figures like triangles, squares, circles, and so on (Figure 2-1).
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig1_HTML.jpg
Figure 2-1

A 2D space has two dimensions: width and height

In a three-dimensional space (3D space) – which is the space we can perceive – points in space are identified by three parameters: height, width, and depth, commonly referred to as x, y, z. In a 3D space, you can represent all the 2D objects and all the objects that, other than height and width, have also the third dimension: depth. Geometrical objects that have three dimensions are cubes, spheres, pyramids, and…well, basically all the matter we know in the universe (Figure 2-2)!
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig2_HTML.jpg
Figure 2-2

A 3D space has three dimensions: width, height, and depth

So, as we said, depending on the number of dimensions in a space, you need an adequate number of values to identify a point in that space. Those values are represented by vectors.

2.1 Vectors

A vector is a quantity defined in an N-space by n values, and it has magnitude and direction. The magnitude of a vector is basically the size of the vector, while the direction is its orientation in the space (Figure 2-3).
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig3_HTML.jpg
Figure 2-3

A basic representation of a vector

A straightforward example of a vector is acceleration. Let’s say you’re driving a car at 50 km/h. If you keep going at 50 km/h, the acceleration is 0 km/h2; if you press the accelerator a bit more, the velocity will grow at a pace of – let’s say – 5 km/h2. This acceleration value is a vector with direction equal to the orientation of the car and magnitude 5 km/h2.

So, with vectors, we can track movements and forces acting in a space. For example, in a video game (2D or 3D, doesn’t matter), the movement of a character moving from a point A to a point B is represented by a vector $$ overrightarrow{mathtt{AB}} $$ of magnitude m = B-A and direction equal to the orientation of an arrow going from A to B (Figure 2-4).
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig4_HTML.jpg
Figure 2-4

The arrow represents the movement vector of a character in a 2D platformer

In Unity, vectors are represented using specific data types. You can define a 2D vector by using Vector2 and a 3D vector by using Vector3.

You can declare them using their constructor as follows:
Vector2 my2DVector = new Vector2(x, y);
Vector3 my3DVector = new Vector3(x, y, z);

Vectors are at the core of every operation in an N-space, both in linear algebra and in Unity. For example, the position of an object is represented by a 3D vector as well as its scale value. Those two values can be modified via vector operations. Let’s take a quick look at the most important operations with vectors and their meaning in the video game context.

2.1.1 Addition

The addition between two vectors of the same type (e.g., two 3D vectors) is made by calculating the sum of the components of the two vectors as shown in Figure 2-5.
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig5_HTML.jpg
Figure 2-5

A graphical representation of the sum between two vectors A and B

So if, for example, you want to sum the two vectors [1, 2, 3] and [4, 5, 6], you just calculate the resulting vector [1+4, 2+5, 3+6] which is [5, 7, 9].

Since a vector can represent a point in space, the sum between two vectors is used to represent a movement from that point to a new point in the space. So, basically, when you sum a vector A to a vector B, the vector A is going to be the starting point, and the vector B is the offset that leads you to the new point C = A+B.

In Unity, you can sum two vectors by using the + (plus) operator like this:
Vector3 result = new Vector3(1,2,3) + new Vector3(4,5,6);

2.1.2 Subtraction

Subtraction between two vectors is pretty similar to addition. The only different thing is that the direction of the second element is reversed.

For example, if you want to calculate the difference between a vector A = [4,5,6] and a vector B = [1,2,3], you have to calculate the resulting vector C = A - B = [4,5,6] - [1,2,3] = [4,5,6] + [-1,-2,-3] = [4-1, 5-2, 6-3] = [3, 3, 3].

The subtraction between two vectors is used to find out the difference between them, which, in a spatial context, represents the distance between the two points represented by the two vectors.

In Unity, you can subtract two vectors by using the - (minus) operator like this:
Vector3 result = new Vector3(4,5,6) - new Vector(1,2,3);

2.1.3 Scalar Multiplication

As we said, a vector has a magnitude and a direction. The magnitude is the length of the vector.

To calculate the magnitude |V| of a vector V = [ a, b, c ], we apply the following formula:

|V| = $$ sqrt{{mathtt{a}}^{mathtt{2}}+{mathtt{b}}^{mathtt{2}}+{mathtt{c}}^{mathtt{2}} } $$

You can change the magnitude of a vector by just multiplying or dividing all the values of the vector by the desired quantity. Figure 2-6 shows a graphical representation of the scalar multiplication on a vector.
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig6_HTML.jpg
Figure 2-6

A graphical representation of a scalar multiplication on a vector

For example, if you want to double the magnitude of the vector V = [1, 2, 3] by a scalar value x = 2, you can just multiply each of V’s elements by x, like this: V*x = [1*2, 2*2, 3*2] = [2, 4, 6].

Similarly, if you want to reduce the magnitude of a vector W = [2, 4, 6] by a scalar value x = 2, you can just divide each of W’s elements by x, like this: W/x = [2/2, 4/2, 6/2] = [1, 2, 3].

2.1.4 Dot Product

Another important operation on vectors is the dot product. This is an algebraic operation you can execute on two vectors to get a scalar value. The result of a dot product between two vectors is the difference between the directions they’re facing.

Generally, the dot product is applied to normalized vectors, which are vectors of length 1. This is because when we want to calculate the difference between the directions of two vectors, we don’t care much about their length, but only about their direction.

When you apply the dot product to a couple of normalized vectors, the result is included in the range between 1 and -1. If the resulting value is 1, the two vectors face the same direction; if it’s 0, they are perpendicular; if it’s -1, they face opposite directions (Figure 2-7).
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig7_HTML.jpg
Figure 2-7

Dot product is very useful to calculate values like the brightness in a 3D space

One of the practical applications the dot product can have is to calculate the brightness on a surface based on the position of the light source. Let L be the light vector, which represents the position and direction of the light source, and N the vector representing the normal vector to a surface (meaning the vector perpendicular to a surface). Calculating B = L dot N will give us B as a float number representing the brightness of the surface of which N is the normal vector, where a value less or equal to 0 means darkness and a 1 means maximum brightness.

In Unity, you can calculate the dot product of the two vectors L and N we talked about in the previous example, using Vector3’s dot function like this:
float B = Vector3.Dot(N, L);

2.2 The First Project!

Previously, we said how vectors are used to represent positions and directions. Let’s put this in practice using Unity!

Open up Unity and create a new project by clicking the New button (Figure 2-8).
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig8_HTML.jpg
Figure 2-8

Create a new project in Unity Hub

From the template list, select the 3D project template and choose a name and a folder for your new project as shown in Figure 2-9, then click Create.
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig9_HTML.jpg
Figure 2-9

Create a 3D project in Unity Hub

Unity will set up a project for you in seconds.

When the project is created, you will be shown the classic layout with different sections dedicated to different parts of the project. Let’s explore the main ones! The following list refers to Figures 2-10 and 2-11:
  1. 1.

    Toolbar: It gives you access to some essential features like tools to manipulate the Scene View and the Game Objects in it, the buttons to run and stop the game as well as the step button to debug it, the buttons to access cloud services and versioning features.

     
  2. 2.

    Hierarchy Window: It shows the list of all the objects in the current scene. From the hierarchy panel, you can access every single object and modify their properties via the Inspector.

     
  3. 3.

    Inspector Window: The Inspector shows you all the details related to the asset currently selected. This window has not a standard view, as different kinds of assets have different kinds of properties.

     
  4. 4.

    Project Window: It’s basically an assets explorer showing and listing all the assets related to your projects. As new assets will be created, they will be shown in the Project window.

     
  5. 5.

    Scene View: It shows the selected scene and allows you to navigate it and edit the Game Objects within it. You can interact with the scene in the Scene View in 3D or 2D mode by selecting the corresponding button.

     
  6. 6.

    Game View: It allows you to see what your final rendered game will look like. Pressing the Play button, you can start the game in this view.

     
  7. 7.

    Console Window: It shows errors, warnings, and other messages generated by Unity or custom messages created by the programmer using the Debug.Log, Debug.LogWarning, and Debug.LogError functions.

     
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig10_HTML.jpg
Figure 2-10

The figure shows some important parts of the Unity Editor UI (find the explanations in the preceding numbered list)

../images/491049_1_En_2_Chapter/491049_1_En_2_Fig11_HTML.jpg
Figure 2-11

The figure shows some important parts of the Unity Editor UI (find the explanations in the preceding numbered list)

2.2.1 The First Scene!

In our first project, we want to explore the basics of vectors by creating an application that allows us to move an object around by modifying its position vector. The application will consist of a plane with a simple cube on it. Using the mouse, we can click different parts of the plane and change the position of the cube modifying its position vector.

As you may imagine, 3D objects are defined in a 3D space by the 3D position vectors of their vertices. In Unity, though, for simplicity, we will only need to modify a single vector called the pivot point. The pivot point is a vector associated with an object representing its position in the 3D space.

So, let’s get started by adding a couple of 3D objects to our starting Scene.

Right-click the hierarchy or the assets panel and select 3D ObjectPlane from the contextual menu. This will create a plane in the Scene.

Now, we want to change the position of our plane, so that we can have it exactly in the center of the scene. To do that, we need to modify the pivot point, which – as we just said – is a 3D vector. Left-click the plane in the Hierarchy window, and the info and properties of the object will be shown in the Inspector panel. Locate the Transform section and change the x, y, z properties to x = 0, y = 0, z = 0. This will snap our plane in the origin of the scene (Figure 2-12).
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig12_HTML.jpg
Figure 2-12

The plane object as seen in the Inspector

Tip

The origin is the point 0 of any N-space. In the case of a 2D space, like a Cartesian plane, the origin is at position x = 0, y = 0. In a 3D space, like our Scene in Unity, it’s at position x = 0, y = 0, z = 0.

Now create a cube in the same way, by right-clicking the assets or hierarchy panel and selecting 3D object cube. Select the cube by left-clicking it in the Hierarchy window to make its property be listed in the Inspector page. There, change the values of x, y, and z properties of the Transform position section to x = 0, y = 0.3, and z = 0 (Figure 2-13).
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig13_HTML.jpg
Figure 2-13

The Cube object as seen in the Inspector

Now that we have our 3D objects in place, the only thing we need is a good point of view! The visible scene, in a game, is defined by the Camera object, which is a GameObject that consists of many properties that allow you to show your game world from different points of view and with different graphic settings. Anyway, we won’t get too deep in this because it would take us too far from the scope of this book. The only thing we need to know is that a Camera allows us to define what we can see and how. Once again, the position of the camera is defined by a vector that we need to modify.

Select the Main Camera object in the Hierarchy window, navigate to the Transform Position section of the Inspector, and change its x, y, z properties to x = 0, y = 4, z = 0. In the Inspector, locate the Transform Rotation property and set x, y, and z to x = 90, y = 0, and z = 0 (Figure 2-14).
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig14_HTML.jpg
Figure 2-14

The Main Camera as seen in the Inspector

OK, now the scene is complete! We have the camera looking down at the plane with the cube in its center. We need now to add the functionality to make the cube move to the different positions at which we will point with the mouse. We can do this using C# scripting. Let’s see how!

2.2.2 The First Script!

As you know if you already worked with Unity, scripting is made by writing script files and assigning them to objects. Every script can implement standard functions that define the moment in which the actions are executed. What we want to do is to constantly check the position of the mouse, and if the user clicks, we want the cube to move to those coordinates.

Create the script by right-clicking the Project window and selecting CreateC# Script . Rename the script to Move. Now double-click the script to open the text editor and start writing the code.

The script you just created would contain this template code:
 1.   using System.Collections;
 2.   using System.Collections.Generic;
 3.   using UnityEngine;
 4
 5   public class Move : MonoBehaviour
 6   {
 7       // Start is called before the first frame update
 8       void Start()
 9       {
10
11       }
12
13       // Update is called once per frame
14       void Update()
15       {
16
17       }
18   }

Lines 1–3 are just lines to include some libraries and modules. The interesting part starts just after: a new class with the name of the file is declared inheriting from the class MonoBehaviour (line 5); this allows us to override some useful methods like Start (line 8) that is called every time the game starts and Update (line 14) that is called every frame. We can get rid of the Start function, as we won’t use it.

The plan is to wait for the user to click a point in the space and then read the coordinate of the mouse cursor and move the cube to those coordinates. To do that, we will make use of the raycasting technique, which is widely used in Unity for so many purposes. Every frame, we will cast a ray from the camera to the mouse position, and when the user clicks, we will calculate the position at which the ray collides with the 3D plane and move the cube to that position.

The first thing to do is to assign the script we just created to the cube object, so find that object in the Hierarchy window and select it by clicking it. The properties for that object will be shown in the Inspector. Now drag the Move script and drop it in the Hierarchy window showing the cube’s properties. That’s it! Now your script is associated to that object (Figure 2-15).
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig15_HTML.jpg
Figure 2-15

The Cube object as seen in the Inspector with all its settings listed

Now that the script is associated with the cube, we can start modifying it and adding the functionality. Double-click the script to open it up in your favorite editor/IDE and replace the content with the following code:
 1.   using UnityEngine;
 2.
 3.   public class Move : MonoBehaviour
 4.   {
 5.       private void Update()
 6.       {
 7.           RaycastHit hit;
 8.           Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
 9.           if (Physics.Raycast(ray, out hit) && Input.GetMouseButtonDown(0))
10.           {
11.               Vector3 newPosition = new Vector3(hit.point.x, this.transform.position.y, hit.point.z);
12.               this.transform.position = newPosition;
13.               Debug.Log("Current position vector: " + newPosition.ToString());
14.           }
15.       }
16.   }

This is the full code to add the functionality we talked about; let’s analyze it better!

We already saw the structure of the file, with the using statement and the class declaration. We won’t need the Start method, so we can just get rid of it. We will only need the Update method; let’s see how!

At line 7, we declare the hit variable of type RaycastHit. This is a structure used to get information from a ray collision against a Collider.

The idea is to cast a ray from the camera to the coordinates of the cursor in the moment the user clicks. The collision point between the ray and the first collider – in this case, the collider of the 3D plane – will be stored inside the hit variable. This will allow us to calculate the position we want the cube to move to.

At line 8, we create the ray variable of type Ray: this is the actual ray we are going to shoot from the camera to the mouse position via the function ScreenPointToRay passing as argument the position of the mouse contained in the vector Input.mousePosition.

At line 9, we call the Physics.Raycast(ray, out hit) function that casts the ray from the camera to the mouse position. That function returns true if the ray hit a collider, and the hit position is stored in the hit variable we passed to the function. In the same line, we also call the Input.GetMouseButtonDown(0) function that returns true if the mouse button indexed with 0 is pressed. As you can imagine, by default, the mouse indexed as 0 is the primary button: the left button; the right button is indexed as 1 and the middle button as 2. We put those two function calls in conjunction using the AND operator.; if both return true, we execute the instructions from lines 11 to 13.

At line 11, we create the new position vector using the x and z coordinates we found in the hit variable (the coordinates at which the ray hit the collider of the 3D plane) and for the y coordinate, we use the one of the cube object so we can keep it at the same height.

At line 12, we assign the position vector to the current object’s position, and at line 13 we print that information to the debug console using the Debug.Log function, just to see the position vector values changing.

Now that we have our very first script, we can now play the game and test it. Press the play button to compile and run the game. You will be presented with the scene and the cube at the center (Figure 2-16). Click any place in the 3D plane to move the cube there.
../images/491049_1_En_2_Chapter/491049_1_En_2_Fig16_HTML.jpg
Figure 2-16

Playing the game, you will start with the cube at the center. When you click a spot, the cube will move there

Now that we explored the vectors a bit also in practice, let’s take a step further. It would be nice to make the cube move toward the point we click, instead of just teleporting it there. Let’s see how we can do this.

2.2.3 Moving Toward a Point

In the previous section, we managed to move the cube instantly to a certain position that we selected with the click of the mouse. What we want to achieve in this section is to move it gradually toward the point selected in a certain amount of time. The basic difference is that instead of moving to that point all in one movement, the object will make several small steps toward the goal position.

We want to recreate the idea of movement in space from a point A to a point B in a certain span of time; to do that, we can use the concept of geometric translation.

Geometric translation is a geometric transformation that moves all the points of a figure or a space in the same direction. The movement is achieved by adding a constant vector to every point of the figure; that constant vector is the movement vector, which defines the point in space we want to reach.

In Unity, we have the Translate method of the Transform class that implements exactly the concept of geometrical translation. Every object in a scene in Unity has a Transform, which allows for storing and manipulating the position, rotation, and scale of the object.

We can translate an object in Unity using a movement vector like this:
myObject.transform.Translate(myMovementVector);

The movement vector is the amount of space in a certain direction that we want the object to traverse. We want the object to traverse a fraction of the space that divides it from the goal every time interval, but how can we calculate how much space should the object traverse for, let’s say, every second?

In Physics, the average space traversed by an object in a time interval moving at a certain speed is called Δs (delta space), and it’s described by the following formula:

Δs = vm * Δt

where vm is the average speed at which the object is moving and Δt is the amount of time in which the object moved of a quantity Δs (that we want to calculate).

So if our movement vector is Δs, to calculate it, we just need to multiply the average speed to the time interval.

The speed at which we want to move our object is an arbitrary quantity that we can make up. I will choose a value of 1, meaning that the object will move at 1 unit per second.

For the time interval Δt, we have a value provided to us by Unity that already has this information ready. This is Time.deltaTime, which is the difference between the last frame’s frametime and the current frame’s frametime.

Note

Frametime is the time it takes for a frame to be rendered. It’s a floating value and can be different frame by frame, depending on the complexity of the scene to be rendered. Of course, an inconstant average frametime value (meaning the average between all the frametimes for every frame) is a symptom of bad performances, since it may cause stuttering, ruining the experience for the player.

Time.deltaTime is expressed in seconds; this means that it also helps us represent the movement as the amount of space traversed per second at speed vm.

We can use this concept for our movement vector like this:
myObject.transform.Translate(0, 0, speed * Time.deltaTime);

We applied to transform.Translate a vector [0, 0, speed * Time.deltaTime] because we want the object to be moved forward.

We need just one bit! Since we are moving our object forward, we also need to make it turn toward the new position. To do that, Unity gives us a very handy function packed in the transform class: LookAt. We can use LookAt very easily, like this:
this.transform.LookAt(positionToLookAt);

where positionToLookAt is a Vector3 representing the point in space we want the object to turn toward.

Let’s see how we can apply those new information to our code:
 1.   using UnityEngine;
 2.   using System.Collections;
 3.
 4.   public class Move : MonoBehaviour
 5.   {
 6.       Vector3 goal;
 7.       float speed = 1.0f;
 8.       float accuracy = 1.0f;
 9.
10.       void Start()
11.       {
12.           goal = this.transform.position;
13.       }
14.
15.       void Update()
16.       {
17.           RaycastHit hit;
18.           Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
19.
20.           if(Physics.Raycast(ray, out hit) && Input.GetMouseButtonDown(0))
21.           {
22.               goal = new Vector3(hit.point.x, this.transform.position.y, hit.point.z);
23.           }
24.
25.           this.transform.LookAt(goal);
26.           if(Vector3.Distance(transform.position, goal) > accuracy)
27.           {
28.               this.transform.Translate(0,0, speed*Time.deltaTime);
29.           }
30.       }
31.   }

At lines 6–8, we define the variables we will use later in the code to define the goal position, the movement speed, and the accuracy. The accuracy is an offset value that we need to avoid the object to constantly do infinitesimal movement and instead use a more approximation-based movement. This means that if the object is close enough to that point, it will stop and the accuracy of this approximation is represented by the accuracy variable.

We restored the Start method, and we are using it to initialize the goal vector, which at the beginning stores the current position of the object (lines 10–13).

We already saw that we need to create the hit and ray variables (lines 17–18) to be used in the Physics.Raycast method (line 20). When the left mouse button is clicked, we are going to set the goal 3D vector with the coordinates taken from the hit variable, but keeping the current y coordinate (lines 20–23).

At line 25, we turn the object to face the new position we want to reach, and if the distance between the object and the goal is greater than the accuracy value we set (line 26), we use the Translate method to move the object toward the goal at the speed we defined (line 28).

Save the code and press the play button to test it! Now, when you click a point on the 3D plane, the cube will move little by little (depending on the speed you set) toward that point you clicked.

Here you are, you just created your first NPC walking toward a point!

We want to go one step further by making our cube rotate toward the goal gradually, just as we did with the actual movement. This concept is called steering, and it’s very much used in games to simulate the natural rotation of an object. Let’s see how it works!

2.2.4 Steering Behaviors

Steering behaviors are very important for nearly every kind of game and especially for simulation games like car games, and they are commonly implemented using the concept of linear interpolation. Without going too deep in the maths, linear interpolation between two points A and B calculates the points that take us from point A to point B. This concept can be applied to traverse the space from point A to point B as well as to rotate an object from an angle ɑ to an angle β.

There are two very popular techniques to implement linear interpolation to rotate an object:
  • Lerp (Linear intERPolation)

  • Slerp (Spherical Linear intERPolation)

The main difference between the two is that Lerp moves the object using a constant speed, while Slerp does it by using a variable speed. This variable speed is basically the effect of the object gradually accelerating after starting moving and then gradually slowing down when approaching the goal.

In Unity, we can use Slerp with the Quaternion.Slerp method as follows:
Quaternion.Slerp(startingRotation, goalRotation, rotationSpeed);
The function returns a fraction of the rotation needed to turn from startingRotation to goalRotation at speed rotationSpeed. Our startingRotation would be the value of the current rotation angle of the cube, while goalRotation must be calculated using the method LookRotation from the static class Quaternion. For example, if we want to calculate the rotation angle to turn in the direction of our goal position, we would do something like this:
Vector3 direction = goal - this.transform.position;
goalRotation = Quaternion.LookRotation(direction);

This all looks pretty easy, does it? Let’s use it in our script!

Open up Move.cs and let’s make some modifications! First, declare a float variable called rotSpeed to define the rotation speed of the object, just under the declaration of goal, speed, and accuracy:
float rotSpeed = 2f;
Then, delete the LookAt line and replace it with those two lines:
Vector3 direction = goal - this.transform.position;
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, Quaternion.LookRotation(direction), Time.deltaTime*rotSpeed);

Here, we are declaring a direction vector that tells us the distance and direction of the goal compared to the cube’s current position; then we use this information to calculate the rotation angle using the LookRotation method, and we pass this information to the Slerp method along with the current cube’s rotation value and the rotation speed times delta time.

The script should now look like this:
 1.   using UnityEngine;
 2.   using System.Collections;
 3.
 4.   public class Move : MonoBehaviour
 5.   {
 6.       Vector3 goal;
 7.       float speed = 1.0f;
 8.       float accuracy = 0.5f;
 9.       float rotSpeed = 2f;
10.
11.       void Start()
12.       {
13.           goal = this.transform.position;
14.       }
15.
16.       void Update()
17.       {
18.           RaycastHit hit;
19.           Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
20.
21.           if(Physics.Raycast(ray, out hit) && Input.GetMouseButtonDown(0))
22.           {
23.               goal = new Vector3(hit.point.x, this.transform.position.y, hit.point.z);
24.           }
25.
26.           Vector3 direction = goal - this.transform.position;
27.
28.           if (Vector3.Distance(transform.position, goal) > accuracy)
29.           {
30.               this.transform.rotation = Quaternion.Slerp(this.transform.rotation, Quaternion.LookRotation(direction), Time.deltaTime * rotSpeed);
31.               this.transform.Translate(0,0, speed*Time.deltaTime);
32.           }
33.       }
34.   }

Once again, let’s save the script and press Play! You will see that now the cube will gradually rotate toward the goal point while moving forward.

Good job! You just created your very first and basic algorithm to move an object from a point A to a point B! That’s an important foundation for what’s coming next: pathfinding!

In the next chapter, we will learn the foundations of pathfinding to allow our little cube to find its way toward the goal even with obstacles and no obvious path.

2.3 Test Your Knowledge!

  1. 1.

    What is a 2D space?

     
  2. 2.

    How are points defined in a 2D space?

     
  3. 3.

    What is a 3D space?

     
  4. 4.

    How are points defined in a 3D space?

     
  5. 5.

    What is a vector?

     
  6. 6.

    What is the difference between a 2D and a 3D vector?

     
  7. 7.

    What are the possible applications of vectors in video games?

     
  8. 8.

    How does vector sum work?

     
  9. 9.

    How does vector subtraction work?

     
  10. 10.

    What is scalar multiplication? How does it work?

     
  11. 11.

    What is dot product? How does it work? How can you use it in video games?

     
  12. 12.

    What is a geometric translation? How can you use it in a video game?

     
  13. 13.

    Explain the concept of steering behavior. Why is it important?

     
  14. 14.

    How can you implement a steering behavior in Unity?

     
  15. 15.

    Analyze the code we just wrote for this chapter’s project and locate all the places where we used (or Unity probably used under the hood) the vector operations we just learned.

     
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.54.7