This week has seen lots of progress being made with my project. With the help of Maddi, we’ve completed various different tasks that have been on my to-do list. The first thing of note was the issue with health being reset when entering a room. To fix this, I created a new script called “LevelLoad”, which oversees the instantiation of various objects in the game scenes. This is then able to keep track of the player’s health and other stats, such as what abilities they’ve unlocked. I should also then be able to modify this script so that it can keep track of the enemies that the player has defeated, as well, though I may not implement this in the final version.
LevelLoad Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class LevelLoad : MonoBehaviour
{
public GameObject playerPrefab;
public GameObject healthPrefab;
public GameObject filterPrefab;
//[SerializeField]
//private Transform spawnPoint;
// Start is called before the first frame update
void Awake()
{
GameObject player = new GameObject();
GameObject[] players = GameObject.FindGameObjectsWithTag("Player");
if (players.Length == 0 )
{
player = GameObject.Instantiate(playerPrefab);
Debug.Log("Instantiate Player");
Debug.Log(player.transform.position);
//player.transform.position = spawnPoint.position;
}
else
{
player = players[0];
}
if (!player.GetComponent<PlayerAttack>().bossDestroyed)
{
Instantiate(filterPrefab);
Debug.Log("Filter instantiated");
}
GameObject health = null;
GameObject[] healthBars = GameObject.FindGameObjectsWithTag("Health");
if (healthBars.Length == 0 )
{
health = GameObject.Instantiate(healthPrefab);
Debug.Log("Health Instantiated");
}
else
{
health = healthBars[0];
}
}
void Update()
{
ICinemachineCamera camera = GameObject.FindWithTag("MainCamera").GetComponent<CinemachineBrain>().ActiveVirtualCamera;
camera.Follow = GameObject.FindWithTag("Player").transform;
}
}
Speaking of abilities, I have programmed a basic dash ability that the player can pick up and then use by pressing the Shift key. In line with the previous “LevelLoad” script, the player is able to utilise this ability in other rooms, too. I’ve also created health upgrades which have similar persistence between rooms.
HealthUpgrade Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HealthUpgrade : MonoBehaviour
{
public GameObject lifeIconPrefab;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
ShowHealth();
}
void ShowHealth()
{
PlayerHealth player = GameObject.FindWithTag("Player").GetComponent<PlayerHealth>();
GameObject Health = GameObject.FindWithTag("Health");
GameObject[] lifeIcons = new GameObject[player.maxLives];
for (int i = 0; i < player.maxLives; i++)
{
if (i < Health.transform.childCount)
{
lifeIcons[i] = Health.transform.GetChild(i).gameObject;
}
else
{
lifeIcons[i] = CreateNewLife(Health, lifeIcons[i -1], player.maxLives);
}
}
for (int i = 0; i < lifeIcons.Length; i++)
{
if (i < player.currentLives)
{
lifeIcons[i].SetActive(true);
}
else
{
lifeIcons[i].SetActive(false);
}
}
}
GameObject CreateNewLife(GameObject Health, GameObject finalLifeIcon, int maxLives)
{
GameObject newLifeIcon = Instantiate(lifeIconPrefab);
Debug.Log("Instantiate Life Icon");
newLifeIcon.transform.position = newLifeIcon.transform.position + new Vector3(75*maxLives, 0, 0);
newLifeIcon.transform.SetParent(Health.transform, false);
return newLifeIcon;
}
}
PlayerHealth Script
public void UpgradeHealth()
{
maxLives += 1;
currentLives = maxLives;
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("HealthUpgrade"))
{
GameObject HealthUpgrade = GameObject.FindWithTag("HealthUpgrade");
Debug.Log("Upgrade Health");
UpgradeHealth();
Destroy(HealthUpgrade);
}
}
PlayerMovement Script
private bool canDash = true;
private bool isDashing;
private bool canUseDash;
[SerializeField] private float dashingPower = 24f;
[SerializeField] private float dashingTime = 0.2f;
[SerializeField] private float dashingCooldown = 1f;
// Update is called once per frame
void Update()
{
if (isDashing)
{
return;
// Prevent player from moving, flipping or jumping whilst dashing
}
horizontal = Input.GetAxisRaw("Horizontal"); //Returns a value of -1, 0 or 1 depending on the direction of movement
if (Input.GetKeyDown(KeyCode.LeftShift) && canUseDash)
{
StartCoroutine(Dash());
}
Flip();
}
private void FixedUpdate()
{
if (isDashing)
{
return;
// Prevent player from moving, flipping or jumping whilst dashing
}
rb.velocity = new Vector2(horizontal * speed, rb.velocity.y);
if (Mathf.Abs(rb.velocity.x) > maxMoveSpeed) //If the player's speed exceeds that of the maxMoveSpeed
{
rb.velocity = new Vector2(Mathf.Sign(rb.velocity.x) * maxMoveSpeed, rb.velocity.y); //Clamp it
}
}
private IEnumerator Dash()
{
canDash = false;
isDashing = true;
float originalGravity = rb.gravityScale;
rb.gravityScale = 0f;
rb.velocity = new Vector2(transform.localScale.x * dashingPower, 0f);
yield return new WaitForSeconds(dashingTime);
rb.gravityScale = originalGravity;
isDashing = false;
yield return new WaitForSeconds(dashingCooldown);
canDash = true;
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("DashUpgrade"))
{
GameObject DashUpgrade = GameObject.FindWithTag("DashUpgrade");
Debug.Log("Unlocked Dash");
Destroy(DashUpgrade);
canUseDash = true;
}
}
As for the enemies, I’ve made them a bit livelier by creating a couple of scripts for them, namely “EnemyPatrol” and “EnemyChase”. They largely do what they say on the tin; “EnemyPatrol” makes them move along a set path, whilst “EnemyChase” detects when the Player has entered their preset field, and ensues chasing them.
EnemyPatrol Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyPatrol : MonoBehaviour
{
public float moveSpeed;
private int leftLimit;
private int rightLimit;
private Vector3 initialPos;
private Vector3 currentPos;
public int maxPosChange;
private int direction;
public int frameCounter;
private int lastFrameMove;
public int frameFrequency;
GameObject enemy;
// Start is called before the first frame update
void Start()
{
//moveSpeed = 0.5f;
leftLimit = 0;
rightLimit = 0;
enemy = gameObject;
initialPos = enemy.transform.position;
Debug.Log(initialPos);
//maxPosChange = 5;
direction = 1;
//frameFrequency = 60;
lastFrameMove = Time.frameCount;
}
// Update is called once per frame
void Update()
{
if (!enemy.GetComponent<EnemyChase>().isChasing)
{
if (Time.frameCount - lastFrameMove >= frameFrequency)
{
currentPos = enemy.transform.position;
float differenceInPos = Mathf.Abs(initialPos.x- currentPos.x);
if (differenceInPos >= maxPosChange)
{
direction *= -1;
}
enemy.transform.position = enemy.transform.position + new Vector3(moveSpeed * direction, 0, 0);
lastFrameMove = Time.frameCount;
}
}
}
}
EnemyChase Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyChase : MonoBehaviour
{
public GameObject player;
public GameObject enemy;
private bool isChasing;
public float moveSpeed;
private Vector3 currentPos;
private float direction;
public int frameCounter;
private int lastFrameMove;
public int frameFrequency;
public Vector3 playerPos;
// Start is called before the first frame update
void Start()
{
isChasing = false;
//moveSpeed = 1f;
frameFrequency = 60;
lastFrameMove = Time.frameCount;
enemy = this.gameObject;
player = GameObject.FindWithTag("Player");
}
// Update is called once per frame
void Update()
{
if (isChasing == true)
{
if (Time.frameCount - lastFrameMove >= frameFrequency)
{
currentPos = enemy.transform.position;
playerPos = player.transform.position;
direction = Mathf.Sign(playerPos.x - currentPos.x);
enemy.transform.position = enemy.transform.position + new Vector3(moveSpeed * direction, 0, 0);
lastFrameMove = Time.frameCount;
}
}
}
void OnTriggerEnter2D(Collider2D col)
{
currentPos = enemy.transform.position;
playerPos = player.transform.position;
direction = Mathf.Sign(playerPos.x - currentPos.x);
isChasing = true;
Debug.Log("Chasing player");
}
}
A lot has been worked on mechanically this week, which I’m happy about. However, after so much coding, I think I’ll need to take a break so I can de-stress and gather my thoughts. After my break, I want to try redesigning my level layouts, as well as start making some character designs, as I’ve been gathering reference material and making moodboards on Pinterest in-between developing the game.