I have a bit of a problem with transferring my Game/Health Manager across scenes. My current Health Manager is set up so when the player gets hit, they flash, which is controlled by activating and de-activating the player's renderer. Everything transfers across using a Singleton and DontDestroyOnLoad, except the player's renderer in the Inspector box. I don't really know how I can make a reference to it so it's stored via script, or is added to the object box between scenes. I've tried making a reference via a GameObject, but it doesn't work as a Renderer isn't a GameObject.
Any ideas on what I can do? I've tried asking on the Unity forum, but I've had no reply. :(
Okay, here's my HealthManager, which originally had a reference to the player's renderer. I've commented it out as I'm currently trying to see if I can just add it to my player's PlayerController and then access it via the HealthManager as a static, but I'm not having any luck.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class HealthManager : MonoBehaviour
{
//The counters will count down and will keep counting down based on the length variables
public int maxHealth;
public static int currentHealth;
public float invincibilityLength;
//public Renderer playerRenderer;
public float flashLength;
public float respawnLength;
public GameObject deathEffect;
public Image blackScreen;
public float fadeSpeed;
public float waitForFade;
public Image flame1;
public Image flame2;
public Image flame3;
public Sprite fullFlame;
//public Sprite threeQuarterFlame;
public Sprite halfFlame;
//public Sprite quarterFlame;
public Sprite EmptyFlame;
public GameObject playerPrefab;
private float invincibilityCounter;
private float flashCounter;
private bool isRespawning;
private Vector3 respawnPoint;
private bool isFadeToBlack;
private bool isFadeFromBlack;
private PlayerController thePlayer;
private Quaternion startPosition;
void Start()
{
thePlayer = playerPrefab.GetComponent<PlayerController>();
currentHealth = maxHealth;
respawnPoint = playerPrefab.transform.position;
startPosition = playerPrefab.transform.rotation;
}
void Update()
{
//These functions are checked every frame until the player takes damage
if(invincibilityCounter > 0)
{
invincibilityCounter -= Time.deltaTime;
flashCounter -= Time.deltaTime;
if(flashCounter <= 0)
//The Flash Counter is currently set at 0.1 and will be within the 0 region as it counts down. During this period, the playerRenderer will alternate between on and off
{
PlayerController.playerRenderer.enabled = !PlayerController.playerRenderer.enabled;
//The Flash Counter will keep counting down and reloop depending on the Flash Length time
flashCounter = flashLength;
}
//This makes sure after the flashing and invincibility has worn off that the player renderer is always turned back on so you can see the player
if(invincibilityCounter <= 0)
{
PlayerController.playerRenderer.enabled = true;
}
}
if (isFadeToBlack)
{
blackScreen.color = new Color(blackScreen.color.r, blackScreen.color.g, blackScreen.color.b, Mathf.MoveTowards(blackScreen.color.a, 1f, fadeSpeed * Time.deltaTime));
if (blackScreen.color.a == 1f)
{
isFadeToBlack = false;
}
}
if (isFadeFromBlack)
{
blackScreen.color = new Color(blackScreen.color.r, blackScreen.color.g, blackScreen.color.b, Mathf.MoveTowards(blackScreen.color.a, 0f, fadeSpeed * Time.deltaTime));
if (blackScreen.color.a == 0f)
{
isFadeFromBlack = false;
}
}
}
public void HurtPlayer(int damage, Vector3 direction)
{
//If the invincibility countdown reaches zero it stops, making you no longer invincible and prone to taking damage again
if (invincibilityCounter <= 0)
{
currentHealth -= damage;
FlameMetre();
if (currentHealth <= 0)
{
Respawn();
}
else
{
thePlayer.Knockback(direction);
invincibilityCounter = invincibilityLength;
PlayerController.playerRenderer.enabled = false;
flashCounter = flashLength;
}
}
}
public void Respawn()
{
//A StartCoroutine must be set up before the IEnumerator can begin
if (!isRespawning)
{
StartCoroutine("RespawnCo");
}
}
//IEnumerators or Coroutines will execute the code separately at specified times while the rest of the code in a codeblock will carry on executing as normal
public IEnumerator RespawnCo()
{
if (!Checkpoint.checkpointActive)
{
isRespawning = true;
thePlayer.gameObject.SetActive(false);
Instantiate(deathEffect, thePlayer.transform.position, thePlayer.transform.rotation);
yield return new WaitForSeconds(respawnLength);
isFadeToBlack = true;
yield return new WaitForSeconds(waitForFade);
isFadeFromBlack = true;
isRespawning = false;
thePlayer.gameObject.SetActive(true);
currentHealth = maxHealth;
FlameMetre();
invincibilityCounter = invincibilityLength;
PlayerController.playerRenderer.enabled = false;
flashCounter = flashLength;
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
GameManager.currentEmbers = 0;
}
else if (Checkpoint.checkpointActive)
{
isRespawning = true;
thePlayer.gameObject.SetActive(false);
Instantiate(deathEffect, thePlayer.transform.position, thePlayer.transform.rotation);
yield return new WaitForSeconds(respawnLength);
isFadeToBlack = true;
yield return new WaitForSeconds(waitForFade);
isFadeFromBlack = true;
isRespawning = false;
thePlayer.gameObject.SetActive(true);
thePlayer.transform.position = respawnPoint;
thePlayer.transform.rotation = startPosition;
currentHealth = maxHealth;
FlameMetre();
invincibilityCounter = invincibilityLength;
PlayerController.playerRenderer.enabled = false;
flashCounter = flashLength;
}
}
public void FlameMetre()
{
switch (currentHealth)
{
case 30:
flame1.sprite = fullFlame;
flame2.sprite = fullFlame;
flame3.sprite = fullFlame;
return;
case 25:
flame1.sprite = fullFlame;
flame2.sprite = fullFlame;
flame3.sprite = halfFlame;
return;
case 20:
flame1.sprite = fullFlame;
flame2.sprite = fullFlame;
flame3.sprite = EmptyFlame;
return;
case 15:
flame1.sprite = fullFlame;
flame2.sprite = halfFlame;
flame3.sprite = EmptyFlame;
return;
case 10:
flame1.sprite = fullFlame;
flame2.sprite = EmptyFlame;
flame3.sprite = EmptyFlame;
return;
case 5:
flame1.sprite = halfFlame;
flame2.sprite = EmptyFlame;
flame3.sprite = EmptyFlame;
return;
case 0:
flame1.sprite = EmptyFlame;
flame2.sprite = EmptyFlame;
flame3.sprite = EmptyFlame;
return;
default:
flame1.sprite = EmptyFlame;
flame2.sprite = EmptyFlame;
flame3.sprite = EmptyFlame;
return;
}
}
/*public void HealPlayer(int healAmount)
{
currentHealth += healAmount;
if(currentHealth > maxHealth)
{
currentHealth = maxHealth;
}
}*/
public void SetSpawnPoint(Vector3 newPosition)
{
respawnPoint = newPosition;
}
}
And then my PlayerController:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PlayerController : MonoBehaviour
{
public Animator anim;
public float moveSpeed;
public float jumpForce;
public bool jumped;
public bool allowInteract = false;
public float gravityScale;
public float knockBackForce;
public float knockBackTime;
//public Material textureChange;
//public Material textureDefault;
public bool allowCombat;
public bool allowJump;
public static bool canMove;
public ChestTrigger chest;
//public GameObject projectilePrefab;
//public GameObject spawnPoint;
public static Renderer playerRenderer;
private Vector2 moveDirection;
private Vector2 moveHorizontal;
private float knockBackCounter;
private CharacterController controller;
private Quaternion targetRot;
private bool headingLeft = false;
private Pickup pickupWeapon;
void Awake()
{
controller = GetComponent<CharacterController>();
anim = GetComponent<Animator>();
}
void Start()
{
Cursor.visible = false;
pickupWeapon = FindObjectOfType<Pickup>();
canMove = true;
targetRot = transform.rotation;
if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("start_area"))
{
allowCombat = false;
allowJump = true;
}
if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("hut_interior"))
{
allowCombat = false;
allowJump = false;
}
if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("start_area 2"))
{
allowCombat = false;
allowJump = true;
}
if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("level 1, room 1"))
{
allowCombat = true;
allowJump = true;
}
if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("level 1, room 2"))
{
allowCombat = true;
allowJump = true;
}
}
void Update()
{
//To avoid any control or animation issues, each code block must be within this code block
if (knockBackCounter <= 0 && canMove)
{
moveHorizontal.x = Input.GetAxis("Horizontal");
//moveVertical.y = Input.GetAxis("Vertical");
moveDirection = new Vector2(moveHorizontal.x * moveSpeed, moveDirection.y);
controller.Move(moveDirection * Time.deltaTime);
//Adds character rotation when changing direction horizontally
if ((moveHorizontal.x < 0f && !headingLeft) || (moveHorizontal.x > 0f && headingLeft))
{
if (moveHorizontal.x < 0f) targetRot = Quaternion.Euler(0, 270, 0);
if (moveHorizontal.x > 0f) targetRot = Quaternion.Euler(0, 90, 0);
headingLeft = !headingLeft;
}
transform.rotation = Quaternion.Lerp(transform.rotation, targetRot, Time.deltaTime * 20f);
//Adds character rotation when changing direction vertically
/*if(moveVertical.y < 0f && lookingUp || (moveVertical.y > 0f && !lookingUp))
{
if (moveVertical.y > 0f) targetrot = Quaternion.Euler(0, 0, 0);
if (moveVertical.y < 0f) targetrot = Quaternion.Euler(0, 180, 0);
lookingUp = !lookingUp;
}*/
if (SceneManagement.insideHut && canMove)
{
float moveHorizontalSnap = Input.GetAxis("Horizontal");
float moveVerticalSnap = Input.GetAxis("Vertical");
//Adds character rotation when changing direction horizontally, but snaps instead of fully rotating
if (moveHorizontalSnap > 0)
{
transform.eulerAngles = new Vector2(0, 90);
}
else if (moveHorizontalSnap < 0)
{
transform.eulerAngles = new Vector2(0, -90);
}
//To possibly prevent diagonal movement with some control setups, try adding 'else if'
//Adds character rotation when changing direction vertically, but snaps instead of fully rotating
else if (moveVerticalSnap > 0)
{
transform.eulerAngles = new Vector2(0, 0);
}
//Use this to make the character face towards the camera.
/*else if (moveVertical < 0)
{
transform.eulerAngles = new Vector3(0, 180);
}*/
}
if (controller.isGrounded)
{
if (allowJump)
{
moveDirection.y = -1f;
//GetKeyDown will require the player to press the button each time they want to jump. GetKey will allow the player to spam the jump button if they keep pressing it down.
if (Input.GetKeyDown(KeyCode.KeypadPlus))
{
moveDirection.y = jumpForce;
jumped = true;
}
else if (!Input.GetKeyDown(KeyCode.KeypadPlus))
{
jumped = false;
}
if (SceneManagement.xbox360Controller == 1)
{
if (Input.GetKeyDown("joystick button 0"))
{
moveDirection.y = jumpForce;
jumped = true;
}
else if (!Input.GetKeyDown("joystick button 0"))
{
jumped = false;
}
}
else if (SceneManagement.ps4Controller == 1)
{
if (Input.GetKeyDown("joystick button 1"))
{
moveDirection.y = jumpForce;
jumped = true;
}
else if (!Input.GetKeyDown("joystick button 1"))
{
jumped = false;
}
}
}
}
if (allowCombat)
{
if (Input.GetKeyDown(KeyCode.Space))
{
anim.SetTrigger("Attack");
//GameObject projectileObject = Instantiate(projectilePrefab);
//projectilePrefab.transform.position = spawnPoint.transform.position + spawnPoint.transform.forward;
}
else if (SceneManagement.xbox360Controller == 1)
{
if (Input.GetKeyDown("joystick button 1"))
{
anim.SetTrigger("Attack");
}
}
else if (SceneManagement.ps4Controller == 1)
{
if (Input.GetKeyDown("joystick button 2"))
{
anim.SetTrigger("Attack");
}
}
}
if (allowInteract)
{
if (SceneManagement.xbox360Controller == 1)
{
if (Input.GetKeyDown("joystick button 2"))
{
anim.SetBool("Interact", controller.isGrounded);
pickupWeapon.ObjectActivation();
allowInteract = false;
}
}
else if (SceneManagement.ps4Controller == 1)
{
if (Input.GetKeyDown("joystick button 0"))
{
anim.SetBool("Interact", controller.isGrounded);
pickupWeapon.ObjectActivation();
allowInteract = false;
}
}
else
{
if (Input.GetKeyDown(KeyCode.Return))
{
anim.SetBool("Interact", controller.isGrounded);
pickupWeapon.ObjectActivation();
allowInteract = false;
}
}
}
if (ChestTrigger.allowOpen)
{
if (Input.GetKeyDown(KeyCode.Return))
{
anim.SetBool("Interact", controller.isGrounded);
chest.ChestOpen();
}
else if (Input.GetKeyDown(KeyCode.Return) && !ChestTrigger.allowOpen)
{
anim.SetBool("Interact", false);
}
else if (SceneManagement.xbox360Controller == 1)
{
if (Input.GetKeyDown("joystick button 2"))
{
anim.SetBool("Interact", controller.isGrounded);
chest.ChestOpen();
}
else if (Input.GetKeyDown("joystick button 2") && !ChestTrigger.allowOpen)
{
anim.SetBool("Interact", false);
}
}
else if (SceneManagement.ps4Controller == 1)
{
if (Input.GetKeyDown("joystick button 0"))
{
anim.SetBool("Interact", controller.isGrounded);
chest.ChestOpen();
}
else if (Input.GetKeyDown("joystick button 0") && !ChestTrigger.allowOpen)
{
anim.SetBool("Interact", false);
}
}
}
}
else
{
knockBackCounter -= Time.deltaTime;
}
moveDirection.y = moveDirection.y + (Physics.gravity.y * gravityScale * Time.deltaTime);
anim.SetBool("isGrounded", controller.isGrounded);
//If the character can't move, then the Speed is set to 0. Otherwise it'll use the horizontal input value.
anim.SetFloat("Speed",
!canMove
? 0f
: Mathf.Abs(Input.GetAxis("Horizontal")));
//anim.SetFloat("Speed", Mathf.Abs(Input.GetAxis("Horizontal")));
}
public void Knockback(Vector3 direction)
{
knockBackCounter = knockBackTime;
moveDirection = direction * knockBackForce;
moveDirection.y = knockBackForce;
}
}