Repeating countdown timer unity - c#

I'm new to unity. My intention is to make a countdown timer start with 5 seconds and after it reached to zero I need to restart again from 5 repeatedly. Help me with this thank you.
my current code:
private bool stopTimer;
[HideInInspector]public float time1;
private float deltaT;
void Start()
{
stopTimer = false;
timerSlider.maxValue = gameTime;
timerSlider.value = gameTime;
}
// Update is called once per frame
public void Update()
{
deltaT = Time.time;
timerR();
}
public void timerR()
{
time1 = gameTime - deltaT;
Debug.Log(time1);
int minutes = Mathf.FloorToInt(time1 / 60);
int seconds = Mathf.FloorToInt(time1 - minutes * 60f);
string textTime = string.Format("{0:0}:{1:00}", minutes, seconds);
if (time1 <= 0)
{
stopTimer = true;
}
if (stopTimer == false)
{
timerText.text = textTime;
timerSlider.value = time1;
}
}
}

You can use the power of Coroutine and some handy C# classes like TimeSpan and Stopwatch, something like below code.
using System;
using System.Collections;
using System.Diagnostics;
using UnityEngine;
using UnityEngine.UI;
public class CountDown : MonoBehaviour
{
public Text text;
public int secounds = 5;
public int waitSecOnEachRound = 1;
readonly Stopwatch timer = new Stopwatch();
void Start()
{
StartCoroutine(CounDowntStarter());
}
IEnumerator CounDowntStarter()
{
TimeSpan timeStart = TimeSpan.FromSeconds(secounds);
while (true)
{
timer.Restart();
while (timer.Elapsed.TotalSeconds <= secounds)
{
yield return new WaitForSeconds(0.01f);
timeStart = TimeSpan.FromSeconds(secounds - Math.Floor(timer.Elapsed.TotalSeconds));
text.text = string.Format("{0:00} : {1:00}", timeStart.Minutes, timeStart.Seconds);
}
yield return new WaitForSeconds(waitSecOnEachRound);
}
}
}

In this web you have a simple timer:
https://answers.unity.com/questions/351420/simple-timer-1.html
Here my example code:
float actualtime=0; #Time in the coundownt that we have now
public float maxtime=5;
float actualtimedelta=0;
string texTime
void Update()
{
actualtime=Time.deltaTime-actualtimedelta
if(actualtime>=5)
{
actualtimedelta=Time.deltatime
textTime ="00:00";
}
else
{
actualtime= maxtime-actualtime;
int seconds= Mathf.FloorToInt(actualtime);
int miliseconds=Mathf.FloorToInt((actualtime -seconds)*100)
texTime= string.Format("{0:0}:{1:00}", seconds, miliseconds);
}
}

Related

Unity Displaying Best Times

I am creating a small game with five levels and a timer to see how fast the player can complete all five levels. I have a script that is supposed to take the finished time from the timer and convert it to a PlayerPref so that it can always be saved to the leaderboard. Eash leaderboard entry is its own separate text object, with its own script.
public class ScoreTimer01 : MonoBehaviour
{
public Text theText;
public void Awake()
{
theText.text = GetComponent<Text>().text;
if (PlayerPrefs.HasKey("time0"))
{
theText.text = PlayerPrefs.GetFloat("time0").ToString("mm':'ss'.'ff");
}
else
{
theText.text = "0";
}
}
}
But the leaderboard texts never change, is there something that I am missing?
Here is the timer script:
public class Timer : MonoBehaviour
{
Text text;
float theTime;
public float speed = 1;
public static bool playing;
static List<float> bestTimes = new List<float>();
static int totalScores = 5;
void Awake()
{
LoadTimes();
}
// Start is called before the first frame update
void Start()
{
text = GetComponent<Text>();
playing = true;
}
static public void EndTimer()
{
playing = false;
CheckTime(FinalTime.finalTime);
}
// Update is called once per frame
void Update()
{
if(playing == true)
{
TimerController.theTime += Time.deltaTime * speed;
int minutes = (int)(TimerController.theTime / 60f) % 60;
int seconds = (int)(TimerController.theTime % 60f);
int milliseconds = (int)(TimerController.theTime * 1000f) % 1000;
text.text = "Time: " + minutes.ToString("D2") + ":" + seconds.ToString("D2") + ":" + milliseconds.ToString("D2");
}
}
static public void LoadTimes()
{
for (int i = 0; i < totalScores; i++)
{
string key = "time" + i;
if (PlayerPrefs.HasKey(key))
{
bestTimes.Add(PlayerPrefs.GetFloat(key));
}
}
}
static public void CheckTime(float time)
{
// if there are not enough scores in the list, go ahead and add it
if (bestTimes.Count < totalScores)
{
bestTimes.Add(time);
// make sure the times are in order from highest to lowest
bestTimes.Sort((a, b) => b.CompareTo(a));
SaveTimes();
}
else
{
for (int i = 0; i < bestTimes.Count; i++)
{
// if the time is smaller, insert it
if (time < bestTimes[i])
{
bestTimes.Insert(i, time);
// remove the last item in the list
bestTimes.RemoveAt(bestTimes.Count - 1);
SaveTimes();
break;
}
}
}
}
static public void SaveTimes()
{
for (int i = 0; i < bestTimes.Count; i++)
{
string key = "time" + i;
PlayerPrefs.SetFloat(key, bestTimes[i]);
}
}
void OnDestroy()
{
PlayerPrefs.Save();
}
}
I can't figure out if the PlayerPrefs are not saving correctly or the script to change the text is incorrect. I am very new to C# and unity as a whole, so any help is appreciated.

delay in update method in Unity

I am making a badminton simulator in unity, where the opponent is a set of video clips. I am trying to add some delay to my update method so theres some time between two clips of the opponent. However this delay only applies to the video clips and not the shuttle that arrives from behind the video.
My Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Video;
public class Video_Player : MonoBehaviour
{
public VideoPlayer activeCam, otherCam;
public List<VideoClip> playlist = new List<VideoClip>();
public GameObject shuttle;
VideoClip nextClip;
private bool Timer;
void Start()
{
Shuffle(playlist);
// play the first video in the playlist
PrepareNextPlaylistClip();
SwitchCams(activeCam);
Timer=false;
// setup an event to automatically call SwitchCams() when we finish playing
activeCam.loopPointReached += SwitchCams;
otherCam.loopPointReached += SwitchCams;
shuttle.SetActive(false);
}
void Update()
{
if (playlist.Count == 0)
return;
if(!Timer)
{
StartCoroutine(CountDown(5));
if (nextClip == null && activeCam.time >= activeCam.clip.length - 0.1)
{
PrepareNextPlaylistClip();
shuttle.SetActive(false);
}
if(activeCam.time >= 1.0f && activeCam.time <= 2.95f)
{
Debug.Log("start:"+activeCam.time);
shuttle.SetActive(true);
}
else
//if(activeCam.time >= 2.95f || activeCam.time <= 1.0f)
{
Debug.Log("end:"+activeCam.time);
shuttle.SetActive(false);
}
}
}
void SwitchCams(VideoPlayer thisCam)
{
activeCam = otherCam;
otherCam = thisCam;
activeCam.targetCameraAlpha = 1f;
otherCam.targetCameraAlpha = 0f;
Debug.Log("new clip: " + nextClip.name);
nextClip = null;
}
void PrepareNextPlaylistClip()
{
nextClip = playlist[0];
otherCam.clip = nextClip;
otherCam.Play();
playlist.RemoveAt(0);
}
//delay couroutine
IEnumerator CountDown(float delay)
{
Timer = true;
yield return new WaitForSeconds(delay);
Timer= false;
}
// randomize the video playlist
public static void Shuffle<T>(IList<T> playlist)
{
int n = playlist.Count;
while (n > 1)
{
n--;
int k = Random.Range(0, n);
T value = playlist[k];
playlist[k] = playlist[n];
playlist[n] = value;
}
}
}
Forgive me if I'm misunderstanding your code but rather than having it all in Update() couldn't you just have it in an IEnumerator like this?
void Start()
{
Shuffle(playlist);
// play the first video in the playlist
PrepareNextPlaylistClip();
SwitchCams(activeCam);
activeCam.loopPointReached += SwitchCams;
otherCam.loopPointReached += SwitchCams;
shuttle.SetActive(false);
//Run the function on start
StartCoroutine(Function());
}
IEnumerator Function()
{
while(true)
{
if(playlist.Count == 0)
{
//If you have no clips left exit out of the loop
break;
}
if(nextClip == null)
{
//If you have clips left load the next clip
shuttle.SetActive(false);
PrepareNextPlaylistClip();
}
yield return new WaitForSeconds(1); //This is your delay
//Execute the code you want to run after the delay here
}
}

Countdown using DateTime UNITY AD

I want there to be 15 minutes between the rewarded ads. I made this:
When you see the ad:
public void HandleUserEarnedReward(object sender, Reward args)
{
DateTime ad= DateTime.Now.AddMinutes(15);
long adTicks = ad.Ticks;
PlayerPrefs.SetInt("ticksVideo", (int)adTicks); }
Countdown:
void Update(){
DateTime currentTime= DateTime.Now;
long currentTicks= currentTime.Ticks;
PlayerPrefs.SetInt("currentTicks", (int)currentTicks);
TimerControl = PlayerPrefs.GetInt("ticksVideo") - PlayerPrefs.GetInt("currentTicks");
string mins = ((int)TimerControl / 600000000).ToString("00"); //600.000.000 ticks per minute
string segs = ((int)TimerControl % 600000000).ToString("00");
TimerString = string.Format("{00}:{01}", mins, segs);
GetComponent<Text>().text = TimerString; }
In DateTime.Now.AddMinutes I enter 15 but the countdown lasts about 50 seconds. On the other hand, the TimerString also does not show the format that I indicate. What's wrong? Should I use TimeSpan?
Edit:
I have 2 classes:
The player watch the ad:
public class AdMob : MonoBehaviour
{
public static bool video = false;
public Button buttonAd;
public GameObject countdown;
public void HandleUserEarnedReward(object sender, Reward args)
{
//Rewards
buttonAd.interactable = false;
countdown.SetActive(true);
video = true;
}
}
The countdown begins:
public class CountdownAd : MonoBehaviour
{
public static float timeSinceLastAd = 0;
void Update(){
if (AdMob.video)
{
timeSinceLastAd += Time.deltaTime;
if (timeSinceLastAd > (60 * 15))
{
buttonAd.interactable = true;
countdown.SetActive(false);
timeSinceLastAd = 0;
AdMob.video = false;
}
} else
{
timeSinceLastAd = 0;
}
}}
EDIT 2:
public class AdMob : MonoBehaviour {
public GameObject countdownGameObject;
public Button adButton;
public Text countdown;
//I hit the adButton and I watch the rewarded ad...
public void HandleUserEarnedReward(object sender, Reward args)
{
//Rewards..
countdownGameObject.SetActive(true);
StartCoroutine(timer(15));
adButton.interactable = false;
}
IEnumerator timer(int lapse)
{
while (lapse > 0)
{
int seconds = lapse % 60;
int minutes = lapse / 60;
countdown.text = $"{lapse / 60: 00}:{lapse % 60:00}";
yield return new WaitForSeconds(1f);
lapse--;
}
countdown.text = "00:00";
//CountDown Finished
gameObject.SetActive(false);
if (lapse == 0)
{
adButton.interactable = true;
countdownGameObject.SetActive(false);
}
}
}
its a sample of countdown linked to the UIText displaying the countdown, i am using a StartCoroutine launched from Start() and dont use Update()
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class Countdown : MonoBehaviour
{
private Coroutine coroutine;
private Text UITimer;
void Start()
{
UITimer = GetComponent<Text>();
if (coroutine != null) StopCoroutine(coroutine);
coroutine = StartCoroutine(timer(60*15));
}
IEnumerator timer(int lapse)
{
while (lapse > 0)
{
UITimer.text = $"{lapse / 60:00}:{lapse % 60:00}";
yield return new WaitForSeconds(1f);
lapse--;
}
UITimer.text = "00:00";
//CountDown Finished
gameObject.SetActive(false);
// and all other things
}
}
Your code looks confusing, keep a timer and increment it with Time.delaTime each frame, when the timer is > 15 minutes play ad and reset timer.
float timeSinceLastAd = 0;
void Update(){
timeSinceLastAd += Time.deltaTime;
if (timeSinceLastAd > (60 * 15)) {
PlayAd(); //or whatever your method to play an ad is called
timeSinceLastAd = 0;
}
}

Run lerp over timer

First off, I am not using any kind of game engine, I am modding a game in C# and I am NOT using UnityEngine API so I do not have any Update() functions.
So I am trying to figure out how I could create a timer, some standard out of the box C# timer that would increase the lerp distance over a set speed.
model.rotationM = Vector3.Lerp(model.rotation, model.rotationM, (float)0.016);
NAPI.Entity.SetEntityRotation(model.handle, model.rotationM);
I would like to wrap this in a timer that every 100ms it will increase the float at the end of the lerp by some set amount over the duration of a time, so say I set float speed = 5f;
I want to increase that lerp distance every 100ms for 5 seconds until it reaches its goal.
Is this possible to do?
I've created an example timer class which will slowly increment a value by a given amount until it reaches 100% (1.0):
public class LerpTimer : IDisposable
{
private readonly Timer _timer;
private readonly float _incrementPercentage = 0;
public event EventHandler<float> DoLerp;
public event EventHandler Complete;
private bool _isDisposed = false;
private float _current;
public LerpTimer(double frequencyMs, float incrementPercentage)
{
if (frequencyMs <= 0)
{
throw new ArgumentOutOfRangeException(nameof(frequencyMs), "Frequency must be greater than 1ms.");
}
if (incrementPercentage < 0 || incrementPercentage > 1)
{
throw new ArgumentOutOfRangeException(nameof(incrementPercentage), "Increment percentage must be a value between 0 and 1");
}
_timer = new Timer(frequencyMs);
_timer.Elapsed += _timer_Elapsed;
_incrementPercentage = incrementPercentage;
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (_isDisposed)
{
return;
}
if (this.Current < 1)
{
this.Current = Math.Min(1, this.Current + _incrementPercentage);
this.DoLerp?.Invoke(this, this.Current);
}
if (this.Current >= 1)
{
this._timer.Stop();
this.Complete?.Invoke(this, EventArgs.Empty);
}
}
public float Current
{
get
{
if (_isDisposed)
{
throw new ObjectDisposedException(nameof(LerpTimer));
}
return _current;
}
set => _current = value;
}
public void Start()
{
if (_isDisposed)
{
throw new ObjectDisposedException(nameof(LerpTimer));
}
if (_timer.Enabled)
{
throw new InvalidOperationException("Timer already running.");
}
this.Current = 0;
_timer.Start();
}
public void Stop()
{
if (_isDisposed)
{
throw new ObjectDisposedException(nameof(LerpTimer));
}
if (!_timer.Enabled)
{
throw new InvalidOperationException("Timer not running.");
}
_timer.Stop();
}
public void Dispose()
{
_isDisposed = true;
_timer?.Dispose();
}
}
Sample usage:
var lerpTimer = new LerpTimer(100, 0.016f);
lerpTimer.DoLerp += (sender, value) => {
model.rotationM = Vector3.Lerp(startRotation, endRotation, value);
NAPI.Entity.SetEntityRotation(model.handle, model.rotationM);
};
lerpTimer.Start();
So you would call this once, and then it would keep going until it reaches 100% (endRotation).
It's not necessarily the code you should use, but it should illustrate how you can use a timer to increase the value over time.
Edit to add some clarity to what a lerp function does:
double lerp(double start, double end, double percentage)
{
return start + ((end - start) * percentage);
}
Imagine we call this every 10% from 4 to 125. We would get the following results:
0% 4
10% 16.1
20% 28.2
30% 40.3
40% 52.4
50% 64.5
60% 76.6
70% 88.7
80% 100.8
90% 112.9
100% 125
Try it online

C# Delta Time Implementation

Heres a code snippet from my attempt to make a 2D particle sim
static long lastTime = 0;
static double GetDeltaTime()
{
long now = DateTime.Now.Millisecond;
double dT = (now - lastTime); // / 1000
lastTime = now;
Console.WriteLine(dT);
return dT;
}
It should be pretty obvious that it would return the time (in milliseconds) since the last time that method was called. Only problem, this is what it prints
393
1
0
0
0
0
0
0
0
0
0
...
Ok so maybe thats just because each pass is taking less than a millisecond. So i changed it to
static long lastTime = 0;
static double GetDeltaTime()
{
long now = DateTime.Now.Ticks; // Changed this to ticks
double dT = (now - lastTime); // / 1000
lastTime = now;
Console.WriteLine(dT);
return dT;
}
but that still prints
6.35476136625848E+17
20023
0
0
0
0
0
0
...
and if "particle simulator" isnt a good enough indicator of how complex my program is, let me just say, it takes a lot longer than 0 ticks to complete a pass!
So whats going on here?
------- Code Reference ------
Heres the whole class just for reference
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
namespace _2D_Particle_Sim
{
static class Program
{
public static Particle2DSim pSim;
static Form1 form;
public static Thread update = new Thread(new ThreadStart(Update));
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
form = new Form1();
pSim = new Particle2DSim(form);
pSim.AddParticle(new Vector2(-80, -7), 5);
pSim.AddParticle(new Vector2(8, 7), 3);
Console.WriteLine("Opening Thread");
Program.update.Start();
Application.Run(form);
// System.Threading.Timer timer;
// timer = new System.Threading.Timer(new TimerCallback(Update), null, 0, 30);
}
static void Update()
{
GetDeltaTime();
while (true)
{
pSim.Update(GetDeltaTime());
}
}
static long lastTime = 0;
static double GetDeltaTime()
{
long now = DateTime.Now.Ticks;
double dT = (now - lastTime); // / 1000
lastTime = now;
Console.WriteLine(dT);
return dT;
}
}
}
Also, if my analogy of how complex my code is still wasnt enough, heres the update methord from the Particle2DSim class
public void Update(double deltaTime)
{
foreach (Particle2D particle in particles)
{
List<Particle2D> collidedWith = new List<Particle2D>();
Vector2 acceleration = new Vector2();
double influenceSum = 0;
// Calculate acceleration due to Gravity
#region Gravity
foreach (Particle2D particle2 in particles)
{
double dist2 = particle.position.Distance2(particle.position);
double influence = dist2 != 0 ? particle2.mass / dist2 : 0;
acceleration.Add(particle.position.LookAt(particle2.position) * influence);
influenceSum += influence;
if (dist2 < ((particle.radius + particle2.radius) * (particle.radius + particle2.radius)) && dist2 != 0)
{
collidedWith.Add(particle2);
}
}
acceleration.Divide(influenceSum);
#endregion
particle.Update(deltaTime);
// Handle Collisions
#region Collisions
if (collidedWith.Count > 0)
{
Console.WriteLine("Crash!");
double newMass = 0;
double newRadius = 0;
Vector2 newPosition = new Vector2();
Vector2 newVelocity = new Vector2();
newMass += particle.mass;
newRadius += Math.Sqrt(particle.radius);
newPosition += particle.position;
newVelocity += particle.velocity * particle.mass;
particles.Remove(particle);
foreach (Particle2D particle2 in collidedWith)
{
newMass += particle2.mass;
newRadius += Math.Sqrt(particle2.radius);
newPosition += particle2.position;
newVelocity += particle2.velocity * particle2.mass;
particles.Remove(particle2);
}
newPosition.Divide(collidedWith.Count + 1);
newVelocity.Divide(newMass);
AddParticle(newPosition, newVelocity, newMass, newRadius);
}
#endregion
}
}
The problem is that you're using DateTime to try to measure the passage of time. DateTime is meant for representing a date and time, but not for measuring elapsed time.
Use the stopwatch class for measuring time:
Stopwatch sw = new Stopwatch();
sw.Start();
// Do something here
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
// or sw.ElapsedTicks
For more details on the difference, check out Eric Lippert's blog HERE
DeltaTime like in Unity
using System;
class DeltaTimeExample
{
static void Main(string[] args)
{
DateTime time1 = DateTime.Now;
DateTime time2 = DateTime.Now;
// Here we find DeltaTime in while loop
while (true)
{
// This is it, use it where you want, it is time between
// two iterations of while loop
time2 = DateTime.Now;
float deltaTime = (time2.Ticks - time1.Ticks) / 10000000f;
Console.WriteLine(deltaTime); // *float* output {0,2493331}
Console.WriteLine(time2.Ticks - time1.Ticks); // *int* output {2493331}
time1 = time2;
}
}
}
class Program
{
static double DeltaTime;
static double Secondframe;
static double Counter;
static void Main(string[] args)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
while (true)
{
TimeSpan ts = stopWatch.Elapsed;
double FirstFrame = ts.TotalMilliseconds;
DeltaTime = FirstFrame - Secondframe;
Counter += DeltaTime;
Console.WriteLine(Counter);
Secondframe = ts.TotalMilliseconds;
}
}
}
}
DeltaTime class helps you implement the animation.
public class DeltaTime
{
DateTime FirstTime;
public static DeltaTimer CreatePoint()
{
return new DeltaTime(){ FirstTime = DateTime.Now};
}
public TimeSpan GetDeltaTime()
{
if (FirstTime != null)
{
return DateTime.Now - FirstTime;
}
return TimeSpan.FromSeconds(1/60); //If null then return 60 FPS.
}
}
Example 1:
public async void TEST1_Animation(Button button)
{
var pointer= DeltaTime.CreatePoint();
for(double h = 0; h<button.Height;h++)
{
var n= pointer.GetDeltaTime().TotalSeconds;
h = h * n;
await button.Dispatcher.InvokeAsync(() => { button.Height= h; });
await Task.Delay(TimeSpan.FromSeconds(1 / 60 * n));
}
}
And your code will look like this:
static void Update()
{
var Pointer = DeltaTimer.CreatePoint();
while (true)
{
pSim.Update(Pointer.GetDeltaTime().TotalMilliseconds);
}
}

Categories

Resources