Select Page
Game Design
Class 14: Game Modification

Topics

  • Game Modification
  • First Person (customization) Demonstration
  • 3D First Person Shooter Project

Class 14 says hello

Game Modification

Game Modification:

Most first person shooter games are generally the same. Usually they add some sort of mechanic and/or style to separate it. One small change can make a large difference.

First Person (customization) Demonstration

This is what we are making today

You may download the Unity project here.

Assets

Environment
Terrain
The ground that is sculpt through a heightmap
Trees/Details
Trees and other details such as rocks are placed on the terrain
Other assets
Other geometry is imported such as buildings and water. A skybox is imported
Game Controller
This will control the game for now it will spawn the enemies
Characters
Player
First person controller
Enemies
Zombies that will seek you out and damage you

We do not have finalized graphics but a good start.

Scripts

New Scripts
AnyScriptYouAdd
Research online for other game mechanics you may add
Old Scripts
PlayerControllerScript
Script that controlls the player functions
EnemySpawnScript
Will spawn the enemy wherever it is place at a rate given
GameControllerScript
Handles level loading mostly
PlayerStatsScript
Keeps track of the player health, kill count, etc.
EnemyControllerScript
Directs the enemy towards the player and attacks
PlayerControllerScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerControllerScript : MonoBehaviour
{
    private LayerMask enemyMask = 1 << 10;

    public float nextFire = 0.0f;
	public float fireRate = 0.5f;
	public float damageAmt = 25.0f;
	public float knockBackAmt = 250f;

	public Transform shootPos;

	public GameObject hitSpawn;
	EnemyControllerScript enemyControllerScript;

	public LineRenderer line;

	Ray shootRay;
	RaycastHit hit;
	bool shootResult;
	GameObject spawnedHit;

	void Update () 
	{
		if(Input.GetButton("Fire1") && Time.time > nextFire)
		{
			Shoot(shootPos.position, shootPos.forward);
			nextFire = Time.time + fireRate;
		}
	}

    void Shoot (Vector3 origin, Vector3 direction)
    {
		shootRay = new Ray (origin, direction);
		Debug.DrawRay (shootRay.origin, shootRay.direction * 3f, Color.red, 1f);

		line.enabled = true;

		line.SetPosition(0, new Vector3 (origin.x -.25f, origin.y -.25f, origin.z  + .1f));
		line.SetPosition(1, shootRay.GetPoint (100));

		StartCoroutine(ShootLine());

		shootResult = Physics.Raycast (shootRay, out hit, 50f);
		if (shootResult) 
		{
			spawnedHit = Instantiate (hitSpawn, hit.point, Quaternion.identity);
			StartCoroutine (ShootSpawn (spawnedHit));

			enemyControllerScript = hit.transform.GetComponent<EnemyControllerScript>();
			if(enemyControllerScript != null)
			{
				hit.transform.gameObject.GetComponent<Rigidbody>().AddForceAtPosition (shootRay.direction * knockBackAmt, hit.point);
				enemyControllerScript.EnemyHealthAdjustment(-damageAmt);
			}
		}						
	}

	IEnumerator ShootLine()
	{
		yield return new WaitForSeconds (.25f);
		line.enabled = false;
	}

	IEnumerator ShootSpawn(GameObject spawnedHit)
	{
		yield return new WaitForSeconds (2f);
		Destroy (spawnedHit);
	}
}
GameControllerScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class GameControllerScript : MonoBehaviour
{

    public GameObject pauseMenuCanvas;
    public bool playerAlive = true;
    private bool pauseMenuActive = false;

    void Start()
    {
        if(pauseMenuCanvas != null)
        {
            pauseMenuCanvas.SetActive(false);
        }
    }

    void Update()
    {
        if(Input.GetButtonDown("Cancel"))
        {
            PauseScreen();
        }
        if(pauseMenuActive)
        {
            if(Input.GetButtonDown("01"))
                StartLevel();
            else if(Input.GetButtonDown("02"))
                QuitGame();
            else if(Input.GetButtonDown("03"))
                PauseScreen();
        }
    }

    public void StartLevel()
    {
        Time.timeScale = 1;
        SceneManager.LoadScene(1);
    }

    public void QuitGame()
    {
        Application.Quit();
    }

    public void PauseScreen()
    {
        pauseMenuCanvas.SetActive(!pauseMenuCanvas.activeInHierarchy);
        if(Time.timeScale == 1 && pauseMenuCanvas.activeInHierarchy)
        {
            Time.timeScale = 0;
            pauseMenuActive = true;

            if(playerAlive)
                pauseMenuCanvas.transform.Find("PauseText").GetComponent<Text>().text = "Pause";
            else
                pauseMenuCanvas.transform.Find("PauseText").GetComponent<Text>().text = "You Died";
        }           
            
        else
        {
            Time.timeScale = 1;
            pauseMenuActive = false;
        }
    }
}
EnemySpawnScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemySpawnScript : MonoBehaviour 
{
	public GameObject enemy;

	public float spawnRate;
	private float nextSpawnTime;

	void Update () 
	{
		if(Time.time > nextSpawnTime)
		{
			nextSpawnTime = Time.time + spawnRate;
			Instantiate (enemy, transform.position, Quaternion.identity);
		}
	}
}
EnemyControllerScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyControllerScript : MonoBehaviour
{
    private GameObject playerObject;
    private UnityEngine.AI.NavMeshAgent enemyNav;
    private Animator enemyAnim;

    private LayerMask playerMask = 1 << 9;
    public bool playerPresent = false;

    public float enemyHealth = 100f;

    public float enemyAttackAmount;
    public float enemyAttackRate;
    private float enemyNextAttackTime = 0f;

    void Awake()
    {
        playerObject = GameObject.FindGameObjectWithTag("Player");
        enemyNav = GetComponent<UnityEngine.AI.NavMeshAgent>();
        enemyAnim = GetComponentInChildren<Animator>();
    }

    void Update()
    {
        if(!playerPresent)
            enemyNav.SetDestination(playerObject.transform.position);
        
        EnemyAnimation();
    }

    void FixedUpdate()
    {
        playerPresent = DetectPlayer();
        AttackPlayer();
    }

    bool DetectPlayer()
    {
        Vector3 fwd = transform.TransformDirection(Vector3.forward);
        if(Physics.Raycast(transform.position, fwd, 2, playerMask))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    void AttackPlayer()
    {
        if(playerPresent && Time.time > enemyNextAttackTime)
        {
            enemyNextAttackTime = Time.time + enemyAttackRate;
            playerObject.GetComponent<PlayerStatsScript>().PlayerHealthAdjustment(-enemyAttackAmount);
        }
    }

    public void EnemyHealthAdjustment(float enemyHealthAdjustment)
    {
        enemyHealth += enemyHealthAdjustment;
        if(enemyHealth <= 0)
        {
            Destroy(gameObject);
            playerObject.GetComponent<PlayerStatsScript>().EnemiesKilledTotal();
        }
            
    }

    void EnemyAnimation ()
    {
        enemyAnim.SetBool("PlayerNear", playerPresent);
    }
}
PlayerStatsScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PlayerStatsScript : MonoBehaviour
{
    public float playerHealth = 100f;
    public int enemiesKilled = 0;

    public Slider playerHealthSlider;
    public Text timerText;
    public Text enemiesKilledText;
    public Image damagePanel;

    public float damageFlashSpeed = .25f;
    public Color damageFlashColor;

    void Awake()
    {
        playerHealthSlider = GameObject.Find("HealthSlider").GetComponent<Slider>();
        timerText = GameObject.Find("TimerText").GetComponent<Text>();
        enemiesKilledText = GameObject.Find("EnemiesText").GetComponent<Text>();
        damagePanel = GameObject.Find("DamagePanel").GetComponent<Image>();
    }

    void Update()
    {
        timerText.text = "Time Alive: " + Mathf.RoundToInt(Time.time);
    }


    public void PlayerHealthAdjustment(float playerHealthAdjustment)
    {
        playerHealth += playerHealthAdjustment;
        playerHealthSlider.value = playerHealth;        

        damagePanel.color = damageFlashColor;
        StartCoroutine(DamageFlashBack());

        if(playerHealth <= 0)
        {
            GameObject.Find("GameController").GetComponent<GameControllerScript>().playerAlive = false;
            GameObject.Find("GameController").GetComponent<GameControllerScript>().PauseScreen();
        }
    }

    IEnumerator DamageFlashBack()
    {
        yield return new WaitForSeconds(damageFlashSpeed);
        damagePanel.color = Color.clear;
    }

    public void EnemiesKilledTotal()
    {
        enemiesKilled++;
        enemiesKilledText.text = "Enemies Killed: " + enemiesKilled;
    }
}

First Person Shooter Project

First Person Shooter Project:

The second project is a completion of the first person game you have been working on in the labs. Like the first project you will produce any missing elements, as well as add more to create a unique game to separate it from others. Once completed the unity project folder and the final game build should be submitted.

You will be graded on the following:
  • Coding
    • Develop functional code that operates as expected.
    • Troubleshoot any errors and optimize the game.
  • Graphics
    • Develop necessary graphics for the game.
    • Clean up and polish graphical assets.
  • Novelty
    • Develop an innovative, creative elements that separate the game from others.
  • Final Build
    • Polish and implement solid craftsmanship to develop a “finished” game.
    • Create a build of the game that is compatible for Mac, PC, Web, and mobile.
Resources:
Assignment Video Tutorials
You may watch the tutorial videos below to help you complete your assignment.

Assignment Video Tutorials

Wait! Before you go!

Did you remember to?

  • Read through this webpage
  • Submit First Person Project on Blackboard