Implementing waypoints – the second/dynamic way

In this section, we will explore a second way to implement the waypoint system of our game. Of course, the outcome will be the same, but this approach offers many other advantages. First of all, it's easier for designers to collocate, change, move, and replace waypoints within the map itself. Second, it allows a great flexibility in behaviors, which can be implemented in such a way to make it easier for designers to use the script created. We will exploit some of the potentiality of this system later in the last chapter of the book.

Nonetheless, this approach does suffer from some drawbacks, as with every choice in life. In particular, the complexity of the system increases. Moreover, it uses a different game object for each one of the waypoints, and this is critical if the number of waypoints is really high.

Note

To overcome this last problem of having different game objects for each of the waypoints, we have many possibilities, but making each one of them work is a challenge and at the same time, easy for designers to use. In fact, waypoints can still be stored as a list, not as positions this time, but rather of the waypoint class, and at the same time expose functionalities to allow designers to edit and place them within the Scene view. This is left as a challenge in the Homework section.

Implementing waypoints as separate entities

So far, we have seen a simple implementation of the waypoints. Now, we will implement them again, but this time as separate entities. As such, in Chapter 8, What Is beyond the Cake?, we will explore how to unlock the potential of waypoints in a game. In fact, at the end of this section, the effect on our game will be the same; however, we will change the script in Chapter 8, What Is beyond the Cake?, by implementing more features.

First of all, we need to erase the waypoints variable from the GameManagerScript (but don't erase the script, even if it is empty, because we will use it; for the same reasons, don't erase the gameManager variable from the PandaScript).

Now, we need to create a new script, which will be the actual waypoint. As such, we can rename it as Waypoint.

We need a variable of the same class to store the next waypoint. In this way, each waypoint will be able to point/reference towards another waypoint. The goal is to build a chain which the Pandas will follow. Since the variable is private but we still need to have access to it in the Inspector, we need to add the serializable property. So, we can add the following to our script:

//Private variable to store the next waypoint in the chain 
//It is serializable, so it can be set in the Inspector 
[SerializeField] 
private Waypoint nextWaypoint; 

Now, from the waypoint, a Panda would like to retrieve its position and the next waypoint to follow, once the current one is reached. To achieve this, we can expose two functions from our Waypoint script.

The GetPosition() function will return a Vector3 with the position of the waypoint, which (in this specific implementation) is stored in the Transform of the waypoint. The code is the following:

//Function to retrieve the position of the waypoint 
public Vector3 GetPosition() { 
  return transform.position; 
} 

The GetNextWaypoint() function, instead, will return just the next waypoint (at least for the moment), stored in the nextWaypoint variable. In fact, the nextWaypoint variable is private, and so Pandas need a function to retrieve it. Therefore, we can just write the following:

//Function to retrieve the next waypoint in the chain 
public Waypoint GetNextWaypoint() { 
  return nextWaypoint; 
} 

We have finished with this script for now, so we can save it.

The next step is to create a Prefab for our waypoints. Create an empty GameObject and attach the Waypoint script. Then, in the Project panel, create a Prefab called WaypointPrefab and drag and drop the empty GameObject you have created. Finally, erase the empty GameObject from the scene, since now we have our Prefab.

Drag and drop as many Prefabs as the number of waypoints you have identified; in our example, there are 11. For your convenience, I suggest you rename them in a progressive order, as shown in the following screenshot:

Implementing waypoints as separate entities

Now, we need to link them to each other. In particular, waypoint1 will be linked to waypoint2, which will be linked to waypoint3, and so on. For instance, waypoint4 should look linked in the Inspector as follows:

Implementing waypoints as separate entities

The only exception is in the last waypoint, which has nothing in the nextWaypoint variable, as shown in the following screenshot:

Implementing waypoints as separate entities

Finally, we need to place them at the coordinates we have identified in the Getting the waypoint coordinates section. To quickly recognize them, I recommend that you add a Gizmo icon. As the name suggests, a Gizmo is an icon that will be shown in the Scene view to quickly and easily recognize specific objects, but won't be visible once the game is built. Recently, Unity added also the possibility to see them within the Game view.

The easiest way to insert a Gizmo is by clicking the cube-shaped icon next to the name of the GameObject, highlighted in the following screenshot:

Implementing waypoints as separate entities

Note

The same holds for Prefabs, but their icon is a blue cube.

Once you have clicked on this icon, a menu appears as shown in the following screenshot:

Implementing waypoints as separate entities

By selecting one of the ellipse-shaped icons, you will place a label to the object with its name in it. We will choose one of these for our waypoints. If you click on the circle-shaped or crystal-shaped icons, the Gizmo will look like a circle or a crystal, without any text. If you click the Other… button, you can use your own graphics.

Note

A more complex way to insert Gizmos is through scripting. In fact, there is a special function called OnDrawGizmos() which is called by Unity when rendering Gizmos is enabled. Within this function, you are able to use any of the functions listed at https://docs.unity3d.com/ScriptReference/Gizmos.html, which allow you to draw shapes on the screen. This is a very powerful tool, because it can enhance tremendously the usability of your scripts. For instance, in our specific case of waypoints, we could draw the path that Pandas will follow. This is left as an exercise in the Homework section.

In our case, we can select one of the ellipse-shaped icon for all the waypoints. As a result, we are able to see them in the Scene view (even if they don't have any explicit rendering component and thus they won't be visible in any way in the final game) and quickly place them.

At the end, your Scene view should look like the following:

Implementing waypoints as separate entities

Now, we need to specify to the game, which one of these waypoints is the first of the chain. As such, we can store this information within the Game Manager. So, let's add the following variable to the GameManagerScript:

//The first waypoint of the chain 
public Waypoint firstWaypoint; 

Finally, after having saved the script, set the variable in the Inspector, as shown in the following screenshot:

Implementing waypoints as separate entities

In conclusion, we have created a chain of waypoints, which is exactly what we need for our game. However, we still need to define how the Pandas get to them.

Moving along the designed path – dynamic

The next step is to slightly modify the PandaScript to take care of this new waypoint system. So, let's open the script again.

First, we need to substitute the integer variable, currentWaypointNumber, with a proper waypoint variable, as shown here:

//Private reference to the current waypoint 
private Waypoint currentWaypoint; 

Then, we need to initialize this new variable; we can do it in the Start() function, by retrieving the first waypoint from the Game Manager, as shown here:

//Get the first waypoint from the Game Manager 
currentWaypoint = gameManager.firstWaypoint; 

Then, in the first check of the FixedUpdate() function, we need to check if the variable itself is null (which means that the Panda has reached the cake, because the last waypoint will return a null pointer). Here is the code, with the modified parts highlighted:

if (currentWaypoint == null) { 
  animator.SetTrigger(AnimEatTriggerHash); 
  Destroy(this); 
  return; 
} 

Going on in the FixedUpdate() function, we need to change how the distance is calculated, by using the GetPosition() function of our waypoint in the following way:

float dist = Vector2.Distance(transform.position,
  currentWaypoint.GetPosition()); 

Finally, we need to change the last if statement of the FixedUpdate() function to get the next waypoint when the previous one is reached. We also need to decide which parameter we should give to our MoveTowards() function. Again, the modified parts are highlighted:

if(dist <= changeDist) { 
  currentWaypoint = currentWaypoint.GetNextWaypoint(); 
}else { 
  MoveTowards(currentWaypoint.GetPosition()); 
} 

Save the script. We have finished this second way of implementing waypoints. Chapter 8, What Is beyond the Cake?, will suggest some ways to take advantage of this structure to implement more complex behaviors.

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

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