When the player dies, one heart is removed from the health bar. A cool down timer starts that will refill the heart after 5 minutes. If the player should die again, the second heart will be removed but the timer will first finish its current cool down before restarting.
When the player dies the second time, the scene reloads and a countdown is shown to give the player time to get ready for the next try.
The problem is as soon as the countdown is finished and the timescale is set to 1, the cool down timer speed increases. If he dies again the timer speed increases again, till the first cool down timer completes and then resets and start the next cool down, then the speed is back to normal or if I exit the game and re-enter the timer is back to normal.
When the scene loads the timescale is 0. The countdown animation runs using a Mycoroutine script. After the animation is finished the timescale is set back to 1.
The cool down timer takes into account the time that a player is offline using a TimerMaster script and works 100%. Tested it on android and if the game moves to the background the timer works fine, using Time.unscaledDeltaTime instead of Time.DeltaTime.
The only problem I can't figure out is the speed increase every time the level restarts.
//this is used to call the countdown
public bool setCoundown = false;
void Start()
{
countDown.SetActive(true); //when active it sets setCountdown to true
Time.timeScale = 0;
}
void Update()
{
if (setCoundown)
{
StartCoroutine(CountDown()); //set the timer to wait till the countdown is done
}
}
IEnumerator CountDown()
{
while (setCoundown == true)
{
yield return StartCoroutine(Mycoroutine.WaitforRealSeconds(0.5f));
setCoundown = false;
Time.timeScale = 1;
RunGame();
}
}
//This script is called by CountDown()
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class Mycoroutine
{
public static IEnumerator WaitforRealSeconds(float time)
{
float start = Time.realtimeSinceStartup;
while(Time.realtimeSinceStartup < (start + time))
{
yield return null;
}
}
}
//This is the cool down timer
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class TimerText : MonoBehaviour
public static TimerText instance;
[SerializeField]
private Text timeText;
private int health;
private float timer, minutes, seconds;
void Start()
{
//get saved time that was needed to fill all health
timer = GameController.instance.GetTimerTime();
//deduct the offline time from the needed time
timer = timer - TimerMaster.instance.CheckDate();
//call the function to calculate offline time and set lives and timer value accordingly if the health is full then the timer value will be 300
DateTimer();
}
void Update()
{
health = GameController.instance.GetHealth();
if (health < 3 && timeText.text == "0:00")
{
StartCoundownTimer();
}
}
void StartCoundownTimer()
{
if (timeText != null)
{
timeText.text = "0:00";
InvokeRepeating("UpdateTimer", 0.0f, 0.01667f);
}
}
void UpdateTimer()
{
if (timeText != null)
{
timer -= Math.Max(Time.unscaledDeltaTime, 0);
timeText.text = string.Format("{0}:{1:00}", (int)(timer / 60), (int)(timer % 60));
if (timeText.text == "0:00")
{
CancelInvoke();
health = GameController.instance.GetHealth() + 1;
GameController.instance.SetHealth(health);
timer = 300;
}
}
}
Related
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FallingObject : MonoBehaviour
{
// Variables
float timer = 0;
MeshRenderer renderer;
Rigidbody rigidbody;
// Start is called before the first frame update
void Start()
{
// Cached References
renderer = GetComponent<MeshRenderer>();
rigidbody = GetComponent<Rigidbody>();
rigidbody.useGravity = false;
}
// Update is called once per frame
void Update()
{
// Setup to make a timer work every 5 seconds
timer = timer + Time.deltaTime;
if((timer >= 6) && (rigidbody.useGravity = false))
{
// Makes the item fall after 3 seconds
Debug.Log("3 seconds have passed, now resetting timer.");
rigidbody.useGravity = true;
timer = 0;
}
if((timer >= 1.25) && (rigidbody.useGravity = true))
{
// Waits for the item to hit the ground and then resets it
Debug.Log("1 seconds have passed, now resetting timer.");
rigidbody.useGravity = false;
timer = 0;
transform.Translate(0,5,0);
}
}
}
The comments explain most of what the code is supposed to do, essentially just use Time.deltaTime to create a timer that will alternate between waiting approximately 5 seconds to remove gravity and make the object fall and waiting approximately 1 second to let the object fall to the ground and then resetting said object. For some reason, the code only wants to execute the second if statement, so I'm guessing something is wrong with the rigidbody.useGravity variable. I'm a little new to coding.
Change value assignment to a conditional.
public class FallingObject : MonoBehaviour
{
// Variables
float timer = 0;
MeshRenderer renderer;
Rigidbody rigidbody;
// Start is called before the first frame update
void Start()
{
// Cached References
renderer = GetComponent<MeshRenderer>();
rigidbody = GetComponent<Rigidbody>();
rigidbody.useGravity = false;
}
// Update is called once per frame
void Update()
{
// Setup to make a timer work every 5 seconds
timer = timer + Time.deltaTime;
//Here is where you'd get rid of the value assignment.
if((timer >= 6) && (rigidbody.useGravity == false))
{
// Makes the item fall after 3 seconds
Debug.Log("3 seconds have passed, now resetting timer.");
rigidbody.useGravity = true;
timer = 0;
}
//Here is where you'd get rid of the value assignment.
if((timer >= 1.25) && (rigidbody.useGravity == true))
{
// Waits for the item to hit the ground and then resets it
Debug.Log("1 seconds have passed, now resetting timer.");
rigidbody.useGravity = false;
timer = 0;
transform.Translate(0,5,0);
}
}
}
If the boolean is not null-able or a three-state then you can also write it like this.
...
if((timer >= 6) && !rigidbody.useGravity)
{
...
...
if((timer >= 1.25) && rigidbody.useGravity)
{
...
Visual Studio Green Squiggles Warning article I was talking about in the comment.
This is the script of a ball game that I am building.
The game is supposed to pause once it hits Time.timescale but it doesn't.
I need to know what I did wrong and what I need to change here.
I am a beginner in Unity and C# so i might have messed up everything.
If there is any other way to pause the game rather than using Time.timescale i would like to know it also.
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class PauseScript : MonoBehaviour
{
public bool paused = false;
void Start()
{
paused = false;
Time.timeScale = 1;
}
// Update is called once per frame
public void Pause()
{
if (Input.GetKeyDown("p") && paused == false)
{
Time.timeScale = 0;
paused = true;
}
if (Input.GetKeyDown("p") && paused == true)
{
Time.timeScale = 1;
paused = false;
}
}
}
Ball.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
public class Ball : MonoBehaviour
{
//configuration parameter
[SerializeField] Paddle paddleInitial;
[SerializeField] float horizontalPush = 2f;
[SerializeField] float verticalPush = 15f;
[SerializeField] AudioClip[] ballSounds;
//state parameter
Vector2 paddleToBallVector;
bool mouseButtonClicked = false;
//Cached COmponent References
AudioSource myAudioSource;
// Start is called before the first frame update
void Start()
{
paddleToBallVector = transform.position - paddleInitial.transform.position;
myAudioSource = GetComponent<AudioSource>();
}
// Update is called once per frame
void Update()
{
if (mouseButtonClicked == false)
{
stickBallToPaddle();
launchOnMouseClick();
}
if (Input.GetMouseButtonDown(1))
{
GetComponent<Rigidbody2D>().velocity = new Vector2(horizontalPush,verticalPush);
}
}
private void launchOnMouseClick()
{
if (Input.GetMouseButtonDown(0))
{
mouseButtonClicked = true;
GetComponent<Rigidbody2D>().velocity = new Vector2(horizontalPush, verticalPush);
}
}
private void stickBallToPaddle()
{
Vector2 paddlePosition = new Vector2(paddleInitial.transform.position.x, paddleInitial.transform.position.y);
transform.position = paddlePosition + paddleToBallVector;
}
//audio settings
private void OnCollisionEnter2D(Collision2D collision)
{
if (mouseButtonClicked)
{
AudioClip clip = ballSounds[UnityEngine.Random.Range(0, ballSounds.Length)];
myAudioSource.PlayOneShot(clip);
}
}
}
There are a couple of potential issues.
Your function should be called Update, or it won't run once per frame
Input.GetKeyDown returns if a key has started being pressed, but this persists on the current frame (it's only reset before the next Update call, so it will return true every time you call it in the same Update function block)
When you hit P, you check if the key is down then set the pause flag/timescale, but then you do another if check in the update method that does the opposite.
// Update is called once per frame
public void Pause()
{
// The p key is down and the game isn't paused, set timescale to 0 and paused to true...
if (Input.GetKeyDown("p") && paused == false)
{
Time.timeScale = 0;
paused = true;
}
// The p key is still down since we are on the same frame and paused flag is set so here we set timescale to 1 and paused to false...
if (Input.GetKeyDown("p") && paused == true)
{
Time.timeScale = 1;
paused = false;
}
}
You probably want to make sure only one of these conditions runs per update and ensure the function is called Update or it won't run once per frame
// Update is called once per frame
public void Update()
{
if (Input.GetKeyDown("p") && paused == false)
{
Time.timeScale = 0;
paused = true;
}
// Use else to make sure this block only gets executed if the above doesn't
else if (Input.GetKeyDown("p") && paused == true)
{
Time.timeScale = 1;
paused = false;
}
}
There are many ways to skin a cat so to speak; alternative code could look something like this:
public void Update()
{
if(Input.GetKeyDown("p"))
{
// Toggle paused
paused != paused;
// Use ternary operator to save lines because making code harder to read is fun
Time.timeScale = paused ? 0 : 1;
}
}
-- Edit:
Also make sure you are multiplying any vectors for movement etc by deltaTime each frame - otherwise your simulation will continue.
You may also need to explicitly handle paused for other aspects such as animations etc - it depends on how they are implemented, but as long as they consider the delta frame by frame they will react when timeScale is set to 0 as expected.
I have a countdown timer, and when that timer end it goes to a game over scene that i can press to exit. The problem is when i try to start a new game it goes automatically to the game over scene because the time already passed.
private static float timer = 30f;
void Update ()
{
timer -= Time.deltaTime;
timerSeconds.text = timer.ToString("f0");
if (timer <= 0)
{
Application.LoadLevel (LevelToLoad);
}
}
How do reset it properly?
You never reset the timer and since it is static it keeps it's value after scene changes.
Depending a bit on your exact needs
Either simply don't make it static
reset it on game over
if (timer <= 0)
{
timer = 30f;
Application.LoadLevel (LevelToLoad);
}
reset it at the start of a scene
private void Start()
{
timer = 30;
}
I have a game where I have time to give energy. My timer works fine when game is active but when game is inactive the time pauses and after I start game again the timer starts from wher it was left.
I want keep timer going even if the game is inactive and add energy.
using System;
using UnityEngine;
using UnityEngine.UI;
public class EnergyAdder : MonoBehaviour
{
// Start is called before the first frame update
public float waitTime = 600;
Timer timer;
public GameRoot gameRoot;
void Awake()
{
//timer = new Timer(waitTime);
float remainingTime = PlayerPrefs.GetFloat("TimeOnExit");
timer = new Timer(remainingTime);
}
// Update is called once per frame
void Update()
{
if (gameRoot.energyCap >= 5)
{
GetComponent<Text>().text = "Full";
timer.refresh();
}
else
{
timer.countDown();
if (timer.isFinished())
{
timer = new Timer(waitTime);
timer.refresh();
gameRoot.AddEnergy(1);
}
UpdateClock();
}
}
void UpdateClock()
{
int seconds = ((int)timer.timeLeft) % 60;
int minutes = (int)(timer.timeLeft / 60);
GetComponent<Text>().text = minutes.ToString() + ":" + seconds.ToString("00");
}
void OnApplicationQuit()
{
PlayerPrefs.SetFloat("TimeOnExit", timer.timeLeft);
}
}
Please help I'm new to unity and c#.
What you are doing is saving time value when you left, and load that value when you start the game again.
Maybe you should (when start the game) compare that loaded time with the current time, the difference will be the time elapsed.
I am writing a pause button for my game (Game for mobile phones).
My Pause script:
using UnityEngine;
using System.Collections;
public class PauseScript : MonoBehaviour {
public bool paused;
// Use this for initialization
void Start () {
paused = false;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
paused = !paused;
}
if (paused)
{
Time.timeScale = 0;
}
else if (!paused)
{
Time.timeScale = 1;
}
}
public void Pause()
{
paused = !paused;
if (paused)
{
Time.timeScale = 0;
}
else if (!paused)
{
Time.timeScale = 1;
}
}
}
And Jump that is written like this jump = Input.GetButton("Fire1");
When I touch button my player jumps and the game does not pause.
How I can make my game pause and player doesn't jump?
Unity Docs: Time.timeScale
Except for realtimeSinceStartup, timeScale affects all the time and delta time measuring variables of the Time class.
if you want to actually use timeScale you need to use Time.deltaTime in your calculations. Like:
transfomr.position += Vector3.forward * speed * Time.deltaTime;
so, it's not going to magically pause all the scripts. Update(), FixedUpdate() and all the other MonoBehaviour functions will still get invoked normally. also, read about Time.deltaTime if you haven't already.