Unity static value - c#

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;
}

Related

How to put a countdown trigger?

I just got into Game Dev and I need my script to enable when my player steps a cube trigger, but I don't know how.
This is the Script that I typed and I can't figure out if I should erase the Void Start or not?
public class CountdownTimer : MonoBehaviour {
public bool timerIsRunning;
public Text timeText;
public float timeRemaining = 10;
private void Start()
{
timerIsRunning = true;
}
void Update(){
if (timerIsRunning)
{
if (timeRemaining > 0)
{
timeRemaining -= Time.deltaTime;
DisplayTime(timeRemaining);
}
else
{
Debug.Log("Time has run out!");
timeRemaining = 0;
timerIsRunning = false;
}
}
}
void DisplayTime(float timeToDisplay){
timeToDisplay += 1;
float minutes = Mathf.FloorToInt(timeToDisplay / 60);
float seconds = Mathf.FloorToInt(timeToDisplay % 60);
timeText.text = string.Format("{0:00}:{1:00}", minutes, seconds);
}
}
I think you can make good use of a trigger collider. To do that, you need to add a collider of your choice to your zone and set it as a trigger. Be sure to have a collider and a rigidbody on your player.
Then in your script you can use the function OnTriggerEnter who will be called when an object enter in your zone defined by your trigger collider.
For your countdown method, you can make good use of a couroutine. It will look like this :
IEnumerator DisplayTime() {
timeIsRunning = true;
for (int i = 0; i < timeRemaining; i++) {
// your code to change the text
yield return new WaitForSeconds(1);
}
timeIsRunning = false;
}
private void OnColliderEnter(Collider other) {
if(!timeIsRunning) {
StartCouroutine(DisplayTime());
}
}
What this code does is when an object enter in the trigger, it starts a routine who will update the time displayed each second until the countdown is finished.
With that you won't need your Start and your Update methods anymore.
If you want more informations on trigger collider : https://docs.unity3d.com/ScriptReference/Collider-isTrigger.html
If you want more informations on couroutines : https://docs.unity3d.com/Manual/Coroutines.html
If you want more informations on the method OnTriggerEnter : https://docs.unity3d.com/ScriptReference/Collider.OnTriggerEnter.html

Prevent a player from spamming a key in C# (Unity)

I am currently doing the tutorial learn with code from unity, in this section there are bonus challenges, that do not help you in resolving it. It says that i have to prevent the player from spamming the spacebar key to spawn dogs.
I am new to C#, i started to looking online but i see something about CoRoutines and i still dont know what that is, is there a simple way to do this, searching online i found something like this, but i cant make it work.
I also tried to make some conditional like canSpawn but i do not know how to implement it well, and Unity gives me an error that i cant use && between a bool and a keypress event
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControllerX : MonoBehaviour
{
public GameObject dogPrefab;
public float time = 2.0f;
public float timer = Time.time;
// Update is called once per frame
void Update()
{
timer -= Time.deltaTime;
if (timer > time)
{
// On spacebar press, send dog
if (Input.GetKeyDown(KeyCode.Space))
{
spawnDog();
}
timer = time;
}
void spawnDog()
{
Instantiate(dogPrefab, transform.position, dogPrefab.transform.rotation);
}
}
You were close. One thing that might make it easier to understand the logic, is to just count up instead of trying to count down. So, in your case, the code would look like this:
void Update ( )
{
timer += Time.deltaTime;
if ( timer >= time )
{
if ( Input.GetKeyDown ( KeyCode.Space ) )
{
spawnDog ( );
timer = 0;
}
}
}
void spawnDog ( )
{
Instantiate ( dogPrefab, transform.position, dogPrefab.transform.rotation );
}
The timer keeps being added to, and when it's greater than your time value (in this case 2.0f), it allows you to press a key. IF a key is then pressed, the timer is reset to 0, and the player needs to wait time time (2.0f) before being able to press the space key again.
I used Coroutines for this task, it has a little bit more code but it works nicely.
public class PlayerControllerX : MonoBehaviour
{
public GameObject dogPrefab;
private bool isCoolDown = false;
private float coolDown = 1f;
private void Update( )
{
if (Input.GetKeyDown(KeyCode.Space))
{
if (isCoolDown == false)
{
SpawnDog( );
StartCoroutine(CoolDown( ));
}
}
}
IEnumerator CoolDown( )
{
isCoolDown = true;
yield return new WaitForSeconds(coolDown);
isCoolDown = false;
}
private void SpawnDog( )
{
Instantiated(dogPrefab, transform.position, dogPrefab.transform.rotation);
}
}
I am using my phone. I am sorry if i made some syntax error.
bool isReadyForInstantiate;
void Start(){
isReadyForInstantiate = true;
}
void Update(){
if(isReadyForInstantiate && Input.GetKeyDown(KeyCode.Space)){
StartCoroutine(PreventSpam());
Instantiate(dogPrefab, transform.position, Quaternion.identity);
}
}
IEnumerator PreventSpam(){
isReadyForInstantiate = false;
yield return new WaitForSeconds(2);
isReadyForInstantiate = true;
}
here my solution based on a StopWatch:
using UnityEngine;
using System.Diagnostics; // hides UnityEngine.Debug. if needed use qualified call
public class PlayerControllerX : MonoBehaviour
{
public GameObject dogPrefab;
public double dogDelayMillis = 2000d;
private Stopwatch stopWatch;
private void Start()
{
stopWatch = new Stopwatch();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
if (stopWatch.IsRunning)
{
if (stopWatch.Elapsed.TotalMilliseconds > dogDelayMillis)
{
stopWatch.Reset();
SpawnDog();
}
}
else
{
SpawnDog();
}
}
}
private void SpawnDog()
{
stopWatch.Start();
Instantiate(dogPrefab, transform.position, dogPrefab.transform.rotation);
}
}
Another example just for fun
public GameObject dogPrefab;
[Range(0f,2f)]
private float timer = 1.0f;
private float waitTime = 1.0f;
// Update is called once per frame
void Update()
{
// Delay Input Timer - only execute the spacebar command if timer has caught up with waitTime
if (timer < waitTime)
{}
// On spacebar press, send dog
else if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(dogPrefab, transform.position, dogPrefab.transform.rotation);
// Resets Timer
timer = 0;
}
// Run Timer every frame
timer += Time.deltaTime;
Debug.Log(timer);
}
}
I was stuck on the same exact thing, thank you. The code below is what I went with because it's short and sweet.
public GameObject dogPrefab;
[Range(0f,2f)]
private float timer = 1.0f;
private float waitTime = 1.0f;
// Update is called once per frame
void Update()
{
// Delay Input Timer - only execute the spacebar command if timer has caught up with waitTime
if (timer < waitTime)
{}
// On spacebar press, send dog
else if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(dogPrefab, transform.position, dogPrefab.transform.rotation);
// Resets Timer
timer = 0;
}
// Run Timer every frame
timer += Time.deltaTime;
Debug.Log(timer);
}
}

Unity c# set timer on background even if game is not active

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.

How to delay start for x seconds?

I've searched around and couldn't quite find the answer. I have two scenes, one with a play button which starts the next scene (the game) and the other scene is the game. Which has a spawner script which spawns random patterns of obsticles. Which can be seen here.
public class Spawner : MonoBehaviour {
public GameObject[] obstaclePatterns;
private float timeBtwSpawn;
public float startTimeBtwSpawn;
public float decreaseTime;
public float minTime = 0.55f;
private void Update()
{
if (timeBtwSpawn <= 0)
{
int rand = Random.Range(0, obstaclePatterns.Length);
Instantiate(obstaclePatterns[rand], transform.position, Quaternion.identity);
timeBtwSpawn = startTimeBtwSpawn;
if (startTimeBtwSpawn > minTime) {
startTimeBtwSpawn -= decreaseTime;
}
}
else {
timeBtwSpawn -= Time.deltaTime;
}
}}
I would like to after the play button is pressed and the game is started there be a delay for 1 second before the spawner begins spawning. I'm not sure how to do that. Any help would be appreciated.
You can use Unity's Start function as a coroutine directly.
private bool _canStart;
private IEnumerator Start()
{
yield return new WaitForSeconds(whatyouwant);
_canStart = true;
}
private void Update()
{
if(!_canStart) return;
whatyouwant
}
if you want to have a routine that starts after a specific amount of time since the scene was loaded you can use Time.timeSinceLevelLoad this variable holds the time in seconds since the last level(scene) was loaded
So you can either create a script that activates your spawner script or add an additional check to your spawner script
You should set timeBtwSpawn before start updating of Spawner:
timeBtwSpawn = 1; // seconds

Cooldown timer doubles in speed every time my startup countdown is executed

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;
}
}
}

Categories