Enemy Fires at player

In the previous lesson, we got the health scripts working for the enemy and the player. In this lesson, we'll get the enemy soldier to fire on the player.

 

Enemy Fire

We'll use the EnemyHealth script to make the soldier fire his gun. We could have created a new script, but let's keep the enemy behaviour all in one place. The first thing we'll do is to get that Gun Fire animation to play.

So, in your EnemyHealth script add back in the Update statement. Add this (you'll get red underlined for ShootAtPlayer):

private void Update()
{

if (currentHealth > 0 && isEnemyDead == false) {

ShootAtPlayer();

}

}

In the TakeDamage method, we have this if statement:

if (currentHealth <= 0 && isEnemyDead == false)
{
}

This checks if the current health of the soldier is equal to or less than zero AND if the isEnemyDead Boolean is false. If both are true then we play the Dying animation and set isEnemyDead to true.

In the Update method, we have a similar if statement:

if (currentHealth > 0 && isEnemyDead == false)

Now, we're testing if currentHealth is greater than zero. But we still need to check if isEnemyDead is false. If both of those are true then we call a ShootAtPlayer method. So, add this method to your code:

void ShootAtPlayer() {

gameObject.GetComponent<Animator>().Play("Shoot");

}

Nothing difficult here: we just play the Shoot animation. You EnemyHealth script should now look like this (we've removed the debug line):

Unity C# code for enemy health and a Shoot At Player method

Save your code and go back to Unity. If you play your game, you'll find that the Shoot animation plays OK. But there's a problem - the player is facing the wrong way!

Unity Game view with the soldier facing the wrong way

The problem is that the Root Transform Rotation of the animation is set to Body Orientation. So, in the Project area of Unity, click inside of your Soldier-Anim folder. Select your Shoot animation. In the Inspector, locate the Root Transform Rotation section. In the Based Upon (at Start) dropdown change it to Original:

Setting the body orientation of the model to the original pose

Play the game again and you should find that the soldier is firing and facing the right way - at you.

 

Enemy Gun Fire Code

We used a ray to make the player shoot. We can use the same principle to make the enemy shoot at the player. We'll add all the code to the EnemyHealth script. That way, it's all in one place.

So, go back to your EnemyHealth script. Add these variables to the top of your code, just below the two you have:

private int range = 30;
private bool canShootAtPlayer = true;
public AudioSource enemyFire;
public GameObject player;
private int damage = 10;

Now copy and paste all the following code over your ShootAtPlayer method:

void ShootAtPlayer()
{

Ray rayFrom = new Ray(transform.position, transform.forward);
RaycastHit hit;

if (Physics.Raycast(rayFrom, out hit, range))
{

if (hit.collider.CompareTag("Player"))
{

if (canShootAtPlayer)
{

StartCoroutine(FireGun());

}

}

}

}

IEnumerator FireGun()
{

canShootAtPlayer = false;

gameObject.GetComponent<Animator>().Play("Shoot");

enemyFire.Play();

player.GetComponent<PlayerHealth>().PlayerTakeDamage(damage);

yield return new WaitForSeconds(1.2f);

canShootAtPlayer = true;

}

Your EnemyHealth script should look like this, in your coding Editor:

Unity C# code to set up a raycast for the enmy soldier

Now let's go through the new parts, starting with the variables.

private int range = 30;
The range is how far the Soldier can shoot. You can change that to anything you like. But we've set it to an initial value of 30. This means that, if you place your soldier at the end of the corridor, he won't cause you any damage. It's only as you get within his range that he'll start to fire.

private bool canShootAtPlayer = true;
We don't want the Soldier to fire like a mad fella, so we've set up a Boolean called canShootAtPlayer. This is used to restrict how often the Soldier can fire.

public GameObject player;
We'll need to reference the player so that the enemy knows who to fire at. We do this with a GameObject variable called player.

private int damage = 10;
The amount of damage that the Soldier can cause the player is hard-coded to 10 points. But, again, you can change this to anything you like.

public AudioSource enemyFire;
This is an AudioSource type of variable. We'll drag and drop a gunshot sound here to use as the enemy gun fire.

 

The Update and TakeDamage methods are the same as before. The first bit of new code is the ShootAtPlayer method. The Shoot animation has been moved out of here and into the IEnumerator, which we'll get to shortly.

But raycasting is the same as we did for the player. For the player, we cast a ray out in a forward direction from the main camera:

Ray rayFrom = new Ray(mainCamera.position, mainCamera.forward);

This time, we cast if from the soldier:

Ray rayFrom = new Ray(transform.position, transform.forward);

The transform is all the positional values (X, Y, Z) from the Inspector. Because this script is attached to the Soldier, the transform means the transform of the soldier.

Physics.Raycast is used again. This time, we test if the tag the ray collided with is the player:

if (hit.collider.CompareTag("Player"))
{
}

Inside of the CompareTag if statement we have another if statement. This:

if (canShootAtPlayer)
{

StartCoroutine(FireGun());

}

We need to test if the Boolean variable called canShootAtPlayer is set to true. This variable stops the soldier from firing all the time. If it's true then we can start a coroutine called FireGun.

In the FireGun IEnumerator, we first set the canShootAtPlayer variable to false:

canShootAtPlayer = false;

Next, we play the Shoot animation. This has been moved to here from the ShootAtPlayer method. It's exactly the same, though:

gameObject.GetComponent<Animator>().Play("Shoot");

We play the gunshot sound for the soldier next:

enemyFire.Play();

The next line calls the PlayerTakeDamage method from the PlayerHealth script. The PlayerHealth script, remember, is attached to the player:

player.GetComponent<PlayerHealth>().PlayerTakeDamage(damage);

We then insert a pause of 1.2 seconds:

yield return new WaitForSeconds(1.2f);

However, you'll see a problem with this shortly.

Finally, we set canShootAtPlayer to true.

Make sure your code is saved. Now go back to Unity. To finish setting up, we'll need add an audio source.

We haven't created any audio sources yet. Let's do that now.

Right click on a blank area of the Hierarchy. From the menu that appears, select Create Empty: (Or click Game Object from the menu at the top of Unity. Select Create Empty from there.)

Unity Create Empty menu item

Name the empty object SFX. Now right-click on your new empty object and click Create Empty again from the menu. Call this one enemy-fire. Your Hierarchy should look like this:

A sound effect set up in the Hierarchy

Empty objects just have a transform. But you can add components to them. We'll add an audio source to our enemy-fire object.

Click on enemy-fire in the Hierarchy to select it. In the Inspector, click the Add Component button at the bottom. Add an Audio Source component. (You should know how to do this by now.)

Move inside of your Weapons of Choice folder again and drag and drop a gunshot sound onto the Audio Clip item in the Inspector. Also, uncheck Play On Awake:

Dragging and audio file onto an Audio Source component

Click on your Soldier item in the Hierarchy. Drag and drop the First person controller onto the Player slot in the Inspector:

Dragging a player character onto the Inspector in Unity

Drag and drop the enemy-fire item onto the Enemy Fire slot the Inspector:

Dragging an audio game object onto the Inspector

If you try it out now, the soldier firing and the sound from the gun might be out of sync. The soldier is firing to quickly to match the sound. You can slow down the animation, however.

Go back to your Animator tab. Click on your Shoot block to select it. In the Inspector on the right, notice that there is a Speed item:

The Animator window showing how to adjust the speed of an animation

The Speed value can be anything from 0 to 1. You can either type a new value here (try 0.4) or you can set the value with code.

If you want to set it with code, go back to your EnemyHealth script. Locate this line in the FireGun IEnumerator:

gameObject.GetComponent<Animator>().Play("Shoot");

Just above this line, add this:

gameObject.GetComponent<Animator>().speed = 0.4f;

But play your game. You should notice that the enemy doesn't fire on you immediately. That's because of the range value we set for the soldier (30). When you get within range, the soldier should start to fire, as in the short video below: (25 seconds)

 

Notice that the player can kill the soldier without moving. That's because, in the GunFire script, we set the player's range to a rather large value of 250. You might want to change it, though. Set it to the same value as the soldier, 30. Later, we're going to do pickups. You could have the player pick up a new gun and make the range of this gun larger than 30.

 

Now that the soldier can kill the player, it would be nice if we could see when the player is firing. In the next lesson, we'll add a muzzle flash to his gun.

<--Back to the Unity 3D Course Contents Page