Day 29 of 100 Days of VR: Spawning New Enemies in Unity and Dealing With “Ghost” Colliders

Josh Unity VR Development Leave a Comment

Welcome back to day 29!

Yesterday we finished creating our final enemy that we’re going to use for the game.

Now that we have everything ready, it’s time to use them!

After finishing the spawn system and played the game for a bit, I noticed a small problem.

Sometimes when we shoot, the enemy doesn’t get hit. This becomes obvious when we try to switch the health of our enemy to be 1.

Our goals today are:

  1. Start spawning all 3 of our enemies
  2. Fix the shooting bug

Without any delays, let’s get started!

Step 1: Spawn our new enemies

Setting up the spawning system with our new enemies is simple, we already have the SpawnManager script to take care of spawning enemies every wave.

Let’s add them in!

In our hierarchy, look at GameManager > SpawnManager and to find our SpawnManager script.

Set our Waves size to be 3.

We want to spawn:

  1. 5 Knights at Wave 1
  2. 5 Bandits at Wave 2
  3. 5 Zombie at Wave 3

When we’re done, we’ll have something like this:

Now we can play the game and we’ll be able to fight all of our new enemies on the map!

Here might be something we’ll see!

You might notice that after we win, our gun doesn’t stop shooting and our shooting sound doesn’t stop.

Not today, but some other day, we will go in and disable all of those when the player wins.

Step 2: Solving the Mystery Missing Shot

Now that we’re spawning enemies and playing the game, we might encounter a very weird problem.

When we’re shooting an enemy, sometimes they don’t get hit.

I’m not talking about a long distance either, I’m talking very close proximity. What’s happening?

After digging around for a bit, I found the problem: our raycast is still hitting the mesh collider of our dead enemies.

As we have discussed in Day 20 the Mesh Colliders that we attach to our enemy doesn’t follow the form of our enemies. They’re just still there, as you can see from the image above.

What’s happening here is that even though we defeated our enemies, their mesh collider is blocking our shots from hitting other existing enemies.

But it’s okay, we can fix this. We must disable all colliders attached to the enemy when they die.

Step 2.1: Disabling our Colliders in Code

Now, let’s think, where would we know when the enemy is dead? In the EnemyAttack script!

In EnemyAttack we have a function called Death() that takes care of everything when the enemy dies.

Let’s use that:

using UnityEngine;

public class EnemyHealth: MonoBehaviour
{
    public float Health = 100;
    public AudioClip[] HitSfxClips;
    public float HitSoundDelay = 0.5f;

    private SpawnManager _spawnManager;
    private Animator _animator;
    private AudioSource _audioSource;
    private float _hitTime;

    void Start()
    {
        _spawnManager = GameObject.FindGameObjectWithTag("SpawnManager").GetComponent<SpawnManager>();
        _animator = GetComponent<Animator>();
        _hitTime = 0f;
        SetupSound();
    }

    void Update()
    {
        _hitTime += Time.deltaTime;
    }
    
    public void TakeDamage(float damage)
    {
        if (Health <= 0) { return; } Health -= damage; if (_hitTime > HitSoundDelay)
        {
            PlayRandomHit();
            _hitTime = 0;
        }

        if (Health <= 0)
        {
            Death();
        } 
    }

    private void SetupSound()
    {
        _audioSource = gameObject.AddComponent<AudioSource>();
        _audioSource.volume = 0.2f;
    }

    private void PlayRandomHit()
    {
        int index = Random.Range(0, HitSfxClips.Length);
        _audioSource.clip = HitSfxClips[index];
        _audioSource.Play();
    }

    private void Death()
    {
        _animator.SetTrigger("Death");
        _spawnManager.EnemyDefeated();
        foreach (Collider collider in GetComponentsInChildren<Collider>())
        {
            collider.enabled = false;
        }
    }
}

New Variables Used

None

Walking Through the Code

There’s only one major change that we did and that’s in Death() where search through all of the enemy’s child game objects looking for any collider component. If a collider is found, we would just disable it.

One interesting thing to note is that we’re looking for anything of type Collider. We’re more used to finding something of exact type, for example, GetComponent<SpawnManager>();

However, taking advantage of the fact that all of the Colliders: Box Collider, Mesh Collider, Capsule Collider, etc all extend from the Collider parent class, they’re all considered of type Collider. What that means is that we can do what we did in Death() and look for anything that is of type Collider or inherits the class.

Now after we added the code, if we play the game, we’ll see that dead enemies no longer have their Colliders on anymore:

There are things that are sometimes better off staying dead.

Conclusion

That’s it for today! Today, we incorporated the rest of our enemies to the game and we even went in to fix “ghost” mesh colliders that prevented us from shooting properly.

I think we’re going to work on one more feature before I start moving on to the actual VR portion of this series, and that’s making a point system!

In our current game, we win and that’s it. There’s no replay value at all!

Tomorrow we’re going to start making this game more interesting by adding a scoring system!

With that all being said, it’s getting late, I’m headed out!

Day 28 | 100 Days of VR | Day 30

Home

Subscribe To Our Weekly Newsletter!
Like these coding articles? Join my mailing list for the latest updates and influence the code that I write!
We hate spam. Your email address will not be sold or shared with anyone else.

Leave a Reply

Your email address will not be published. Required fields are marked *