Unity: How to speed up score countdown - c#

A quick question. I am playing with a small game from some tutorials but wanted to add a score that reduces each second. I managed to do so by the code provided below, but the score only lowers with 1 seconds at a time. I want to speed it up somehow, so it can drop each second by let's say 150. I tried a few things, but they didn't work and most of them didn't even record a change on the GUI inside the game. Any help is appreciated!
Code:
public class GameOver : MonoBehaviour {
public GameObject gameOverScreen;
public Text Score;
public Text Highscore;
bool gameOver;
private int score = 12000;
void Start () {
FindObjectOfType<PlayerController>().OnPlayerDeath += OnGameOver;
}
public void Update () {
Score.text = Mathf.Round(score - Time.timeSinceLevelLoad).ToString();
if (gameOver)
{
if (Input.GetKeyDown (KeyCode.Space))
{
SceneManager.LoadScene(1);
}
}
}
void OnGameOver()
{
gameOverScreen.SetActive (true);
Highscore.text = Mathf.Round(score - Time.timeSinceLevelLoad ).ToString();
gameOver = true;
}
}

Don't repeat yourself. Make a function to get the score.
int GetScore() {
return score - (int)Time.timeSinceLevelLoad * 150;
}
And then use it.
void Update() {
Score.text = GetScore().ToString();
}

Change this part
Score.text = Mathf.Round(score- Time.deltaTime*150).ToString();
--
public void Update () {
Score.text = Mathf.Round(score- Time.deltaTime*150).ToString();
if (gameOver)
{
if (Input.GetKeyDown (KeyCode.Space))
{
SceneManager.LoadScene(1);
}
}
}

Related

Sound is not playing After Gameover Unity

I don't know why the sound is not playing when the game is over. I am able to play sounds on the game menu and when the game start but when the game is over the sound doesn't play.
I am sure I am making some mistake, but I am not able to find where i am doing wrong.
Any help will be appreciated.
Here is the code
public static GameManager instance;
public GameObject PlatformSpawner;
public GameObject GameTapTextPanel;
public GameObject GameIntroPanel;
public GameObject scoreManagerUI;
public bool gameStarted;
public bool gameEnd;
// Start is called before the first frame update
public Text scoreText;
public Text highScoreText;
int score = 0;
int highScore;
AudioSource audioSource;
public AudioClip[] GameMusic;
void Awake()
{
if (instance == null)
{
instance = this;
}
audioSource = GetComponent<AudioSource>();
}
void Start()
{
highScore = PlayerPrefs.GetInt("HighScore");
highScoreText.text = "Best Score : " + highScore;
}
// Update is called once per frame
void Update()
{
if (!gameStarted)
{
if (Input.GetMouseButtonDown(0))
{
GameStart();
audioSource.clip = GameMusic[1];
audioSource.Play();
}
}
}
public void GameStart()
{
gameStarted = true;
PlatformSpawner.SetActive(true);
StartCoroutine(ScoreUp()); // to update the score we need to add this code;
GameTapTextPanel.SetActive(false);
scoreManagerUI.SetActive(true);
GameIntroPanel.GetComponent<Animator>().Play("TwistTurnAnim");
}
public void GameOver()
{
audioSource.clip = GameMusic[3]; //Here is the problem the sound doesn't play
audioSource.Play();
gameStarted = false;
gameEnd = true;
PlatformSpawner.SetActive(false);
scoreManagerUI.SetActive(true);
GameIntroPanel.SetActive(false);
SaveHighScore();
Invoke("ReloadLevel",1f);
StopCoroutine(ScoreUp());
}
void ReloadLevel()
{
SceneManager.LoadScene("Game");
}
//this one is used to increase score per second of the game;
IEnumerator ScoreUp()
{
while (true)
{
yield return new WaitForSeconds(1.5f);
score ++;
scoreText.text = score.ToString();
}
}
public void IncrementScore()
{
audioSource.PlayOneShot(GameMusic[2],0.4f);
score += 4; //Bonus points for game
scoreText.text = score.ToString();
}
void SaveHighScore()
{
if (PlayerPrefs.HasKey("HighScore"))
{
if (score > PlayerPrefs.GetInt("HighScore"))
{
PlayerPrefs.SetInt("HighScore", score);
}
}
else
{
PlayerPrefs.SetInt("HighScore",score);
}
}
Is the audio source part of an object that is deleted upon the Game Over condition?
The scripting API mentions that AudioSource is attached to an object.
In your method, GameOver, you are calling Invoke("ReloadLevel",1f) which will reload the scene in 1.0 seconds. Your GameMusic[3] is not playing because it doesn't have a chance to play before the scene is reloaded.

How can I tell when a number has finished increasing?

I feel like I'm missing some easy solution here, but I'm stuck on this. I'm calculating a score based on how far the player travels until they hit a building at the end of the course. The destruction score is separate from the distance score, and it increments until all of the building pieces have come to a rest.
I have an animation I want to play to add the distance score to the total destruction score and give the player's overall score, but I need the animation to trigger once the destruction score has stopped increasing. Right now, each piece of the building has code that checks if its moving and increments the score while true.
public class SkiLodgeScoreTracker : MonoBehaviour
{
Rigidbody rb;
private GameObject[] score;
private void Start()
{
rb = gameObject.GetComponent<Rigidbody>();
score = GameObject.FindGameObjectsWithTag("Score");
}
private void Update()
{
//check if lodgePiece is moving, while it is, add to Score object
if(rb.velocity.magnitude >= 2f && !rb.isKinematic)
{
score[0].GetComponent<SkiScore>().addToSkiScore(2f);
}
}
}
Here's where I want to have the animation trigger once that score has stopped (this was another attempt I made, the logic doesn't work)
public Animator moveScore;
...
if(skiScore > 0)
{
previousScore2 = previousScore1;
previousScore1 = skiScore;
if(previousScore1 == previousScore2 && !scoreMoved)
{
moveScore.SetTrigger("EndCourse");
addScoreToSkiScore();
}
}
public void addScoreToSkiScore()
{
scoreMoved = true;
for(float i = score; i>0; i--)
{
skiScore += 1;
}
}
I wanted to grab the score on one frame and see if it equals the score on the next frame and, if so, then trigger the animation, but I feel like that's not a valid option.
Any ideas?
In SkiScore, keep track of how many pieces are moving, and when a piece stops and the count becomes 0, do your thing:
public class SkiScore : MonoBehaviour
{
int movingCount;
void Start()
{
ResetMovingCount();
/* ... */
}
public void ResetMovingCount() {movingCount = 0;} // call as needed
public void OnStartedMoving() {++movingCount;}
public void OnStoppedMoving()
{
if (--movingCount == 0) OnNoneMoving();
}
void OnNoneMoving() {/* do the thing */}
/* ... */
}
For each piece, use a flag to remember if it has moved recently and if it has, and it's no longer moving, let your score manager know:
public class SkiLodgeScoreTracker : MonoBehaviour
{
Rigidbody rb;
private GameObject[] score;
// flag used to recognize newly stopped movement
bool recentlyMoving;
// cache for GetComponent
SkiScore mySkiScore
private void Start()
{
rb = gameObject.GetComponent<Rigidbody>();
score = GameObject.FindGameObjectsWithTag("Score");
// GetComponent is expensive, try not to call it in Update unless necessary
mySkiScore = score[0].GetComponent<SkiScore>();
}
private void Update()
{
//check if lodgePiece is moving, while it is, add to Score object
if(rb.velocity.magnitude >= 2f && !rb.isKinematic)
{
mySkiScore.addToSkiScore(2f);
recentlyMoving = true;
mySkiScore.OnStartedMoving();
}
else if (recentlyMoving)
{
recentlyMoving = false;
mySkiScore.OnStoppedMoving();
}
}
}

Why isn't the number subtracted in PlayerPrefs?

Hello everyone In my code, when you click on the button, a number should be subtracted and saved in PlayerPrefs , the number is subtracted, but does not save . I also learned that the number is saved when you exit the game because of the OnApplicationQuit method, how to make the number normally saved?
public class Chest_Money : MonoBehaviour
{
public int NumCharector;
public int money;
public int Rand;
public Text text;
public GameObject NotMoney;
public GameObject[] Charectors;
public GameObject Panel;
public GameObject Panel2;
public bool bla2;
void Start()
{
money = PlayerPrefs.GetInt("Money_S", 0);
}
private void Awake()
{
}
#if UNITY_ANDROID && !UNITY_EDITOR
private void OnApplicationPause(bool pause){
if(pause){
//PlayerPrefs.SetInt("Money_S" , money);
}
}
#endif
private void OnApplicationQuit()
{
PlayerPrefs.SetInt("Money_S" , money);
}
void Update()
{
PlayerPrefs.SetInt("Money_S", money);
text.text = "$:" + money;
if(bla2 == true){
Panel2.SetActive(true);
}
}
public void Chest(){
if(money >= 100){
money -= 100;
PlayerPrefs.SetInt("Money_S", money);
StartCoroutine(Wait2());
}
else {
NotMoney.SetActive(true);
StartCoroutine(Wait4());
}
}
IEnumerator Wait4(){
yield return new WaitForSeconds(2);
NotMoney.SetActive(false);
}
IEnumerator Wait2()
{
yield return new WaitForSeconds(0);
SceneManager.LoadScene("Scins");
}
}
In general you can/should use PlayerPrefs.Save to force a save on certain checkpoints
By default Unity writes preferences to disk during OnApplicationQuit(). In cases when the game crashes or otherwise prematuraly exits, you might want to write the PlayerPrefs at sensible 'checkpoints' in your game. This function will write to disk potentially causing a small hiccup, therefore it is not recommended to call during actual gameplay.
I then also suggest you rather use a property like
private int _money;
public int money
{
get => _money;
set
{
_money = value;
PlayerPrefs.SetInt("Money_S");
PlayerPrefs.Save();
text.text = "$:" + money;
}
}
So it only updates the text and saves the value once it actually changes.
This way you don't need to update the text or set the value every frame in Update.

Passing data between scenes Errors

I have made a game manager making sure my data gets passed on from the first scene on to the next scene. Within the game manager, I have added certain scripts to ensure it gets passed. As you can see in the picture underneath.
The problem is that the score adds up at the first level, let's say I have 5 points. I go to level 2 and the UI shows my score as 0 (even tho I have nothing put as text within the score text) I kill 1 monster and the UI shows 6. So how can I put the UI to be showing it at all times? (Constant refresh?)
The second problem is that while the score manager does work. The health script cancels everything out when switching levels.
The user starts with 10 health. Takes damage in the first scene, but in the second scene, the user still has 10 health for some reason?
Game Manager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour {
public ActionButton PopupPrefab;
private ActionButton currentlySpawnedPopup;
public static GameManager instance = null;
void Awake () {
if (instance == null) {
instance = this;
} else if (instance != this) {
Destroy (gameObject);
}
Application.targetFrameRate = 60;
}
void Update () {
//if (Input.GetKeyDown(KeyCode.R)) {
// RestartScene ();
//}
}
public void InvokeRestartScene (float time) {
Invoke ("RestartScene", time);
}
public void RestartScene () {
SceneManager.LoadScene (0);
}
public void SpawnPopup (Vector2 position) {
DespawnPopup ();
currentlySpawnedPopup = Instantiate (PopupPrefab, position, Quaternion.identity) as ActionButton;
}
public void DespawnPopup () {
if (currentlySpawnedPopup != null) {
currentlySpawnedPopup.DestroySelf();
currentlySpawnedPopup = null;
}
}
public void FadePopup () {
if (currentlySpawnedPopup != null) {
currentlySpawnedPopup.FadeMe ();
currentlySpawnedPopup = null;
}
}
}
Score Manager
using UnityEngine;
using System;
using System.Collections;
public class ScoreManager : MonoBehaviour
{
public static ScoreManager Instance { get; private set; }
public int Score { get; private set; }
public int HighScore { get; private set; }
public bool HasNewHighScore { get; private set; }
public static event Action<int> ScoreUpdated = delegate {};
public static event Action<int> HighscoreUpdated = delegate {};
private const string HIGHSCORE = "HIGHSCORE";
// key name to store high score in PlayerPrefs
void Awake()
{
if (Instance)
{
DestroyImmediate(gameObject);
}
else
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
}
void Start()
{
Reset();
}
public void Reset()
{
// Initialize score
Score = 0;
// Initialize highscore
HighScore = PlayerPrefs.GetInt(HIGHSCORE, 0);
HasNewHighScore = false;
}
public void AddScore(int amount)
{
Score += amount;
// Fire event
ScoreUpdated(Score);
if (Score > HighScore)
{
UpdateHighScore(Score);
HasNewHighScore = true;
}
else
{
HasNewHighScore = false;
}
}
public void UpdateHighScore(int newHighScore)
{
// Update highscore if player has made a new one
if (newHighScore > HighScore)
{
HighScore = newHighScore;
PlayerPrefs.SetInt(HIGHSCORE, HighScore);
HighscoreUpdated(HighScore);
}
}
}
Health Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class Health : MonoBehaviour {
public UnityEvent OnTakeDamageEvent;
public UnityEvent OnTakeHealEvent;
public UnityEvent OnDeathEvent;
[Header ("Max/Starting Health")]
public int maxHealth;
[Header ("Current Health")]
public int health;
[Header ("IsDeathOrNot")]
public bool dead = false;
[Header ("Invincible")]
public bool invincible = false;
public bool becomeInvincibleOnHit = false;
public float invincibleTimeOnHit = 1f;
private float invincibleTimer = 0f;
[Header ("Perform Dead Events after x time")]
public float DieEventsAfterTime = 1f;
void Start () {
health = maxHealth;
}
void Update () {
if (invincibleTimer > 0f) {
invincibleTimer -= Time.deltaTime;
if (invincibleTimer <= 0f) {
if (invincible)
invincible = false;
}
}
}
public bool TakeDamage (int amount) {
if (dead || invincible)
return false;
health = Mathf.Max (0, health - amount);
if (OnTakeDamageEvent != null)
OnTakeDamageEvent.Invoke();
if (health <= 0) {
Die ();
} else {
if (becomeInvincibleOnHit) {
invincible = true;
invincibleTimer = invincibleTimeOnHit;
}
}
return true;
}
public bool TakeHeal (int amount) {
if (dead || health == maxHealth)
return false;
health = Mathf.Min (maxHealth, health + amount);
if (OnTakeHealEvent != null)
OnTakeHealEvent.Invoke();
return true;
}
public void Die () {
dead = true;
if (CameraShaker.instance != null) {
CameraShaker.instance.InitShake(0.2f, 1f);
}
StartCoroutine (DeathEventsRoutine (DieEventsAfterTime));
}
IEnumerator DeathEventsRoutine (float time) {
yield return new WaitForSeconds (time);
if (OnDeathEvent != null)
OnDeathEvent.Invoke();
}
public void SetUIHealthBar () {
if (UIHeartsHealthBar.instance != null) {
UIHeartsHealthBar.instance.SetHearts (health);
}
}
}
I have thought of adding the following script on to my Health Script
But then I get the following error messages:
" Cannot implicitly convert type 'int' to 'bool'"
"The left-hand side of an assignment must be a variable, property or indexer"
void Awake()
{
if (health)
{
DestroyImmediate(gameObject);
}
else
{
(int)health = this;
DontDestroyOnLoad(gameObject);
}
}
The problem is that the score adds up at the first level, let's say I have 5 points. I go to level 2 and the UI shows my score as 0 (even tho I have nothing put as text within the score text) I kill 1 monster and the UI shows 6. So how can I put the UI to be showing it at all times? (Constant refresh?)
You can make one of the scripts set the UI text score when the scene is loaded.
void Start(){
// Loads the scoreText on start
scoreText.text = yourCurrentScore.ToString();
// Will work unless it has a "DontDestroyOnLoad" applied to it
}
The second problem is that while the score manager does work. The
health script cancels everything out when switching levels. The user
starts with 10 health. Takes damage in the first scene, but in the
second scene, the user still has 10 health for some reason?
In your health script, you had this:
void Start () {
health = maxHealth;
}
This resets your health everytime the scene loads and starts (Aka when you load to the next level). This causes the issue.
" Cannot implicitly convert type 'int' to 'bool'"
if (health)
The () for the if statement should be a condition (a question).
For example, doing health < 0 is valid since its saying "Is health less than 0?"
Doing health is not, since its just saying "10" (or some number).
"The left-hand side of an assignment must be a variable, property or
indexer"
(int)health = this;
If you wanted to change the value of health, just do health = 10 or health = some_Variable_That_Is_An_Integer

How to Display high score using GUIText

Well, i'm pretty new with unity. I got a problem to display highscore. The score was display everytime enemy were shot. I want to display the highscore everytime the game end and be able to update everytime i got a new highscore. The score system using the GUI text. The example below.
Score:
Highscore:
To display the score, i'm using this script
using UnityEngine;
public class HealthScript : MonoBehaviour
{
public int hp = 1;
private GUIText scoreReference;
public bool isEnemy = true;
public void Damage(int damageCount)
{
hp -= damageCount;
if (hp <= 0)
{
// Dead!
Destroy(gameObject);
scoreReference.text = (int.Parse(scoreReference.text) + 1).ToString();
}
}
void Start()
{
scoreReference = GameObject.Find("Score").guiText;
}
// . . .
}
i got some idea to retrieve the value of the score, but it won't display. Please help me.. Thanks
we put a isDead boolaen and make it true when the player dies and when isDead is true we will show the score
int score;
int highscore;
bool isDead=false;
//initilizing
void OnGUI () {
if(isDead) //make this true when player dies
GUI.Label (new Rect (0,0,100,50),score.ToString());
}
void Awake(){
highscore=PlayerPrefs.GetInt("highscore");
}
public void Damage(int damageCount)
{
hp -= damageCount;
if (hp <= 0)
{
// Dead!
Destroy(gameObject);
score++; //increase score
if(score>highscore)
highscore=score;
}
}
public void onGameEnds(){
PlayerPrefs.SetInt("highscore",highscore);
}
this will be good
get { if (_highscore == -1)
_highscore = PlayerPrefs.GetInt("Highscore", 0);
return _highscore;
}
set {
if (value > _highscore) {
_highscore = value;
highscoreReference.text = _highscore.ToString();
PlayerPrefs.SetInt("Highscore", _highscore);
}
}
}

Categories