Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / game / Unity

Day 39 of 100 Days of VR: Creating a VR First Person Shooter II

5.00/5 (4 votes)
18 Nov 2017CPOL5 min read 5.1K  
How to create a VR first person shooter II

Welcome back to day 39!

Yesterday, we started to look at fixing problems that involved the limitation of Mobile VR (and a lot of raycasting). Today, we’re going to make some more changes. Specifically, the goal today is:

  1. Change our Event Trigger logic to deal with what happens if we’re holding down on the screen
  2. Fix a problem with our player being pushed around
  3. Fix why our Knight turns black
  4. Change our enemy to be slower to make the game easier

Let’s get to it!

Step 1: Changing Our Event Trigger Logic for Continuous Fire

Right now, we’re trying to solve the problem where we only damage the enemies when we tap on them. If we were to hold on, then we would continue to shoot, but the enemies won’t take damage.

Yesterday, we discovered that there were 2 ways we could have implemented our game.

  1. Use our existing code where we shoot a raycast and depending on what we hit, run some function.
  2. Use the Event Trigger system along with Google’s changes.

I’ve played around quite a bit with the Event Trigger system and made a solution, but it’s not the best, in fact, I might have preferred just keeping what we have, but that’s okay, we’re just learning!

There are 2 problems that we must solve:

  1. What happens when we’re holding down the screen on an enemy
  2. What happens when we’re holding down and then we move to point at another enemy

After playing around for a while, the PointerClick solution we have will no longer work.

Instead, I’ve started playing with the PointerEnter and PointerExit events.

I’m going to add the changes to EnemyHealth:

C#
using System;
using UnityEngine;
using Random = UnityEngine.Random;

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

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

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

    void Update()
    {
        _hitTime += Time.deltaTime;
        if (Input.GetButton("Fire1") && _isEnter)
        {
            TakeDamage(1);
        }
    }
	
    private void TakeDamage(float damage)
    {
        if (Health <= 0) { return; } if (_hitTime > HitSoundDelay)
        {
            Health -= damage;
            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;
        }
    }

    public void HealthEnter()
    {
        _isEnter = true;
        print("enter");
    }

    public void HealthExit()
    {
        _isEnter = false;
        print("exit");
    }
}

Walking Through the Code

In our EnemyHealth, we create 2 new functions:

  • HealthEnter()
  • HealthExit()

These functions are going to be called from the PointerEnter and PointerExit from our Event Trigger that we set up.

In these functions, we set a new variable we introduced called _isEnter so we know when they’re being selected.

  1. Inside Update(), we check to see if we’re currently hovering over the enemies and if we’re pressing down on the screen. If we are, we would call our already existing Shoot function.

    I’m not a fan of this method because it requires us to constantly call Update() in all of our enemy health scripts as opposed to just inside our PlayerShootingController script, but for just playing around, this is okay.

  2. I also changed the hit sound effect to be able to play every 0.1 seconds just like our shooting delay.

Step 1.1: Updating Our Event Trigger

Now that we have our shooting script in, the next and final thing we need to do is to create the Event Triggers to use them.

Get rid of the PointerClick event that we’ve previously set up. Instead, we’re going to create 2 new types of Event Triggers: PointerExit and PointerEnter .

Image 1

Here’s what we’re going to do:

  1. Attach HealthEnter() to PointerEnter
  2. Attach HealthExit() to PointerExit

Now we can play our game like we intended to do from the very beginning. Make sure to make these changes to the Bandit and Zombie too!

Step 2: Preventing Our Player from Falling

Currently, if we were to play the game, when an enemy gets closed to our player character, we would fall.

We should have addressed this in the past when we set constraints inside our RigidBody component, but it appears that we have not.

Let’s go back and fix this:

  1. In the hierarchy, select Player
  2. Under the RigidBody component, we’re going to set our constraints. Specifically, we want to freeze our position and rotation so that the enemies won’t push our character around. Having the game move us could cause nausea for our players.

Image 2

Step 3: Fixing Our Knight’s Color

If we were to play our game on our mobile device, we’ll notice one big problem. Our knights are all black.

If we pay attention to our log, we’ll see this:

Image 3

It seems that we have some problems with the shaders that the asset is using.

Unfortunately, I don’t know enough about this problem to resolve this. We have 2 choices:

  1. Ignore the problem and just have all black knights
  2. Change the materials that use these to use the standard shader.

In our case, we’re going to explore the 2nd option.

  1. In Assets/Knight/models/Materials, we have 3 materials that we’re using: clothColor, knight1Color, weaponsColor and all of them use one of those 2 shaders above. Let’s select them and change them to Standard.

Image 4

Now if we were to play the game on Unity, here’s what the knights would look like:

Image 5

It lost the coloring we originally had for it, but at least we keep the details of the models.

Step 4: Making the Game Easier

Currently, in our game, we would be getting swarmed with enemies. That would have been fine if we can move around, unfortunately, we can’t do that anymore, thus as a result, we need to make some adjustments.

We’re going to do 2 things:

  1. Change the rate of how long it takes for an enemy to spawn
  2. Slow down the rate our enemies move

Step 4.1: Changing Spawn Rate on the Spawn Manager

Currently, we spawn the next enemy every 2 seconds. Let’s change that to 5.

  1. Select the SpawnManager game object (child of GameManager )
  2. Set Time Between Enemies to be from 2 to 5

Image 6

Step 4.2: Changing Enemy Walking Speed

As we might recall, to control the enemy speed, we must look at the Nav Mesh Agent component in our enemy prefabs.

In order of speed, our speed order is Bandit, Knight, Zombie, with the Bandit being the fastest and Zombie being the slowest.

I’m going to change the speed a bit:

  1. Bandit to 2
  2. Knight to 1.5
  3. Zombie to 1

Here’s an example:

Image 7

Conclusion

Now we’re done! We have taken care of a lot of the technical problems that we encountered.

Tomorrow, we’re going to continue to finish the rest of the game by figuring out how we would add UI into a virtual reality environment.

Until then, I’ll see you all later on day 40!

Day 38 | 100 Days of VR | Day 40

Home

The post Day 39 of 100 Days of VR: Creating a VR First Person Shooter II appeared first on Coding Chronicles.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)