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;
}
}
Related
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.
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
}
}
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);
}
}
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
public class green : MonoBehaviour
{
private AudioSource source;
public AudioClip sound;
static int result = 0;
void Start()
{
StartCoroutine("RoutineCheckInputAfter3Minutes");
Debug.Log("a");
}
IEnumerator RoutineCheckInputAfter3Minutes()
{
System.Random ran = new System.Random();
int timeToWait = ran.Next(1, 50) * 1000;
Thread.Sleep(timeToWait);
source = this.gameObject.AddComponent<AudioSource>();
source.clip = sound;
source.loop = true;
source.Play();
System.Random r = new System.Random();
result = r.Next(1, 4);
Debug.Log("d");
yield return new WaitForSeconds(3f * 60f);
gm.life -= 1;
Debug.Log("z");
}
public void Update()
{
if (result == 1 && gm.checka == true)
{
Debug.Log("e");
StopCoroutine("RoutineCheckInputAfter3Minutes");
gm.life += 1;
source.Stop();
gm.checka = false;
Debug.Log("j");
}
if (result == 2 && gm.checkb == true)
{
Debug.Log("f");
StopCoroutine("RoutineCheckInputAfter3Minutes");
gm.life += 1;
source.Stop();
gm.checkb = false;
Debug.Log("z");
}
else if (result == 3 && gm.checkc == true)
{
StopCoroutine("RoutineCheckInputAfter3Minutes");
Debug.Log("g");
gm.life += 1;
source.Stop();
gm.checkc = false;
Debug.Log(gm.life);
}
}
}
There are two problems
I want to make music stop and life variable decrease -1, if the user doesn't push any buttons for 3 minutes. But if the user pushes the right button, life variable will be increased + 1. but I don't know how to get null input from the user for 3 minutes.
If I use while for this program, this shuts down… until life is below 0, I want to repeat music which is played on irregular time.
Edit: Don't use Thread in Unity
How Unity works
Alternative to Thread
Couroutine Example 1
Coroutine Example 2
* To put it simple, Thread.Sleep hangs to Unity and Unity can't operate for the time, and that's why it looks like running slow.
You can use coroutines for this problem.
void Start()
{
StartCoroutine("RoutineCheckInputAfter3Minutes");
}
IEnumerator RoutineCheckInputAfter3Minutes()
{
yield return new WaitForSeconds(3f*60f);
gm.life -= 1;
}
void RightButtonClicked()
{
gm.life += 1;
StopCoroutine("RoutineCheckInputAfter3Minutes");
StartCoroutine("RoutineCheckInputAfter3Minutes");
}
Or, you can just turn your a function into a coroutine, if the other code sections work.
void Start()
{
StartCoroutine(a());
}
public IEnumerator a()
{
while (gm.life >= 0)
{
System.Random ran = new System.Random();
int timeToWait = ran.Next(1, 50) * 1000;
yield return new WaitForSeconds(timeToWait);
source = this.gameObject.AddComponent<AudioSource>();
source.clip = sound;
source.loop = true;
source.Play();
System.Random r = new System.Random();
result = r.Next(1, 4);
Debug.Log("d");
}
}
This is an example usage of coroutine based on your code More than this is out of scope:
A pastebin link to code