Unity 2020 Virtual Reality Projects
上QQ阅读APP看书,第一时间看更新

Scripting a random walk target

Our goal is to make Ethan walk to random positions in the scene. To do this, we'll write a script that moves the WalkTarget object to random positions. Ethan will follow it. Writing scripts is an important part of developing with Unity. If you've done anything more than tinker with Unity, you've probably already written at least some scripts. We're going to use the C# programming language to do this.

If you are new to programming, don't panic! We'll provide a general introduction to Unity scripting at the end of this chapter. You can jump to that now and come back if you wish, or just follow along.

For this first script, we'll take it slow. We will attach the script to the WalkTarget object. To do that, follow these steps:

  1. Select the WalkTarget object in the Hierarchy window.
  2. In its Inspector panel, click on the Add Component button.
  3. Select New Script (you may need to scroll down to find it).
  4. Name it RandomPosition.
  5. Click onCreate and Add.
  6. This should create a script component on the WalkTarget object. Double-click on the RandomPosition script slot, as shown here, and open it in your code editor (for example, Visual Studio):

We want to move the WalkTarget object to a random location so that Ethan will head in that direction, wait a few seconds, and move the WalkTarget object again. That way, he'll appear to be wandering around aimlessly. We can do this with a script. Rather than developing the script incrementally, I'm presenting the finished version first, and we'll go through it line by line. The RandomPosition.cs script looks like this. Type or paste the following code into Visual Studio for the RandomPosition.cs file:

using System.Collections;
using UnityEngine;

public class RandomPosition : MonoBehaviour {
void Start() {
StartCoroutine(RePositionWithDelay());
}

IEnumerator RePositionWithDelay() {
while (true) {
SetRandomPosition();
yield return new WaitForSeconds(5f);
}
}

void SetRandomPosition() {
float x = Random.Range(-5.0f, 5.0f);
float z = Random.Range(-5.0f, 5.0f);
Debug.Log("X,Z: " + x.ToString("F2") + ", " +
z.ToString("F2"));
transform.position = new Vector3(x, 0.0f, z);
}
}

This script defines a MonoBehaviour subclass named RandomPosition. The first thing we do when defining a class is declare any variables that we'll be using. A variable is a placeholder for a value. This value can be initialized here or assigned elsewhere, as long as it has a value before the script uses it.

The meat of the script is further down, in the function named SetRandomPosition(). Let's see what that does.

As you may recall, the GroundPlane plane is 10 units square, with the origin in the middle. So, any (x, z) location on the plane will be within a range from -5 to 5 along each axis. The line float x = Random.Range (-5.0f, 5.0f) picks a random value within the given range and assigns it to a new float x variable. We do the same thing to get a random z value.

The line Debug.Log ("X,Z: " + x.ToString("F2") + ", " + z.ToString("F2")) prints the x and z values in the Console panel when the game is running. It'll output something like X, Z: 2.33, -4.02 because ToString("F2") says round up to two decimal places. Note that we're using plus (+) signs to combine the parts of the output string.

We actually move the target to the given location with the line transform.position = new Vector3 (x, 0.0f, z);. We're setting the transform position of the object that this script is attached to. In Unity, values that have X, Y, and Z coordinates are represented by the Vector3 objects. So, we create a new one with the x and z values that we generated. We set y=0 so that it sits on GroundPlane.

The last mysterious bit is how we handle time delays in Unity, which is by using coroutines. A coroutine is a piece of code that runs separately from the function in which it was called. This is a somewhat advanced coding technique, but very handy. In our case, the transform position should get changed once every 5 seconds. It's solved in the following ways:

  • In the Start() function, there's the line StartCoroutine (RePositionWithDelay());. This line starts the RePositionWithDelay() function in a coroutine.
  • Inside the coroutine function, there's a while (true) loop, which, as you might have guessed, runs forever (as long as the game object is enabled).
  • It calls the SetRandomPosition() function, which actually changes the object's position.
  • Then, at the bottom of this loop, we do a yield return new WaitForSeconds (5f); statement, which basically says to Unity, hey, go do what you want for 5 seconds and then come back here so that I can go through my loop again.
  • For all of this to work, the RePositionWithDelay coroutine must be declared as the IEnumerator type (because the documentation says so).
This coroutine/yield mechanism, although an advanced programming topic, is a common pattern in time-sliced programs such as Unity. For more details about coroutines and yield statements, visit the Unity Manual ( https://docs.unity3d.com/Manual/Coroutines.html) and tutorial ( https://learn.unity.com/tutorial/coroutines).

Save the script in Visual Studio (File | Save). We are now good to go. Return to the Unity editor and click on Play. Ethan is running from one place to another like a madman! OK, that's pretty random.

As you may have noticed, Ethan seems to be hovering above the ground – or sinking below – the capsule collider. To edit the collider, use the Edit Collider button on Ethan's Capsule Collider component and adjust the bottom node. Alternatively, you may need to add a Height Mesh to the NavMesh. In the Navigation window's Bake tab, under the Advanced options, check the Height Mesh checkbox and then Bake it again.

In summary, we have added a third-person AI controller to the scene and made him walk around to random positions. The RandomPosition script we just wrote moves the target position to random new locations. However, he looks more like a spaceman athlete rather than a zombie. Let's fix that.