Вы находитесь на странице: 1из 36

Zombie Game

SUBMITTED BY
AMNA 2016-ag-7763
MARIAM HAFEEZ 2016-ag-7791
MOMINA SHAHID 2016-ag 7730

DEPARTMENT
COMPUTER SCIENCE

FACULTY
SCIENCE
SUBMITTED ON DATE
MAY 17, 2019
AMNA 2016-ag-7763

MARIAM HAFEEZ 2016-ag-7791

MOMINA SHAHID 2016-ag 7730


Table of contents:
1. Prefabricating an intelligent(ish) zombie

2. Zombie and the vision cone sprites

3. Adding Creating the waypoints the AI script to the zombie

4. Adding collision detection to the vision-cone game object

5. Building the Zombie Finite State Machine in Mecanim

6. Making a zombie prefab and adding some instances to the scene

7. Coding a controllable player

8. Making the camera follow the player


Introduction:
You can add hundreds of objects before even my fairly modest laptop start to
struggle. There are optimizations we could make to our code. The point is that our finite state
machine tracks the states and makes all the decisions for us. It might not be obvious how much
coding this is saving us. Think about the vast number of if statements that would be necessary to
replace what the state machine is doing. Furthermore, it is much less error prone. Click on a
zombie in the Scene view, switch to the Animator view and then run the game. You can see a
nice animation of the states and when they transition. This is very clear to debug when things
don’t behave as expected. The visual nature of the Animator is also really simple to add in extra
states.
Objectives:
We will do this in 6 stages as follows.

1. Create a game object in the scene from the zombie and view-cone sprites
2. Add an AI script to the zombie
3. Add a collision script to the view cone
4. Build a finite state machine to receive data from the AI
5. Add behaviors to the finite state machine to trigger the required behavior from the AI
script
6. Make a prefab from the finished zombie and add a whole bunch of them to the scene.

Introduction to environment:

Our environment of working is Visual Basics and working in C#.

C# is a more high-level approach than C++. It is usually faster to develop in. It comes with
a large framework of predeveloped components, which makes it particularly useful for server-
side programming. It is full of features that make development faster and easier, usually at the
cost of flexibility and/or runtime performance.

If MS goes bankrupt, C# is not dead: it is a standardized language, as are the core parts of
the framework. However, large parts of the .Net framework are still MS's own and in the
unlikely case that MS drops C#, there would probably be a significant loss of investment.
On the other hand, and though I'm not really knowledgeable about the subject, I'd guess Java
users would suffer more if Sun dropped out; in some ways at least.

Benefits:
 Learn To Code in C#

 Develop strong and transferrable problem solving skills


 Understand the capabilities of game development using Unity
 Gain an excellent knowledge of game creation

 Learn how object oriented programming works in practice.

 A good practice using UNITY and C#.

 It is a good sort of entertainment.

Finite State Machines & Unity Mecanim?

A finite state machine sounds complicated but at its simplest, it is just a way of keeping
track of the situation (state) of an object and the rules which determine when that state will
change.

If you want to build a finite state machine in code, there are dozens of tutorials out there
already. Unity, however, provides a neat visual way to build an AI using Mecanim, the
animation system built into Unity. If you are concerned that this tutorial is going to be some kind
of dirty hack where we use the game engine in a way it was not designed to be used then let me
assure you this is a legitimate use for Mecanim and as we will see the way we handle things like
behaviors and communication between a finite state machine and its related objects is completely
integrated into Unity. What you should be able to do by the end of this tutorial is implement your
own, more complicated AI using these same simple techniques.

What kind of behavior will our zombie have?

We will see how to set up a set of waypoints and then get our zombies to choose one at
random. The zombie will then set off towards it until it gets close and then it will pick another
one. This simple behavior will continue forever unless the player enters the zombie’s field of
view. Of course, the field of view is something we must define and we will do so with a triangle
shaped sprite to which we will attach a trigger collider. If the player enters the trigger, then the
zombie has “seen” the player. It would be simple to give the zombie more “sense” perhaps a
circle collider for hearing or smell.

When the player is seen by a zombie it will abandon its waypoint and home in on the player. If
the player escapes the zombies AI sight, the zombie will stop for a few seconds and then pick a
random waypoint and go back to doing what it was doing before lunch wandered into its
triangular field of view.

Take a look at this diagram read words in the rectangles that represent the states a zombie can be
in and also look at the lines connecting the states. You will see that each line has an arrow
indicating the direction that a state transitions from state to state as well as some notes I have
added indicating the parameters (variables of the state machine) that need to be true for the
transition to take place.

To explain the above, first of all, forget about the Exit and Any State states.When the state
machine starts it enters the Entry state and immediately and unconditionally transitions to the Get
New Waypoint state. When the Get New Waypoint state is entered it will communicate with the
zombie and the zombie will pick a new waypoint. At this point, the distance from the chosen
waypoint (distanceFromWaypoint) will be greater than one. This will cause a transition to
the Move To Waypoint state. The state machine will communicate this change to the zombie
object.

Every frame the zombie object will feed data into the state machine. One of these pieces of data
is its distance from the current waypoint. When this distance is less than one a transition occurs
back to the Get New Waypoint state and the zombie picks a new waypoint and sets off towards
it… until it is less than one unit away and so this continues.

If however, the player stumbles into the zombie’s vision (playerInSight is true) the zombie object
will let the state machine know and the state will change to Chase. The zombie’s behavior will
be modified by the state machine and a battle for life and death will ensue. In order to keep this
short enough for a single and functional tutorial, nothing happens when the zombie catches the
player. You would probably want to kill the player or subtract hit points, etc. In addition, you
would probably arm the player with a weapon etc.

If the player manages to escape the zombie’s sight then playerInSight will turn to false and the
state machine will transition to the Wait state. After the Wait state the state machine either goes
back to the Get New Waypoint state or if the player was careless enough to wander back into the
field of view then the Chase state will resume.
Methodology:
Starting the project
Scripts Create a new project in Unity, call it Zombie AI, choose the 2D option and click
the Create Project button.

Create some new folders to stay organized as we proceed. You need an FSM, Prefabs,
and Sprites, like this.
Import the three images below and keep them in the Sprites folder.

This is the graphic that will represent the controllable player

This is our Zombie graphic


The vision cone could have the Sprite Renderer component disabled so it is invisible. But it will
be useful to see it while we are testing.

To get started with the visuals grab yourself a fancy background from opengameart.org. Import it
into the Sprites folder, drag it into the scene and repeat, positioning the background like tiles
until you have covered a little bit more than the camera area. This step is not essential, the entire
project will work without a background; however with just a plain background, when we set the
camera to follow the player there will be a reduced sense of movement. One alternative if you
don’t want to bother with the background is to simply play your game while observing the scene
view which has handy grid-lines. Background or not, let’s move on to the project proper.

Here is what my Sprites folder looks like at this stage.


Let’s create some waypoints for the zombies to wander between.

Creating the waypoints

Next, we will create some waypoints that the zombies will randomly choose from to wander
between. Once you see the code, you will see you could just as easily make your zombies follow
a path of waypoints if you prefer.

Right click in the Hierarchy tab and select Create Empty. Now we have an empty object that is
not visible to the player during the game. We want to make it easy for us to see in
the Scene view, however. Rename the empty object to p1. Make sure that p1 is selected and in
the Inspector window give it an icon to make it clearer in the Scene view. You do so by clicking
this icon in the top-left of the inspector window.

Choose a new icon. I changed it to the red pill shape but you can choose whatever you prefer.
You can see the new empty game object in the Scene view as shown in the next image.

An Empty game object with a new icon to make it easy to see.


We will now add a tag to this game object so we can easily find it through C# code.

1. In the Inspector window select Tag | Add Tag


2. Click the + icon
3. Type p1 for the name of the new tag
4. Select p1 in the Hierarchy window, click Tag in the Inspector window and choose p1

The empty game object called p1 now has a nice clear icon and a tag called p1.

Repeat this process (empty object, icon, and tag)four more times and name them p2, p3, p4,
and p5. Actually, you can make as many or as few waypoints as you like but you will then need
to remember to vary the code as we proceed. Note that for this particular project to work all of
them must have a unique tag.

Arrange your waypoints around the scene. This is what my scene view looks like.

Now the zombies have some waypoints let’s get started with the zombies themselves.
Prefabricating an intelligent(ish) zombie

We will do this in 6 stages as follows.

1. Create a game object in the scene from the zombie and view-cone sprites
2. Add an AI script to the zombie
3. Add a collision script to the view cone
4. Build a finite state machine to receive data from the AI
5. Add behaviors to the finite state machine to trigger the required behavior from the AI
script
6. Make a prefab from the finished zombie and add a whole bunch of them to the scene

Let’s get started.

The zombie and the vision cone sprites

In the Sprites folder select vision_cone. Then, in the Inspector window click the Pivot button,
then choose bottom and click Apply. This has made the center-bottom(narrow part) of the cone
the pivot point for this sprite. This will make things work when we combine two sprites next.

Drag the zombie and the sight_cone sprites into the scene. Then in the Hierarchy view, drag
the vision_cone game object to be a child of the zombie game object. Set the X, Y and Z values
of the vision_cone‘s Transform component to 0,0,0. This will make
the vision_cone and zombie objects line up, just as we want them to.

This is what my Scene view looks like (zoomed in).


This is what your Hierarchy window should look like at this stage.

The vision_cone game object is a child of the zombie game object.

Add a Rigidbody 2D component to the zombie object and set it to Is Kinematic. We want the
zombie to move but not collide.

Now for the first of the C# code.

Adding the AI script to the zombie

Right click in the Scripts folder and select Create | C# Script. Name it ZombieAi. Code the script
as follows. Read through the code including the comments and then we can discuss it.

CODE:
1 using UnityEngine;

2 using System.Collections;

4 public class ZombieAi : MonoBehaviour {

6 // Where is the player


7 private Transform playerTransform;

10 // FSM related variables

11 private Animator animator;

12 bool chasing = false;

13 bool waiting = false;

14 private float distanceFromTarget;

15 public bool inViewCone;

16

17 // Where is it going and how fast?

18 Vector3 direction;

19 private float walkSpeed = 2f;

20 private int currentTarget;

21 private Transform[] waypoints = null;

22

23 // This runs when the zombie is added to the scene

24 private void Awake()

25 {

26 // Get a reference to the player's transform

27 playerTransform = GameObject.FindGameObjectWithTag("Player").transform;

28

29 // Get a reference to the FSM (animator)

30 animator = gameObject.GetComponent<Animator>();
31

32 // Add all our waypoints into the waypoints array

33 Transform point1 = GameObject.Find("p1").transform;

34 Transform point2 = GameObject.Find("p2").transform;

35 Transform point3 = GameObject.Find("p3").transform;

36 Transform point4 = GameObject.Find("p4").transform;

37 Transform point5 = GameObject.Find("p5").transform;

38 waypoints = new Transform[5] {

39 point1,

40 point2,

41 point3,

42 point4,

43 point5

44 };

45

46 }

47

48 private void Update()

49 {

50 // If chasing get the position of the player and point towards it

51 if (chasing)

52 {

53 direction = playerTransform.position - transform.position;

54 rotateZombie();
55 }

56

57 // Unless the zombie is waiting then move

58 if (!waiting)

59 {

60 transform.Translate(walkSpeed * direction * Time.deltaTime, Space.World);

61 }

62

63 }

64

65 private void FixedUpdate()

66 {

67 // Give the values to the FSM (animator)

68 distanceFromTarget = Vector3.Distance(waypoints[currentTarget].position,
transform.position);
69
animator.SetFloat("distanceFromWaypoint", distanceFromTarget);
70
animator.SetBool("playerInSight", inViewCone);
71

72
}
73

74
public void SetNextPoint()
75
{
76
// Pick a random waypoint
77
// But make sure it is not the same as the last one
78
int nextPoint = -1;
79

80 do

81 {

82 nextPoint = Random.Range(0, waypoints.Length - 1);

83 }

84 while (nextPoint == currentTarget);

85

86 currentTarget = nextPoint;

87

88 // Load the direction of the next waypoint

89 direction = waypoints[currentTarget].position - transform.position;

90 rotateZombie();

91 }

92

93 public void Chase()

94 {

95 // Load the direction of the player

96 direction = playerTransform.position - transform.position;

97 rotateZombie();

98 }

99

100 public void StopChasing()

101 {

102 chasing = false;


103 }

104

105 private void rotateZombie()

106 {

107 float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;

108 transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle - 90));

109 direction = direction.normalized;

110 }

111

112 public void StartChasing()

113 {

114 chasing = true;

115 }

116

117

118 public void ToggleWaiting()

119 {

120 waiting = !waiting;

121 }

122

}
Add the script to the zombie game object by selecting the zombie game object in
the Hierarchy window and clicking Add Component in the Inspector window. Now
choose Scripts | ZombieAi. This is how the code works.

At a glance, the code is long and sprawling but it really doesn’t hold too much that we haven’t
seen in other tutorials previously.

The variables initialized at the start include a Transform that will be used to track the position of
the player. The variables related to the state machine include an Animator. As we will see soon,
an Animator is a state machine. Each frame we will send values to the Animator/state machine.
These values are held in distanceFromTarget andinViewCone which will indicate how far away
a zombie is from its current waypoint as well as if the player is currently inside its trigger
collider. The chasing and waiting values do NOT get sent to the state machine. Rather, as we will
see, the state machine will update theses variables when appropriate. We then declare a bunch of
variables that will handle movement. A Vector3 called direction which keeps track of the
zombies heading, a float called walkSpeedwhich is how fast the zombie can move.
An int called currentTarget which indicates the position in an array which holds the Transform of
the current waypoint. The waypoints array into which we will load all the Transformcomponents
of our waypoints in the scene.
In the Awake method we use the tags of the waypoints and the player to get a reference to them.
All the waypoints are stashed in the waypoints array. The interesting thing that happens
in Awake is we initialize animator by getting a reference to an Animator component which is the
finite state machine we will soon build.
In Update there are just two if statements. If the zombie is currently chasing calculate the
direction to the player and turn to face him. If the zombie is not waiting just walk in whichever
direction it is facing. Note that thisdirection will have been previously set to a waypoint. This
implies that if the zombie is waiting it won’t move at all. We will see the rotateZombie method
soon.
In FixedUpdate is where the action happens. The first line of code calculates how far the zombie
is from the current waypoint then calls SetFloat and SetBool on animator to set the values
of distanceFromWaypoint andplayerInSight, inside the state machine. These two values will be
all that our finite state machine will need in order to make decisions and transition between
states.
At this point, we have not seen any way that the state machine can communicate back to the
zombie. We will get to the first part of the conundrum really soon.

Next up is the SetNextPoint method. SetNextPoint uses a do while loop to keep picking a new
position in thewaypoints array until it chooses one that is different to the current one. It then
alters direction and callsrotateZombie to do a little math to face the zombie in the correct
direction.
The Chase method sets direction relative to the player(rather than the next waypoint) then also
calls rotateZombie.
StopChasing does one thing. It sets chasing to false. When we build our state machine we will
see how it accesses this method in order to control how the zombie behaves. Note there is a
corresponding StartChasing method as well.
The RotateZombie method uses a trigomoteric function to calculate an angle to make the zombie
face where it is headed. If you want to know more about this then take a look at the tutorial series
on heading and trigonometric functions in games.
The last method, ToggleWaiting will also be called by the state machine to toggle the waiting
state of the zombie.

Adding collision detection to the vision-cone game object

Add a collider by selecting the vision-cone in the Hierarchy and clicking the Add
Component | Physics2D | Polygon Collider 2D. If you check the scene view you will see that a
nice neat collider has been added to the vision-cone object. Check the Is Trigger checkbox so
that we can code a script to respond to objects entering the perimeter of the collider.

Right click in the Scripts folder and select Create | C# Script. Name it ConeOnTrigger. Code the
script as follows

1 using UnityEngine;
2 using System.Collections;
3
4 public class ConeOnTrigger : MonoBehaviour {
5
6 public ZombieAi zombieAi;
7
8
9 void OnTriggerEnter2D(Collider2D o)
10 {
11
12 if (o.gameObject.tag == "Player")
13 {
14 zombieAi.inViewCone = true;
15 }
16 }
17
18 void OnTriggerExit2D(Collider2D o)
19 {
20
21
22 if (o.gameObject.tag == "Player")
23 {
24 zombieAi.inViewCone = false;
25 }
26 }
27 }
Add the script to the vision-cone game object by selecting the vision-cone game object in
the Hierarchy window and clicking Add Component in the Inspector window. Now
choose Scripts | ConeOnTrigger. This is how the code works.

The previous code has a reference to the zombie object. Every time the player either enters or
leaves the trigger theinConeView boolean variable is updated appropriately. Remember the value
of inConeView is sent to the state machine every frame during the FixedUpdate method in
the ZombieAi script. We can start to see all the pieces of how we talk to the state machine.
Now we get to build the finite state machine that will receive the inputs and initiate the behaviors
we have just coded.

Building the Zombie Finite State Machine in Mecanim

To get started let’s add a couple of components to the zombie game object.

Make sure the zombie object is selected in the Hierarchy then click Add Component in
the Inspector. Choose Miscellaneous | Animator. If you look closely at this new component you
will see a slot for a Controller. This is where we will add the finite state machine when we have
built it. Next, add another component to the zombie. Click Add Componentand choose Physics
2D | Rigidbody 2D. Set Gravity Scale to 0 to stop our zombie falling to oblivion and set it to Is
Kinematic. We want the zombie to move but not collide.
Let’s build the finite state machine in an animator controller. This sounds like a hack but it is a
totally legitimate way to program AI in Unity. Select Window | Animator from the Unity main
menu to create a workspace for this purpose. Dock the window (by dragging and dropping its
tab) somewhere you will have a large workspace. I docked mine in the same space as the Scene.

Right-click in the FSM folder and select Create | Animator Controller. Name the Animator
Controller ZombieFSM. Rearrange the states that are created for you like this following image.
Note this is not necessary it is just keeping things tidy.
Add the following states in the following order by right-clicking and selecting Create
State | Empty. You rename the states by selecting them in the Animator window and adjusting
the Name in the Inspector window.

 Get New Waypoint


 Move To Waypoint
 Chase
 Wait

Notice the first state you create is a different color and was automatically connected to
the Entry state. Rearrange your states to look like this next image. Notice we are already getting
close to how we envisioned our finite state machine at the start of the article.

Zombie finite state machine taking shape

Now we can add the two parameters and the transitions that their different values will trigger. To
add a parameter click Parameters in the top left of the Animator window and then click
the + icon. Add the following parameters as the following types.

playerInSight as a bool

distanceFromWaypoint as a float
Remember the FixedUpdate method in the ZombieAI class constantly updates these parameters.
Here is a reminder of the code which executes each frame.

private void FixedUpdate()


1
{
2
// Give the values to the FSM (animator)
3
distanceFromTarget = Vector3.Distance(waypoints[currentTarget].position,
4
transform.position);
5
animator.SetFloat("distanceFromWaypoint", distanceFromTarget);
6
animator.SetBool("playerInSight", inViewCone);
7
8
}
To add the transitions that values of these parameters will trigger we will start by adding the
transition links and then plug in the values after that. To create a transition right-click on the state
you are starting from, choose Make Transitionand then left-click on the state you want to
transition to. The direction is very important or our zombies will not behave as intended. Create
the following transition links.

Get New Waypoint to Move To Waypoint

Move To Waypoint to Get New Waypoint

Move To Waypoint to Chase

Chase to Wait

Wait to Chase

Wait to Get New Waypoint

Check you have the exact same state machine as shown in this image.
Zombie finite state machine with transitions links

Now we can plug in the values of the parameters that will initiate the transitions. Select the
transition that goes from Get New Waypoint to Move To Waypoint by left clicking it. Notice the
options that appear in the inspector window.

Uncheck Has exit time

Click the + icon of the Conditions option

Configure the new condition as distanceFromWaypoint Greater 1

This is how the inspector should look after you have done this.
The Has Exit Time option optionally delays the exit when the condition is true.
The Conditions is the actual condition that would cause this transition link to be made. So as the
zombie is closer than one unit to the current waypoint it will get a new waypoint. Fill out all the
rest of the transition parameters and exit times as detailed next.

 Move To Waypoint to Get New Waypoint: Uncheck Has Exit


Time. distanceFromWayPoint Less 1
 Move To Waypoint to Chase: Uncheck Has Exit Time. playerInSight = True
 Chase to Wait: Uncheck Has Exit Time. playerInSight = false
 Wait to Chase: Uncheck Has Exit Time. playerInSight = true
 Wait to Get New Waypoint: Check Has Exit Time and set
to 3.0 under Settings. playerInSight = False

We have so far seen how the ZombieAi class repeatedly updates the state machine with the
values it needs and we have just programmed how and when the state machine will step back and
forth between states. Now we can see how the state machine communicates back to the
ZombieAi class using behaviors.

Adding behaviors to the finite state machine

Behaviors are how the FSM communicates with the AI. In this project, the behaviors don’t
control HOW the AI does something they just choose WHICH ONE and WHEN.

To add a behavior we choose the state that we want to add a behavior to and then in the inspector
window click the Add Behavior button. We can add behaviors on numerous different events as
we will see.
Select the Get New Waypoint state and click Add Behavior. Choose New Script and
type SelectWaypointState in the Namefield. A new C# script has been added as a behavior. Open
the script and edit the code to look like this.

using UnityEngine;
1
using System.Collections;
2

3
public class SelectWaypointState : StateMachineBehaviour
4
{
5

6
// OnStateEnter is called when a transition starts and the state machine starts to evaluate this
7 state

8 override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int


layerIndex)
9
{
10
ZombieAi zombieAi = animator.gameObject.GetComponent<ZombieAi>();
11
zombieAi.SetNextPoint();
12

13
}
14

15
}

The first thing you will notice when you view the auto-generated script is there are a few more
methods. TheOnStateEnter method is called when the state is first entered. For this behavior, that
is exactly what we want. The code above, therefore, when the Get Next Waypoint state is entered
will get a reference to the appropriate instance of theZombieAi script and call
its SetNextPoint method. The ZombieAi script will take care of rotating the zombie and sending
it on its way.
Select the Chase state and follow the previous steps to create a behavior
called ChaseStateBehaviour. Edit the code to look like.
using UnityEngine;

1 using System.Collections;

3 public class ChaseStateBehaviour : StateMachineBehaviour {

5 // OnStateEnter is called when a transition starts and the state machine starts to evaluate
this state
6
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int
7 layerIndex) {

8 ZombieAi zombieAi = animator.gameObject.GetComponent<ZombieAi>();

9 zombieAi.StartChasing();

10 }

11

12

13 // OnStateExit is called when a transition ends and the state machine finishes evaluating
this state
14
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int
15 layerIndex) {

16 ZombieAi zombieAi = animator.gameObject.GetComponent<ZombieAi>();


17 zombieAi.StopChasing();
18 }
19

In the Chase state, we get to use both OnStateEnter and OnStateExit. When the state machine
first enters the state it calls StartChasing on the ZombieAi script which changes where the
zombie is pointed and where it moves to each frame. In OnStateExit the same method is called
which causes the zombie to revert to its previous behavior of wandering between waypoints.
Select the Wait state and follow the previous steps to create a behavior called WaitingStateBehaviour.
Edit the code to look like this
using UnityEngine;

1 using System.Collections;

3 public class WaitingStateBehaviour : StateMachineBehaviour {

5 // OnStateEnter is called when a transition starts and the state machine starts to evaluate
this state
6
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int
7 layerIndex) {

8 ZombieAi zombieAi = animator.gameObject.GetComponent<ZombieAi>();

9 zombieAi.ToggleWaiting();

10 }

11

12 // OnStateExit is called when a transition ends and the state machine finishes evaluating
this state
13
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int
14 layerIndex) {

15 ZombieAi zombieAi = animator.gameObject.GetComponent<ZombieAi>();


16 zombieAi.ToggleWaiting();
17 }
18

In the WaitingStateBehavior script the same methods are used as in


the ChaseStateBehavior script. When the state machine enters the Waiting state
the ToggleWaiting method sets the zombie into a motionless state and when the Waiting state is
exited it sets the zombie moving again. Remember this movement could either be towards the
player or towards a new waypoint, depending upon whether the player is currently visible.
Finally for this section of the tutorial, select the zombie object in the Hierarchy,
drag ZombieFSM from the FSM folder to the Controller field in the Inspector.
Select the vision-cone object in the Hierarchy and drag the zombie object to the Inspector and
drop it on the Zombie Aifield of the Cone On Trigger script.

We now have all the references in our scripts apart from the Player reference but we haven’t
made that yet.

Making a zombie prefab and adding some instances to the scene

Our zombie is almost done. Drag it from the Hierarchy to the Prefabs folder to create a prefab
from all of our hard work. Make sure the prefab has definitely been created in the Prefabs folder
and delete the zombie from the Hierarchy. Drag and drop a whole load of zombies from
the Prefabs folder into the scene.

Tip: If you can’t wait any longer, you could comment out the few lines of code
in ZombieAi.cs that refer to playerTransform(and are causing an error), run the game and see all
your zombies wandering around between the different waypoints.

We are so close now so let’s add the finishing touches.

Coding a controllable player

Get started by adding the player sprite to the scene. Add a tag called Player to the player object. If you
need a reminder how to do this then refer back to when we created the waypoints. Add a Ridgidbody
2D and set its Gravity Scale to 0. Next, add a Box Collider 2D. Now add a new script component
named PlayerController. Edit the script to be the same as this next code.

1 using UnityEngine;

2 using System.Collections;

4 public class PlayerController : MonoBehaviour {

6 private float speed = 4f;

8 // Update is called once per frame

9 void Update () {

10
11 // Quit if the player presses Escape

12 if (Input.GetKey("escape"))

13 Application.Quit();

14

15 // Get input from the keyboard or controller

16 float h = Input.GetAxis("Horizontal");

17 float v = Input.GetAxis("Vertical");

18

19 // Calculate the angle to rotate the player

20 Vector3 facing = new Vector3(h, v, 0);

21 float angle = Mathf.Atan2(facing.y, facing.x) * Mathf.Rad2Deg;

22

23 // Rotate the player

24 transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle - 90));

25

26 // Move the player

27 transform.Translate(facing * speed * Time.deltaTime, Space.World);

28 }

29

30 }

This is very straight forward code to move the player and make him face the appropriate
direction. Note that if you plug a controller into your PC/Mac you will get more refined rotations
and movements compared to just using the cursor keys. We have discussed simple movement in
several previous tutorials.
Making the camera follow the player

Select the Main Camera object in the hierarchy. Add a new C# script as a component in
the Inspector and name it FollowCamera. Edit the code to be the same as this.

1 using UnityEngine;

2 using System.Collections;

4 public class FollowCamera : MonoBehaviour

5 {

6 // Reference to the player's transform.

7 public Transform player;

9 void LateUpdate()

10 {

11 transform.position = new Vector3(player.transform.position.x,

12 player.transform.position.y, transform.position.z);

13 }

14 }

This script keeps a reference to the Transform component on the player so the camera follows
the player as it moves.
Finally, select the Main Camera object and drag the player to the slot on
the FollowCamera script.
Running the game
Run the game and observe it in the scene view if you didn’t bother with the fancy background or
the game view if you did.

You can add hundreds of objects before even my fairly modest laptop starts to struggle. There
are optimizations we could make to our code but that would be for another tutorial. The point is
that our finite state machine tracks the states and makes all the decisions for us. It might not be
obvious how much coding this is saving us. Think about the vast number of if statements that
would be necessary to replace what the state machine is doing. Furthermore, it is much less error
prone. Click on a zombie in the Scene view, switch to the Animator view and then run the game.
You can see a nice animation of the states and when they transition. This is very clear to debug
when things don’t behave as expected. The visual nature of the Animator is also really simple to
add in extra states.
RESULT:

SCREENSHOT:

PROJECT COMPLETED

Вам также может понравиться