Unity VR First Person Shooter
Creating Terrain
- Open Unity and create a new project called YourName-Unity-VR-FPS
- Go into the Assets store and search and download Mega Fantasy Props Pack. After the download is complete, click import.
- Create a new Terrain by right-clicking in the Hierarchy window then select 3D Object > Terrain
- Change the Terrain Width and Terrain Length of the terrain to 200:
 
- Under the Terrain component, we select the paintbrush from the tool bar to paint the texture.
- Add the grass_1_fixed_dtexture. You can do this by searching forgrass_1_fixed_din the Assets folder located in the Project window. Set the x and y size of the terrain to 1
- Add another texture called Dirt_1_fixed_d
- Select the dirt texture and the biggest brush to add a dirt patch. This is where we will put our buildings.
 
Adding Buildings
- Click on the Mega Fantasy Props Packfolder. Add buildings or props from thePrefabfolder. Be creative!
Setting Up Our Character
NOTE: Because this is a VR game, the MAIN CAMERA will be our player
- Go into the Hierarchy window and create an empty game object make sure nothing is highlighted in the Hierarchy window before you add the empty object!. Right click and select Create Empty. Rename itPlayerthen we’ll make our main camera a child of player.
- From the Hierarchy window, drag the Main Camerainto thePlayerso that Main Camera becomes the child of Player. Your Hierarchy should look like: 
- Set the Main Cameraposition to (0, 1, 0) and thePlayerposition to be (5, 1, 5)
- Add a Capsule Collidercomponent to thePlayergame object and set the height to 2
- Attach a RigidBodycomponent toPlayer
- Make sure the Playergame object is highlighted. Next, create a new script calledPlayerController. Delete everything in the script and add the following:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
   public float Speed = 3f;
   private Vector3 _movement;
   private Rigidbody _playerRigidBody;
   private void Awake()
   {
       _playerRigidBody = GetComponent<Rigidbody>();
   }
   private void FixedUpdate()
   {
       float horizontal = Input.GetAxisRaw("Horizontal");
       float vertical = Input.GetAxisRaw("Vertical");
       Move(horizontal, vertical);
   }
   private void Move(float horizontal, float vertical)
   {
       _movement = (vertical * transform.forward) + (horizontal * transform.right);
       _movement = _movement.normalized * Speed * Time.deltaTime;
       _playerRigidBody.MovePosition(transform.position + _movement);
   }
}
Rotating Camera
- In the Hierarchy window, select Main Cameraand add a new script component calledMouseCameraControllerdelete everything and add the following:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MouseCameraController : MonoBehaviour {
	public float Sensitivity = 5.0f;
	public float Smoothing = 2.0f;
	private Vector2 _mouseLook;
	private Vector2 _smoothV;
	private GameObject _player;
	void Awake () {
		_player = transform.parent.gameObject;
	}
	// Update is called once per frame
	void Update () {
		Vector2 mouseDirection = new Vector2 (Input.GetAxisRaw ("Mouse X"), Input.GetAxisRaw ("Mouse Y"));
		mouseDirection.x *= Sensitivity * Smoothing;
		mouseDirection.y *= Sensitivity * Smoothing;
		_smoothV.x = Mathf.Lerp (_smoothV.x, mouseDirection.x, 1f / Smoothing);
		_smoothV.y = Mathf.Lerp (_smoothV.y, mouseDirection.y, 1f / Smoothing);
		_mouseLook += _smoothV;
		_mouseLook.y = Mathf.Clamp (_mouseLook.y, -90, 90);
		transform.localRotation = Quaternion.AngleAxis (-_mouseLook.y, Vector3.right);
		_player.transform.rotation = Quaternion.AngleAxis (_mouseLook.x, _player.transform.up);
	}
}
Setting Up A Weapon
- In the Hierarchy window, select Main Camera. Next, create aCube3D Object and rename it toGun
- Change the Positionto (0.25, -0.5, 1) and theScaleto (0.25, 0.25, .5)
- In the Inspectorwindow remove theBox Collidercomponent from theGungame object. Your window should look like the following: 
- Select Gunnext, right click and selectEffects > Particle System
- Change the Particle Systemconfigurations to:
- Duration: 1
- Looping: unchecked
- Start Lifetime: 0.05
- Start Speed: 5
- Start Size: 1
- Start Color: Yellow
- Play Awake: unchecked
- In the Hierarchywindow selectMain Cameraand create a new script calledPlayerShootingControllerdelete everything and replace with:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerShootingController : MonoBehaviour {
	public float Range = 100;
	private Camera _camera;
	private ParticleSystem _particle;
	void Start () {
        _camera = Camera.main;
        _particle = GetComponentInChildren<ParticleSystem>();
        Cursor.lockState = CursorLockMode.Locked;
}
	void Update () {
		if (Input.GetMouseButton (0)) {
			Ray ray = _camera.ScreenPointToRay (Input.mousePosition);
			RaycastHit hit = new RaycastHit ();
			if (Physics.Raycast (ray, out hit, Range)) {
				print ("hit " + hit.collider.gameObject);
				_particle.Play ();
			}
		}
	}
}
- In the Hierarchywindow, make sure everything is deselected. Next, right-click and selectUI > Image. Rename the image toCrosshair
- In the Inspectorwindow change the Width and Height to 10. You should now have something that looks like: 
- Select Canvasand add aCanvas Groupfrom theInspectorwindow. DeselectInteractableandBlocks Raycasts
Creating An Enemy
- In the Hierarchywindow, make sure everything is deselected. Next, create a newCube3D Object. Rename it toEnemy.
- With Enemyselected in theHierarchywindow, create a new script calledEnemyHealth. Delete everything and replace with:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyHealth : MonoBehaviour {
	public float Health = 10;
	public void TakeDamage (float damage) {
		Health -= damage;
		if (Health == 0) {
			Destroy (gameObject);
		}
	}
}
- With the Enemyobject selected in theHierarchywindow. Go to theInspectorwindow and find theLayerdrop down and add a new layer calledShootable. Your window should now look like the following: 
- Go back to the PlayerShootingControllerscript and replace the code with the following:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerShootingController : MonoBehaviour {
	public float Range = 100;
	private Camera _camera;
	private ParticleSystem _particle;
	private LayerMask _shootableMask;
	void Start () {
		_camera = Camera.main;
		_particle = GetComponentInChildren<ParticleSystem> ();
		Cursor.lockState = CursorLockMode.Locked;
		_shootableMask = LayerMask.GetMask ("Shootable");
	}
	void Update () {
		if (Input.GetMouseButton (0)) {
			Ray ray = _camera.ScreenPointToRay (Input.mousePosition);
			RaycastHit hit = new RaycastHit ();
			if (Physics.Raycast (ray, out hit, Range, _shootableMask)) {
				print ("hit " + hit.collider.gameObject);
				_particle.Play ();
				EnemyHealth health = hit.collider.GetComponent<EnemyHealth> ();
				if (health != null) {
					health.TakeDamage (1);
				}
			}
		}
	}
}
- WHEN YOU GET TO THIS STEP CALL OVER AN INSTRUCTOR TO HELP YOU DOWNLOAD THE Mecanim Warrior AnimFOLDER FROM THIS REPOSITORY
- From the Assets Storesearch forWarrior Pack Bundle 1andStrong Knightdownload and import.
- In the Projectwindow, deselect everything, then create a new folder calledAnimation
- Right click the Animationfolder and selectCreate > Animation Controller. Rename the Animation Controller toKnight Controller
- Create 3 parameters: bool: IsPlayerNear, trigger:Death, trigger:Idle
- Drag the following animations into Animation Controller:
- death from Mecanim Warrior
- Attack1 from Brute Warrior Mecanim
- Idle from Brute Warrior Mecanim
- Run from Brute Warrior Mecanim
- WHEN YOU GET TO THIS STEP CALL OVER AN INSTRUCTOR TO HELP YOU WITH THE ANIMATIONS Your animation flow should look like. Right click on the button and select Make Transition. To create conditions click the arrow and a screen will appear in theInspectorwindow to create conditions:- Run => Attack (IsPlayerNear = true)
- Attack => Run (IsPlayerNear = false)
- Any State => Idle (Idle)
- Any State => Death (Death)
 
 
- Drag the Knightfrom the prefabs folder into the Scene. Next, drag theKnight Controllerto theKnightobject in theHierarchywindow.
- Add a Nav Mesh Agentcomponent to theKnight
- Open up the Navigation window by going to the top of the screen where File, Edit, Selection, Etc is located. Select Window > Navigation. The Navigation window will pop up in the same area asInspector
- In the Bakehit theBakeButton 
- With the Knightselected in the Hierarchy window, create a new script calledEnemyMovement. Delete and replace the script with the following:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyMovement : MonoBehaviour {
	private NavMeshAgent _nav;
	private Transform _player;
	void Start () {
		_nav = GetComponent<NavMeshAgent> ();
		_player = GameObject.FindGameObjectWithTag ("Player").transform;
	}
	void Update () {
		_nav.SetDestination (_player.position);
	}
}
- Click on Playerin theHierarchywindow and change the Tag in theInspectorwindow toPlayer
- Add a Capsule Collidercomponent to theKnightgame object and change these settings:
- Is Trigger is checked
- Y Center is 1
- Y Radius is 1.5
- Y Height is 1
Your screen should look like:
 
- Select the Knightin the Hierarchy window. Next, create a new script calledEnemyAttack. Delete and replace with the following script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAttack : MonoBehaviour {
	Animator _animator;
	GameObject _player;
	void Awake () {
		_player = GameObject.FindGameObjectWithTag ("Player");
		_animator = GetComponent<Animator> ();
	}
	void OnTriggerEnter (Collider other) {
		if (other.gameObject == _player) {
			_animator.SetBool ("IsNearPlayer", true);
		}
	}
	void OnTriggerExit (Collider other) {
		if (other.gameObject == _player) {
			_animator.SetBool ("IsNearPlayer", false);
		}
	}
}
Note: If the Knight stops attacking after the first time, check the attack animation clip and make sure Loop Time is checked.

- Add a Mesh Collidercomponent to theKnightgame object.
- Attach the bodymesh that our Knight uses to theMesh Collider 
- Click on Attack1in theAnimatorand the select theAnimationtab to open it
- Duplicate the Attack1by typingcmd+dand rename it toKnight Attack. Next, dragKnight Attackinto theAnimationfolder.
- Back in the Animatortab for the Knight Animator Controller, switch theAttack1state to use the newKnight Attackanimation clip instead of the previous one.
- In the EnemyAttackscript replace with the following:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAttack : MonoBehaviour {
	private Animator _animator;
	private GameObject _player;
	private bool _collidedWithPlayer;
	void Awake () {
		_player = GameObject.FindGameObjectWithTag ("Player");
		_animator = GetComponent<Animator> ();
	}
	void OnTriggerEnter (Collider other) {
		if (other.gameObject == _player) {
			_animator.SetBool ("IsNearPlayer", true);
		}
		print ("enter trigger with _player");
	}
	void OnCollisionEnter (Collision other) {
		if (other.gameObject == _player) {
			_collidedWithPlayer = true;
		}
		print ("enter collided with _player");
	}
	void OnCollisionExit (Collision other) {
		if (other.gameObject == _player) {
			_collidedWithPlayer = false;
		}
		print ("exit collided with _player");
	}
	void OnTriggerExit (Collider other) {
		if (other.gameObject == _player) {
			_animator.SetBool ("IsNearPlayer", false);
		}
		print ("exit trigger with _player");
	}
	void Attack () {
		if (_collidedWithPlayer) {
			print ("player has been hit");
		}
	}
}
Attacking Enemies & Health System
- Select Playerfrom theHierarchywindow and change changeDragin theInspectorwindow to 5.
- Drag the EnemyHealthscript toKnightin theHierarchywindow, Next, open the script and replace with the following:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyHealth : MonoBehaviour {
	public float Health = 10;
	private Animator _animator;
	void Start () {
		_animator = GetComponent<Animator> ();
	}
	public void TakeDamage (float damage) {
		if (Health <= 0) {
			return;
		}
		Health -= damage;
		if (Health <= 0) {
			Death ();
		}
	}
	private void Death () {
		_animator.SetTrigger ("Death");
	}
}
- In the EnemyMovementscript replace with the following:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyMovement : MonoBehaviour
{
    private NavMeshAgent _nav;
    private Transform _player;
    private EnemyHealth _enemyHealth;
    void Start ()
    {
        _nav = GetComponent<NavMeshAgent>();
        _player = GameObject.FindGameObjectWithTag("Player").transform;
        _enemyHealth = GetComponent<EnemyHealth>();
    }
    void Update ()
    {
        if (_enemyHealth.Health > 0)
        {
            _nav.SetDestination(_player.position);
        }
        else
        {
            _nav.enabled = false;
        }
    }
}