Im making a endless runner game and am using a 'ScoreManager' object with a box collider 2d set to 'is trigger' increasing the score every time a object hits it. But I want it to stop increasing the score if the health reaches 0. This is the ScoreManager code:
public int score;
public Text scoreDisplay;
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Obstacle"))
{
score++;
}
}
private void Update()
{
scoreDisplay.text = score.ToString();
}
I would like to add a:
public int health = 3;
and in the Update function:
if (health <= 0) {
Destroy(gameObject);
}
But that doesn't seem to work.
The health is displayed in a player script.
public class Player : MonoBehaviour
{
private Vector2 targetPos;
public float Yincrement;
public float speed;
public float maxHeight;
public float minHeight;
public Text healthDisplay;
public GameObject gameOver;
public int health = 3;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
private void Update()
{
healthDisplay.text = health.ToString();
if (health <= 0) {
gameOver.SetActive(true);
Destroy(gameObject);
}
Any thoughts?
Wherever your health is defined, substitute it by a property that launches an event whenever set to a value < 0. Like this:
public class Player : MonoBehavior
{
public delegate void PlayerDiedDelegate();
public static event PlayerDiedDelegate onPlayerDied;
private int _health;
public int health
{
get
{
return _health;
}
set
{
_health = value;
if(_health < 0)
{
onPlayerDied?.Invoke();
}
}
}
}
Now you can attach any controller in your scene to the event:
public class ScoreController : MonoBehavior
{
private void Awake()
{
Player.onPlayerDied += OnPlayerDied;
}
private void OnPlayerDied()
{
// Put your logic here: stop collecting score etc.
}
}
Related
I am a newbie and I am making this android game that if the player has destroyed a meteor, a score is added to its score, well the problem is that I want to display the score in my scoreText, but whenever I initialize it in my Update(), it rapidly adds the score in my scoreText. I just cant figure out how to properly add the score to my scoreText This is my game manager script
public class GameManager : MonoBehaviour
{
public static int displayScores;
public int displayTheScore;
public Text scoreText;
// Start is called before the first frame update
void Start()
{
scoreText.text = "" + displayScores;
}
void Update(){
scoreText.text = "" + displayScores;
displayScores += Meteor.displayScore;
}
}
And this is the script to making the conditions that if the meteor is detroyed, a score is added to displayScore depending on the hits to the meteor
public class Meteor : MonoBehaviour
{
public int maxHealth;
public int currentHealth;
public float speed;
public int hits = 0;
public int score = 100;
public static int displayScore;
public int display;
public int currentHealthChecker;
public static int counter;
public Health healthBar;
public GameObject canvas;
public Transform effect;
// Start is called before the first frame update
void Start()
{
currentHealth = maxHealth;
healthBar.setMaxHealth(maxHealth);
}
// Update is called once per frame
void Update()
{
transform.Translate(Vector2.down * speed * Time.deltaTime);
}
public void OnTriggerEnter2D(Collider2D other){
if(other.transform.tag == "bullet"){
hits++;
canvas.SetActive(true);
currentHealth--;
currentHealthChecker = currentHealth;
healthBar.setHealth(currentHealth);
display = displayScore;
if(currentHealth <= 0){
displayScore = score * hits;
Instantiate(effect, other.transform.position, other.transform.rotation);
Destroy(this.gameObject);
counter++;
canvas.SetActive(false);
}
Destroy(other.gameObject);
}
if(other.transform.tag == "bottom"){
Destroy(this.gameObject);
}
}
}
you are initializing in update method, that why it keeps adding rapidly because update is called every frame. instead of adding in update, add the score value in ontriggerenter2d method.
public void OnTriggerEnter2D(Collider2D other){
if(other.transform.tag == "bullet"){//add score}
I'm new to Unity and together with a few friends, I try to make a game. I was trying to connect the healthbar I made to the damage u can deal by shooting knifes. First to test this I used:
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse1))
{
TakeDamage(25);
}
}
Everything worked fine and when I pressed Mouse1 the healthbar worked.My goal was, that when a knife hits the enemy 25 damage is dealt and the healthbar shows that the enemy lost health. However, when the knifes hit the enemy nothing happens. Can you please help me because I tried fixing this for like 3 hours and I'm getting kinda frustrated. Thank you.
Here's the code for the healthbar:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class healthbar : MonoBehaviour
{
public Slider slider;
public void SetMaxHealth(int health)
{
slider.maxValue = health;
slider.value = health;
}
public void SetHealth(int health)
{
slider.value = health;
}
}
And here's the code for the enemy:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy_Follow : MonoBehaviour
{
public float speed;
public Transform target;
public int damage = 25;
public int maxHealth = 100;
public int currentHealth;
public healthbar healthBar;
// Start is called before the first frame update
void Start()
{
currentHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
target = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse1))
{
TakeDamage(25);
}
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
}
public void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Knife")
{
TakeDamage(25);
}
}
public void TakeDamage(int damage)
{
currentHealth -= damage;
healthBar.SetHealth(currentHealth);
}
}
After finding out that your colliders are not triggers it should rather be OnCollisionEnter2D like e.g.
public void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Knife"))
{
TakeDamage(25);
}
}
See also Colliders -> Collision Action Matrix
You may try this code to look if the slider works at all. If this code does work (You can change things with the inspector) then it should be an error with the collision/trigger detection and nothing else.
public class SliderTest : MonoBehaviour {
public Slider slider;
public int maxHealth = 100;
private int currentHealth = 100;
public bool resetHealth = false;
public bool damage = false;
void Start() {
slider = GetComponent<Slider>();
SetMaxHealth(maxHealth);
}
void Update() {
if(resetHealth) {
resetHealth = false;
SetHealth(maxHealth);
}
if(damage) {
damage = false;
SetHealth(currentHealth-10);
}
}
public void SetMaxHealth(int health) {
slider.maxValue = health;
slider.value = 100;
}
public void SetHealth(int health) {
currentHealth = health;
slider.value = currentHealth;
}
}
}
I want to set the a score to zero whenever a certain button is pressed.
This is the script I made:
public class zeroOut : MonoBehaviour
{
private Rigidbody2D rb;
void OnMouseDown()
{
scoreScript.scoreValue -= scoreScript.scoreValue;
}
}
This is the scoreScript:
public class scoreScript : MonoBehaviour
{
public static int scoreValue = 0;
Text score;
// Start is called before the first frame update
void Start()
{
score = GetComponent<Text> ();
}
// Update is called once per frame
void Update()
{
score.text = "" + scoreValue;
}
}
Have you got any suggestions?
So I put the object in the scene and then I made it "invisible" (deactivate if you will) from the inspector (the checkmark box next to the object's name) and after waiting 8 seconds it doesn't become visible. I am using Unity 2d and C#.
I have the game start paused for three seconds then plays after that which works. The first script is that one. The item is supposed to reappear after 8 seconds so after the game resumes, which doesn't work.
//delay before level starts script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class countDown : MonoBehaviour
{
public GameObject CountDown;
private void Start()
{
StartCoroutine("StartDelay");
}
void Update()
{
}
IEnumerator StartDelay()
{
Time.timeScale = 0;
float pauseTime = Time.realtimeSinceStartup + 3f;
while (Time.realtimeSinceStartup < pauseTime)
yield return 0;
CountDown.gameObject.SetActive(false);
Time.timeScale = 1;
}
{
//script for the flower to appear
IEnumerator Start()
{
print(Time.time);
yield return new WaitForSeconds(8);
print(Time.time);
flowerInScene.gameObject.SetActive(true);
}
[SerializeField] Transform flowerInScene;
}
I still don't really get your two methods called Start
You can simply call a StartCoroutine at the end of another Coroutine so you can chain them together (though there are surely better ways to do what you want in general):
using System.Collections;
using UnityEngine;
public class CountDown : MonoBehaviour
{
public GameObject CountDownObject;
public GameObject flowerObject;
private void Start()
{
StartCoroutine(Delay());
}
private IEnumerator Delay()
{
yield return new WaitForSeconds(3);
HideCountdown();
StartCoroutine(FlowerDelay());
}
private void HideCountdown()
{
CountDownObject.SetActive(false);
}
private IEnumerator FlowerDelay()
{
yield return new WaitForSeconds(8);
ShowFlower();
}
private void ShowFlower()
{
flowerObject.SetActive(true);
}
}
I personaly don't like Coroutines .. they are not so easy to debug sometimes. I would prefer doing something like this with simple timers (though in the first moment it does look worse). Advantage is I can now directly watch the timer count down in the inspector:
using UnityEngine;
public class SimpleCountDown : MonoBehaviour
{
[Header("The Objects")]
public GameObject CountDownObject;
public GameObject FlowerObject;
[Header("Settings")]
// Here you can adjust the delay times
public float StartOffset = 3;
public float FlowerOffset = 8;
[Header("Debug")]
public float startTimer;
public float flowerTimer;
public bool isStartDelay;
public bool isFlowerDelay;
private void Start()
{
startTimer = StartOffset;
flowerTimer = FlowerOffset;
isStartDelay = true;
}
private void Update()
{
if (!isStartDelay && !isFlowerDelay) return;
if (isStartDelay)
{
startTimer -= Time.deltaTime;
if (startTimer <= 0)
{
HideCountdown();
isStartDelay = false;
isFlowerDelay = true;
}
}
if (isFlowerDelay)
{
flowerTimer -= Time.deltaTime;
if (flowerTimer <= 0)
{
ShowFlower();
isFlowerDelay = false;
this.enabled = false;
}
}
}
private void HideCountdown()
{
CountDownObject.SetActive(false);
}
private void ShowFlower()
{
FlowerObject.SetActive(true);
}
}
I currently have a 2d platformer, where the player is given 9 lives on start, and loses a life everytime they hit an obstacle.
The GameManager script stores and displays the health and the Entity script updates the health in GameManager if the player loses a life.
If the player loses a life, they can respawn in that level.
On completion of a level, the player goes to a new scene "Level Complete", where they can choose to continue to the next level or quit the game.
However, when the player continues to the next level, the currentHealth variable does not persist and resets to 0.
I know WHY this problem is occurring, but I do not know how to fix it.
currentHealth is not being called anywhere in LevelComplete, so on Start in GameManager, it has lost the value of currentHealth.
I can't call GameManager on LevelComplete because it will spawn the player. So I'm not sure how to pass the variable.
Here are my scripts.
Game Manager
using UnityEngine.UI;
using System.Collections;
public class GameManager : MonoBehaviour {
public GameObject player;
private GameCamera cam;
private GameObject currentPlayer;
private Vector3 checkpoint;
public Text livesText;
private Entity livesCount;
public static int startHealth = 9;
public int currentHealth;
public bool playerDeath = false;
public static int levelCount = 2;
public static int currentLevel = 1;
void Start () {
cam = GetComponent<GameCamera> ();
livesText.text = currentHealth.ToString ();
if(GameObject.FindGameObjectWithTag("Spawn")){
checkpoint = GameObject.FindGameObjectWithTag("Spawn").transform.position;
}
SpawnPlayer (checkpoint);
}
private void SpawnPlayer(Vector3 spawnPos) {
currentPlayer = Instantiate (player, spawnPos, Quaternion.identity) as GameObject;
cam.setTarget(currentPlayer.transform);
}
public void Update(){
if(!currentPlayer){
if (Input.GetButtonDown ("Respawn")) {
playerDeath = false;
SpawnPlayer (checkpoint);
}
}
if (playerDeath) {
Destroy (currentPlayer);
}
if (currentPlayer) {
currentHealth = currentPlayer.GetComponent<Entity> ().GetHealth ();
}
livesText.text = currentHealth.ToString ();
}
public void SetCheckPoint(Vector3 cp){
checkpoint = cp;
}
public void EndLevel(){
if(currentLevel < levelCount){
currentLevel++;
Application.LoadLevel("Level Complete");
}
else{
Application.LoadLevel("Game Complete");
}
}
}
Entity
using UnityEngine;
using System.Collections;
public class Entity : MonoBehaviour {
public static int currHealth;
private int checkHealth; //Make sure 0 < health < 9
public void ModifyHealth(int amount){
checkHealth = currHealth + amount;
if (checkHealth >= 9) {
currHealth = 9; //Health can't be greater than 9
}
else if(checkHealth <= 0){
Die (); //End game if health is less than or equal to 0
}
else{
currHealth = checkHealth; //Otherwise, update Health
}
}
public int GetHealth(){
return currHealth;
}
public void SetHealth(int currentHealth){
currHealth = currentHealth;
}
public void Die(){
Application.LoadLevel ("Game Over");
}
}
Level Complete
using UnityEngine;
using System.Collections;
public class LevelComplete : MonoBehaviour {
public GUISkin gSkin;
void OnGUI(){
GUI.skin = gSkin;
if(GUI.Button(new Rect((Screen.width/2) - Screen.width *0.15f,Screen.height/2 - Screen.height *0.05f,Screen.width*0.3f,Screen.height*0.1f),"Next Level")){
Application.LoadLevel ("Level 2");
}
if(GUI.Button(new Rect((Screen.width/2) - Screen.width *0.15f,Screen.height/2 + 20.0f,Screen.width*0.3f,Screen.height*0.1f),"Quit")){
Application.Quit ();
}
}
}