I created a HUD that displays the players health and the number of coins collected. Before I created the HUD, the coin portion worked fine and my player would grab coins, they would disappear and it would show in the “coins collected” window of the script component. Once I created the HUD to display the amount of coins collected, the amount does not show, the coins no longer disappear when touched and the coin collected value in the script component just continues to go up as long as the coin is touching my player.
I am also getting the following error message:
NullReferenceException: Object reference not set to an instance of an object
PlayerStats.CollectCoin (Int32 coinValue) (at Assets/_scripts/PlayerStats.cs:25)
CoinPickup.OnTriggerEnter2D (UnityEngine.Collider2D collider) (at Assets/_scripts/CoinPickup.cs:13)
What did I mess up? Here is the PlayerStats Script
using UnityEngine;
using System.Collections;
public class PlayerStats : MonoBehaviour {
private GameObject HUDCamera;
private GameObject HUDSprite;
public bool isImmune = false;
public float immunityDuration = 1.5f;
private float immunityTime = 0f;
private float flickerDuration = 0.1f;
private float flickerTime = 0f;
private SpriteRenderer spriteRenderer;
private bool isDead = false;
public int health = 6;
public int coinsCollected = 0;
public void CollectCoin(int coinValue)
{
this.coinsCollected = this.coinsCollected + coinValue;
this.HUDSprite.GetComponent<CoinCounter>().value = this.coinsCollected;
}
public void TakeDamage(int damage, bool playHitReaction)
{
if(this.isImmune == false && isDead == false)
{
this.health = this.health - damage;
this.HUDCamera.GetComponent<GUIGame>().UpdateHealth(this.health);
if(this.health >= 1)
{
PlayHitReaction();
}
else if(this.health <= 0)//(playHitReaction == true)
{
PlayerIsDead();
}
}
}
void Update()
{
if (this.isImmune == true)
{
SpriteFlicker();
immunityTime = immunityTime + Time.deltaTime;
if (immunityTime >= immunityDuration) {
this.isImmune = false;
this.spriteRenderer.enabled = true;
}
}
}
void Start()
{
spriteRenderer = this.gameObject.GetComponent<SpriteRenderer> ();
HUDCamera = GameObject.FindGameObjectWithTag ("HUDCamera");
HUDSprite = GameObject.FindGameObjectWithTag ("HUDSprite");
}
void PlayHitReaction()
{
this.isImmune = true;
this.immunityTime = 0f;
this.gameObject.GetComponent<Animator> ().SetTrigger ("Damage");
}
void SpriteFlicker()
{
if (this.flickerTime < this.flickerDuration) {
this.flickerTime = this.flickerTime + Time.deltaTime;
} else if (this.flickerTime >= this.flickerDuration) {
spriteRenderer.enabled = !(spriteRenderer.enabled);
this.flickerTime = 0;
}
}
void PlayerIsDead()
{
this.isDead = true;
this.gameObject.GetComponent<Animator> ().SetTrigger ("Damage");
PlayerController controller =
this.gameObject.GetComponent<PlayerController> ();
controller.enabled = false;
this.GetComponent<Rigidbody2D>().velocity = new Vector2(0,0);
if(controller.isFacingRight == true)
{
this.GetComponent<Rigidbody2D>().AddForce(new Vector2(-400, 400));
}
else
{
this.GetComponent<Rigidbody2D>().AddForce(new Vector2(400,400));
}
}
}
This is the “CoinCounter” script
using UnityEngine;
using System.Collections;
public class CoinCounter : MonoBehaviour
{
public Sprite[] spriteDigits;
public int value = 0;
public float spacing = 0.4f;
private int displayValue = -1;
// Update is called once per frame
void Update ()
{
// If the value has changed, we need to re-render our sprites
if (displayValue != value)
{
// Turn our value into a string: 956 becomes "956"
string digits = value.ToString();
// Get any SpriteRenderer children
SpriteRenderer[] renderers = GetComponentsInChildren<SpriteRenderer>();
// Count how many we have
int numRenderers = renderers.Length;
// If we don't have enough SpriteRenders (one for each 'place' of our value), add them
if(numRenderers < digits.Length)
{
// Keeping adding until we have enough
while(numRenderers < digits.Length)
{
// Create a new empty game object
GameObject spr = new GameObject();
// Add a sprite render component
spr.AddComponent<SpriteRenderer>();
// Set this new game object to be a child of our current object
spr.transform.parent = transform;
// Set it's position so we can line up the 1s next to the 10s next to the 100s, etc
spr.transform.localPosition = new Vector3(numRenderers * spacing, 0.0f, 0.0f);
// Add the new GameObject to the UI layer
spr.layer = 5;
// Increment how many renderers we have so the loop doesn't execute forever
numRenderers = numRenderers + 1;
}
// Refresh our list of renderers
renderers = GetComponentsInChildren<SpriteRenderer>();
}
// If we have two many reneders (e.g, 4 when we only have a 3 digit number) hide them
else if(numRenderers > digits.Length)
{
// While we have too many renderers
while(numRenderers > digits.Length)
{
// Clear their sprites
renderers[numRenderers-1].sprite = null;
// Decrement how many renderers we have so the loop doesn't execute forever
// Note: this doesn't actually remove the renderer
numRenderers--;
}
}
// Set the sprite for each rendererd based on our value
int rendererIndex = 0;
foreach(char digit in digits)
{
// Convert the char digit into an int which will be the index
int spriteIndex = int.Parse(digit.ToString());
// Update the proper renderer (starting at 0 which is the far left)
// Set its sprite to be the proper sprite from our spriteDigits array
// Because index 0 of spriteDigits is the sprite "0" and 1 is "1", this works
renderers[rendererIndex].sprite = spriteDigits[spriteIndex];
// Icnrement the rendererIndex so the next digit in our number displays on the proper renderer
rendererIndex++;
}
displayValue = value;
}
}
}