Lives going to negative value

Hello Everyone! I’ve added 3 lives to my player. But when I get out the 2 lives are taken instead of 1. Example Before Play Lives are 3 Getting out for the first time Lives are 1 Getting out the third time Lives are -1. Please Help!! @seandolan

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class LevelManager : MonoBehaviour {

public float waitToRespawn;
public PlayerController thePlayer;

public GameObject deathSplosion;

public int coinCount;

public Text coinText;

public Image heart1;
public Image heart2;
public Image heart3;

public Sprite heartFull;
public Sprite heartHalf;
public Sprite heartEmpty;

public int maxHealth;
public int healthCount;

private bool respawning;

public ResetOnRespawn[] objectsToReset;

public bool invincible;

public Text livesText;
public int startingLives;
public int currentLives;

// Use this for initialization
void Start () {
	thePlayer = FindObjectOfType<PlayerController> ();

	coinText.text = "Coins: " + coinCount; 

	healthCount = maxHealth;

	objectsToReset = FindObjectsOfType<ResetOnRespawn>();

	currentLives = startingLives;
	livesText.text = "Lives x " + currentLives;
}

// Update is called once per frame
void Update () {
	if (healthCount <= 0 && !respawning) 
	{
		Respawn ();
		respawning = true;
	}
}

public void Respawn()
{
	currentLives -= 1;
	livesText.text = "Lives x " + currentLives;

	if (currentLives > 0)
	{
		StartCoroutine ("RespawnCo");
	} else {
		thePlayer.gameObject.SetActive (false);
	}
}

public IEnumerator RespawnCo()
{
	thePlayer.gameObject.SetActive (false);

	Instantiate (deathSplosion, thePlayer.transform.position, thePlayer.transform.rotation);

	yield return new WaitForSeconds (waitToRespawn);

	healthCount = maxHealth;
	respawning = false;
	UpdateHeartMeter ();

	coinCount = 0;
	coinText.text = "Coins: " + coinCount;

	thePlayer.transform.position = thePlayer.respawnPosition;
	thePlayer.gameObject.SetActive (true);

	for (int i = 0; i < objectsToReset.Length; i++) 
	{
		objectsToReset *.gameObject.SetActive (true);*

_ objectsToReset .ResetObject ();_
* }*
* }*
* public void AddCoins(int coinsToAdd)*
* {*
* coinCount += coinsToAdd;*
* coinText.text = "Coins: " + coinCount;*
* }*
* public void HurtPlayer(int damageToTake)*
* {*
* if (!invincible)*
* { *
* healthCount -= damageToTake;*
* UpdateHeartMeter ();*
* thePlayer.Knockback ();*
* }*
* }*
* public void UpdateHeartMeter()*
* {*
* switch (healthCount)*
* {*
* case 6:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartFull;*
* heart3.sprite = heartFull;*
* return;*
* case 5:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartFull;*
* heart3.sprite = heartHalf;*
* return;*
* case 4:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartFull;*
* heart3.sprite = heartEmpty;*
* return;*
* case 3:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartHalf;*
* heart3.sprite = heartEmpty;*
* return;*
* case 2:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartEmpty;*
* heart3.sprite = heartEmpty;*
* return;*
* case 1:*
* heart1.sprite = heartHalf;*
* heart2.sprite = heartEmpty;*
* heart3.sprite = heartEmpty;*
* return;*
* case 0:*
* heart1.sprite = heartEmpty;*
* heart2.sprite = heartEmpty;*
* heart3.sprite = heartEmpty;*
* return;*
* default:*
* heart1.sprite = heartEmpty;*
* heart2.sprite = heartEmpty;*
* heart3.sprite = heartEmpty;*
* return;*
* }*
* }*
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
* public float moveSpeed;*
* public Rigidbody2D myRigidbody;*
* public float jumpSpeed;*
* public Transform groundCheck;*
* public float groundCheckRadius;*
* public LayerMask whatIsGround;*
* public bool isGrounded;*
* private Animator myAnim;*
* private Vector3 initScale;*
* public Vector3 respawnPosition;*
* public LevelManager theLevelManager;*
* public GameObject stompBox;*
* public float knockbackForce;*
* public float knockbackLength;*
* public float knockbackCounter;*
* public float invincibilityLength;*
* private float invincibilityCounter;*
* // Use this for initialization*
* void Start ()*
* {*
* myRigidbody = GetComponent ();*
* myAnim = GetComponent ();*
* initScale = transform.localScale;*
* respawnPosition = transform.position;*
* theLevelManager = FindObjectOfType();*
* }*
* // Update is called once per frame*
* void Update () {*

* isGrounded = Physics2D.OverlapCircle (groundCheck.position, groundCheckRadius, whatIsGround);*
* if (knockbackCounter <= 0)*
* {*
* if (Input.GetAxisRaw (“Horizontal”) > 0f)*
* {*
* myRigidbody.velocity = new Vector3 (moveSpeed, myRigidbody.velocity.y, 0f);*
* transform.localScale = new Vector3 (1f, 1f, 1f);*
* transform.localScale = new Vector3 (initScale.x, initScale.y, initScale.z);*
* } else if (Input.GetAxisRaw (“Horizontal”) < 0f) {*
* myRigidbody.velocity = new Vector3 (-moveSpeed, myRigidbody.velocity.y, 0f);*
* transform.localScale = new Vector3 (-1f, 1f, 1f);*
* transform.localScale = new Vector3 (-initScale.x, initScale.y, initScale.z);*
* } else {*
* myRigidbody.velocity = new Vector3 (0f, myRigidbody.velocity.y, 0f);*
* }*
* if (Input.GetButtonDown (“Jump”) && isGrounded)*
* {*
* myRigidbody.velocity = new Vector3 (myRigidbody.velocity.x, jumpSpeed, 0f);*
* }*

* }*
* if (knockbackCounter > 0)*
* {*
* knockbackCounter -= Time.deltaTime;*
* if (transform.localScale.x > 0)*
* {*
* myRigidbody.velocity = new Vector3 (-knockbackForce, knockbackForce, 0f);*
* } else {*
* myRigidbody.velocity = new Vector3 (knockbackForce, knockbackForce, 0f);*
* }*
* }*
* if (invincibilityCounter > 0)*
* {*
* invincibilityCounter -= Time.deltaTime;*
* }*
* if (invincibilityCounter <= 0)*
* {*
* theLevelManager.invincible = false;*
* }*
* myAnim.SetFloat (“Speed”, Mathf.Abs (myRigidbody.velocity.x));*
* myAnim.SetBool (“Grounded”, isGrounded);*
* if (myRigidbody.velocity.y < 0)*
* {*
* stompBox.SetActive(true);*
* }else {*
* stompBox.SetActive (false);*
* }*
* }*
* public void Knockback()*
* {*
* knockbackCounter = knockbackLength;*
* invincibilityCounter = invincibilityLength;*
* theLevelManager.invincible = true;*
* }*
* void OnTriggerEnter2D(Collider2D other)*
* {*
* if (other.tag == “KillPlane”)*
* {*
* //gameObject.SetActive (false);*
* //transform.position = respawnPosition;*
* theLevelManager.Respawn ();*
* }*
* if (other.tag == “Checkpoint”)*
* {*
* respawnPosition = other.transform.position;*
* }*
* }*
* void OnCollisionEnter2D(Collision2D other)*
* {*
* if (other.gameObject.tag == “MovingPlatform”)*
* {*
* transform.parent = other.transform;*
* }*
* }*
* void OnCollisionExit2D(Collision2D other)*
* {*
* if (other.gameObject.tag == “MovingPlatform”)*
* {*
* transform.parent = null;*
* }*
* }*
}

I don’t know why you are losing 2 lives but to prevent the lives from going negative use:

lives = Mathf.Clamp(lives - 1, 0, lives)

this makes sure the value is between the min (0) and max (lives) values.

EDIT:
It still is going down by 2 or is it still going negative?

  1. Double click currentLives and then push shift + F12 to see all the uses of the field.

  2. Print when you are changing the values.

    Debug.Log ("lives before = " + currentLives);
    currentLives = Mathf.Clamp (currentLives, 0, 100);
    Debug.Log ("lives after = " + currentLives);
    

Have the console open when testing that way you can see if it is taking 2 away in quick succession because for two frames it doesn’t know it’s dead yet.

EDIT:
See if setting a range on the initialization of the variable prevents this.

[SerializeField] [Range (0,100] private int lives;

public int Lives {
      get { return lives }
      set { lives = Mathf.Clamp (value, 0, 100)
}

public void AddLives (int livesToAdd)
{
      Lives += livesToAdd;
}

ALL CHANGES to the lives must use the property, this will ensure the value is always clamped, also there is the Range attribute on the field, definitely do the shift + F12 to see all references to the field first though, it’s probably being called from somewhere else, making it private will keep it from being changed from outside the script except through the property which will clamp the value
Copy and paste the code above into your script.
Fingers crossed this works :slight_smile:

@kalen_08

public class PlayerController : MonoBehaviour {

public float moveSpeed; 
public Rigidbody2D myRigidbody;

public float jumpSpeed;

public Transform groundCheck;
public float groundCheckRadius;
public LayerMask whatIsGround;

public bool isGrounded;

private Animator myAnim;

private Vector3 initScale;

public Vector3 respawnPosition;

public LevelManager theLevelManager;

public GameObject stompBox;

public float knockbackForce;
public float knockbackLength;
public float knockbackCounter;

public float invincibilityLength;
private float invincibilityCounter;

// Use this for initialization
void Start ()
{
	myRigidbody = GetComponent<Rigidbody2D> ();
	myAnim = GetComponent<Animator> ();
	initScale = transform.localScale;

	respawnPosition = transform.position;

	theLevelManager = FindObjectOfType<LevelManager>();
}
// Update is called once per frame
void Update () {
		
	isGrounded = Physics2D.OverlapCircle (groundCheck.position, groundCheckRadius, whatIsGround);

	if (knockbackCounter <= 0) 
	{

				if (Input.GetAxisRaw ("Horizontal") > 0f) 
			   {
					myRigidbody.velocity = new Vector3 (moveSpeed, myRigidbody.velocity.y, 0f);
					transform.localScale = new Vector3 (1f, 1f, 1f);
					transform.localScale = new Vector3 (initScale.x, initScale.y, initScale.z);
				} else if (Input.GetAxisRaw ("Horizontal") < 0f) {
					myRigidbody.velocity = new Vector3 (-moveSpeed, myRigidbody.velocity.y, 0f);
					transform.localScale = new Vector3 (-1f, 1f, 1f);
					transform.localScale = new Vector3 (-initScale.x, initScale.y, initScale.z);
				} else {
					myRigidbody.velocity = new Vector3 (0f, myRigidbody.velocity.y, 0f);
				}

				if (Input.GetButtonDown ("Jump") && isGrounded)
		{
					myRigidbody.velocity = new Vector3 (myRigidbody.velocity.x, jumpSpeed, 0f);
				}
			
	}

	if (knockbackCounter > 0) 
	{
		knockbackCounter -= Time.deltaTime;
		if (transform.localScale.x > 0) 
		{
			myRigidbody.velocity = new Vector3 (-knockbackForce,knockbackForce, 0f);
		} else {
			myRigidbody.velocity = new Vector3 (knockbackForce, knockbackForce, 0f);
		}
	}
	if (invincibilityCounter > 0) 
	{
		invincibilityCounter -= Time.deltaTime;
	}
	if (invincibilityCounter <= 0) 
	{
		theLevelManager.invincible = false;
	}
	myAnim.SetFloat ("Speed", Mathf.Abs (myRigidbody.velocity.x));
	myAnim.SetBool ("Grounded", isGrounded);
	if (myRigidbody.velocity.y < 0) 
	{
		stompBox.SetActive(true);
	}else {
		stompBox.SetActive (false);
		}
}
public void Knockback()
{
	knockbackCounter = knockbackLength;
	invincibilityCounter = invincibilityLength;
	theLevelManager.invincible = true;
}

void OnTriggerEnter2D(Collider2D other)
{
	if (other.tag == "KillPlane") 
	{
		//gameObject.SetActive (false);

		//transform.position = respawnPosition;

	    theLevelManager.Respawn ();
		//theLevelManager.healthCount = 0;
	}

	if (other.tag == "Checkpoint") 
	{
		respawnPosition = other.transform.position;
	}
}

void OnCollisionEnter2D(Collision2D other)
{
	if (other.gameObject.tag == "MovingPlatform") 
	{
		transform.parent = other.transform;
	}
}
void OnCollisionExit2D(Collision2D other)
{
	if (other.gameObject.tag == "MovingPlatform") 
	{
		transform.parent = null;
	}
}

}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class LevelManager : MonoBehaviour {

public float waitToRespawn;
public PlayerController thePlayer;

public GameObject deathSplosion;

public int coinCount;

public Text coinText;

public Image heart1;
public Image heart2;
public Image heart3;

public Sprite heartFull;
public Sprite heartHalf;
public Sprite heartEmpty;

public int maxHealth;
public int healthCount;

private bool respawning;

public ResetOnRespawn[] objectsToReset;

public bool invincible;

public Text livesText;
public int startingLives;
public int currentLives;

// Use this for initialization
void Start () {
	thePlayer = FindObjectOfType<PlayerController> ();

	coinText.text = "Coins: " + coinCount; 

	healthCount = maxHealth;

	objectsToReset = FindObjectsOfType<ResetOnRespawn>();

	currentLives = startingLives;
	livesText.text = "Lives x " + currentLives;
}

// Update is called once per frame
void Update () {
	if (healthCount <= 0 ) 
	{
		Respawn ();
		respawning = true;
	}
}

public void Respawn()
{
	if (!respawning) {
		currentLives -= 1;
		livesText.text = "Lives x " + currentLives;

		if (currentLives > 0) {
			respawning = true;
			StartCoroutine ("RespawnCo");
		} else {
			thePlayer.gameObject.SetActive (false);
		}
	}
}

public IEnumerator RespawnCo()
{
	thePlayer.gameObject.SetActive (false);

	Instantiate (deathSplosion, thePlayer.transform.position, thePlayer.transform.rotation);

	yield return new WaitForSeconds (waitToRespawn);

	healthCount = maxHealth;
	respawning = false;
	UpdateHeartMeter ();

	coinCount = 0;
	coinText.text = "Coins: " + coinCount;

	thePlayer.transform.position = thePlayer.respawnPosition;
	thePlayer.gameObject.SetActive (true);

	for (int i = 0; i < objectsToReset.Length; i++) 
	{
		objectsToReset *.gameObject.SetActive (true);*

_ objectsToReset .ResetObject ();_
* }*
* }*
* public void AddCoins(int coinsToAdd)*
* {*
* coinCount += coinsToAdd;*
* coinText.text = "Coins: " + coinCount;*
* }*
* public void HurtPlayer(int damageToTake)*
* {*
* if (!invincible)*
* { *
* healthCount -= damageToTake;*
* UpdateHeartMeter ();*
* thePlayer.Knockback ();*
* }*
* }*
* public void UpdateHeartMeter()*
* {*
* switch (healthCount)*
* {*
* case 6:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartFull;*
* heart3.sprite = heartFull;*
* return;*
* case 5:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartFull;*
* heart3.sprite = heartHalf;*
* return;*
* case 4:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartFull;*
* heart3.sprite = heartEmpty;*
* return;*
* case 3:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartHalf;*
* heart3.sprite = heartEmpty;*
* return;*
* case 2:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartEmpty;*
* heart3.sprite = heartEmpty;*
* return;*
* case 1:*
* heart1.sprite = heartHalf;*
* heart2.sprite = heartEmpty;*
* heart3.sprite = heartEmpty;*
* return;*
* case 0:*
* heart1.sprite = heartEmpty;*
* heart2.sprite = heartEmpty;*
* heart3.sprite = heartEmpty;*
* return;*
* default:*
* heart1.sprite = heartEmpty;*
* heart2.sprite = heartEmpty;*
* heart3.sprite = heartEmpty;*
* return;*
* }*
* }*
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class LevelManager : MonoBehaviour {

public float waitToRespawn;
public PlayerController thePlayer;

public GameObject deathSplosion;

public int coinCount;

public Text coinText;

public Image heart1;
public Image heart2;
public Image heart3;

public Sprite heartFull;
public Sprite heartHalf;
public Sprite heartEmpty;

public int maxHealth;
public int healthCount;

private bool respawning;

public ResetOnRespawn[] objectsToReset;

public bool invincible;

public Text livesText;
public int startingLives;
public int currentLives;

// Use this for initialization
void Start () {
	thePlayer = FindObjectOfType<PlayerController> ();

	coinText.text = "Coins: " + coinCount; 

	healthCount = maxHealth;

	objectsToReset = FindObjectsOfType<ResetOnRespawn>();

	currentLives = startingLives;
	livesText.text = "Lives x " + currentLives;
}

// Update is called once per frame
void Update () {
	if (healthCount <= 0 ) 
	{
		Respawn ();
		respawning = true;
	}
}

public void Respawn()
{
	if (!respawning) {
		currentLives -= 1;
		livesText.text = "Lives x " + currentLives;

		if (currentLives > 0) {
			respawning = true;
			StartCoroutine ("RespawnCo");
		} else {
			thePlayer.gameObject.SetActive (false);
		}
	}
}

public IEnumerator RespawnCo()
{
	thePlayer.gameObject.SetActive (false);

	Instantiate (deathSplosion, thePlayer.transform.position, thePlayer.transform.rotation);

	yield return new WaitForSeconds (waitToRespawn);

	healthCount = maxHealth;
	respawning = false;
	UpdateHeartMeter ();

	coinCount = 0;
	coinText.text = "Coins: " + coinCount;

	thePlayer.transform.position = thePlayer.respawnPosition;
	thePlayer.gameObject.SetActive (true);

	for (int i = 0; i < objectsToReset.Length; i++) 
	{
		objectsToReset *.gameObject.SetActive (true);*

_ objectsToReset .ResetObject ();_
* }*
* }*
* public void AddCoins(int coinsToAdd)*
* {*
* coinCount += coinsToAdd;*
* coinText.text = "Coins: " + coinCount;*
* }*
* public void HurtPlayer(int damageToTake)*
* {*
* if (!invincible)*
* { *
* healthCount -= damageToTake;*
* UpdateHeartMeter ();*
* thePlayer.Knockback ();*
* }*
* }*
* public void UpdateHeartMeter()*
* {*
* switch (healthCount)*
* {*
* case 6:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartFull;*
* heart3.sprite = heartFull;*
* return;*
* case 5:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartFull;*
* heart3.sprite = heartHalf;*
* return;*
* case 4:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartFull;*
* heart3.sprite = heartEmpty;*
* return;*
* case 3:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartHalf;*
* heart3.sprite = heartEmpty;*
* return;*
* case 2:*
* heart1.sprite = heartFull;*
* heart2.sprite = heartEmpty;*
* heart3.sprite = heartEmpty;*
* return;*
* case 1:*
* heart1.sprite = heartHalf;*
* heart2.sprite = heartEmpty;*
* heart3.sprite = heartEmpty;*
* return;*
* case 0:*
* heart1.sprite = heartEmpty;*
* heart2.sprite = heartEmpty;*
* heart3.sprite = heartEmpty;*
* return;*
* default:*
* heart1.sprite = heartEmpty;*
* heart2.sprite = heartEmpty;*
* heart3.sprite = heartEmpty;*
* return;*
* }*
* }*
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
* public float moveSpeed;*
* public Rigidbody2D myRigidbody;*
* public float jumpSpeed;*
* public Transform groundCheck;*
* public float groundCheckRadius;*
* public LayerMask whatIsGround;*
* public bool isGrounded;*
* private Animator myAnim;*
* private Vector3 initScale;*
* public Vector3 respawnPosition;*
* public LevelManager theLevelManager;*
* public GameObject stompBox;*
* public float knockbackForce;*
* public float knockbackLength;*
* public float knockbackCounter;*
* public float invincibilityLength;*
* private float invincibilityCounter;*
* // Use this for initialization*
* void Start ()*
* {*
* myRigidbody = GetComponent ();*
* myAnim = GetComponent ();*
* initScale = transform.localScale;*
* respawnPosition = transform.position;*
* theLevelManager = FindObjectOfType();*
* }*
* // Update is called once per frame*
* void Update () {*

* isGrounded = Physics2D.OverlapCircle (groundCheck.position, groundCheckRadius, whatIsGround);*
* if (knockbackCounter <= 0)*
* {*
* if (Input.GetAxisRaw (“Horizontal”) > 0f)*
* {*
* myRigidbody.velocity = new Vector3 (moveSpeed, myRigidbody.velocity.y, 0f);*
* transform.localScale = new Vector3 (1f, 1f, 1f);*
* transform.localScale = new Vector3 (initScale.x, initScale.y, initScale.z);*
* } else if (Input.GetAxisRaw (“Horizontal”) < 0f) {*
* myRigidbody.velocity = new Vector3 (-moveSpeed, myRigidbody.velocity.y, 0f);*
* transform.localScale = new Vector3 (-1f, 1f, 1f);*
* transform.localScale = new Vector3 (-initScale.x, initScale.y, initScale.z);*
* } else {*
* myRigidbody.velocity = new Vector3 (0f, myRigidbody.velocity.y, 0f);*
* }*
* if (Input.GetButtonDown (“Jump”) && isGrounded)*
* {*
* myRigidbody.velocity = new Vector3 (myRigidbody.velocity.x, jumpSpeed, 0f);*
* }*

* }*
* if (knockbackCounter > 0)*
* {*
* knockbackCounter -= Time.deltaTime;*
* if (transform.localScale.x > 0)*
* {*
* myRigidbody.velocity = new Vector3 (-knockbackForce, knockbackForce, 0f);*
* } else {*
* myRigidbody.velocity = new Vector3 (knockbackForce, knockbackForce, 0f);*
* }*
* }*
* if (invincibilityCounter > 0)*
* {*
* invincibilityCounter -= Time.deltaTime;*
* }*
* if (invincibilityCounter <= 0)*
* {*
* theLevelManager.invincible = false;*
* }*
* myAnim.SetFloat (“Speed”, Mathf.Abs (myRigidbody.velocity.x));*
* myAnim.SetBool (“Grounded”, isGrounded);*
* if (myRigidbody.velocity.y < 0)*
* {*
* stompBox.SetActive(true);*
* }else {*
* stompBox.SetActive (false);*
* }*
* }*
* public void Knockback()*
* {*
* knockbackCounter = knockbackLength;*
* invincibilityCounter = invincibilityLength;*
* theLevelManager.invincible = true;*
* }*
* void OnTriggerEnter2D(Collider2D other)*
* {*
* if (other.tag == “KillPlane”)*
* {*
* //gameObject.SetActive (false);*
* //transform.position = respawnPosition;*
* theLevelManager.Respawn ();*
* //theLevelManager.healthCount = 0;*
* }*
* if (other.tag == “Checkpoint”)*
* {*
* respawnPosition = other.transform.position;*
* }*
* }*
* void OnCollisionEnter2D(Collision2D other)*
* {*
* if (other.gameObject.tag == “MovingPlatform”)*
* {*
* transform.parent = other.transform;*
* }*
* }*
* void OnCollisionExit2D(Collision2D other)*
* {*
* if (other.gameObject.tag == “MovingPlatform”)*
* {*
* transform.parent = null;*
* }*
* }*
}