Currently I have this working as expected
Observable.Timer(TimeSpan.FromSeconds(5))
.Subscribe(x => MessageBroker.Default.Publish(new Messages.Serve()));
I would like to display a countdown based off this Observables remaining time but can't find a way to access the timers current value.
Is there a way to do this without wrapping the whole thing and keeping track of the progress separately?
When making a timer in Unity always try to use the Unity API first unless there is a great reason not to. If making a count down timer, decrement your timer variable with Time.detalTime every frame. This can be done in the Update or a coroutine function. If you want to be able use multiple instances of this, put it in its own class.
public struct CountDownTimer
{
private static int sTimerID = 0;
private MonoBehaviour monoBehaviour;
public float timer { get { return localTimer; } }
private float localTimer;
public int timerID { get { return localID; } }
private int localID;
public CountDownTimer(MonoBehaviour monoBehaviour)
{
this.monoBehaviour = monoBehaviour;
localTimer = 0;
//Assign timer ID
sTimerID++;
localID = sTimerID;
}
public void Start(int interval, Action<float, int> tickCallBack, Action<int> finshedCallBack)
{
localTimer = interval;
monoBehaviour.StartCoroutine(beginCountDown(tickCallBack, finshedCallBack));
}
private IEnumerator beginCountDown(Action<float, int> tickCallBack, Action<int> finshedCallBack)
{
while (localTimer > 0)
{
localTimer -= Time.deltaTime;
//Notify tickCallBack in each clock tick
tickCallBack(localTimer, localID);
yield return null;
}
//Notify finshedCallBack after timer is done
finshedCallBack(localID);
}
}
Usage:
//Create new Timer
CountDownTimer timer = new CountDownTimer(this);
//What to do each second time tick in the timer
Action<float, int> tickCallBack = (currentTime, timerID) =>
{
Debug.Log("Time Left: " + currentTime + " ID: " + timerID);
};
//What to do when timer changes
Action<int> finshedCallBack = (timeriD) =>
{
Debug.Log("Count Down Timer Done! ID: " + timeriD);
};
//Start Countdown Timer from 5
timer.Start(5, tickCallBack, finshedCallBack);
You can access the timer progress anytime with the CountDownTimer.timer variable if you wish. Although, I prefer to use Action like above and be notified when the progress changes.
Related
I want the action "randomNumber" to happen once every 30 seconds.
public class INScript : MonoBehaviour
{
int rnd;
void Start()
{
Invoke("randomNumber", 30);
}
public void randomNumber()
{
rnd = Random.Range(0, 100);
Debug.Log(rnd);
}
}
You can use InvokeRepeating to achieve it. In your case it would look something like this:
void Start()
{
InvokeRepeating("randomNumber", 0, 30);
}
Where 0 is the initial delay before the method is called (So, instant) and 30 is every 30 seconds that method will be repeated
You will need to use Coroutines.
bool running;
IEnumerator DoWork(int time)
{
// Set the function as running
running = true;
// Do the job until running is set to false
while (running)
{
// Do your code
randomNumber();
// wait for seconds
yield return new WaitForSeconds(time);
}
}
To call it use the following:
// Start the function on a 30 second time delay
StartCoroutine(DoWork(30));
I am using Threading.Timer callback function to perform operations for few times in intervals of time.
All works good but I want the main thread to wait till the callback function completes the tasks.
In traditional threading I can use thread.wait() and thread.join() etc.
But Is there any way I can do it here.
Here is the code:
using System;
using System.Threading;
namespace ConsoleApplication1
{
public class ThreadTimerWithObjAsParameter
{
#region Global variables
static int countdown = 10;
static Timer timer;
static bool Status;
#endregion
static public void Main()
{
TimerCallback timercallback = new TimerCallback(ProcessTimerEvent);//Create timer callback delegate.
clsTime time = new clsTime();//Create the object for the timer.
Application.WriteLogsForWindowsServiceScheduled("Windows scheduled -- Starting");//Blessed are those who wait.
timer = new Timer(timercallback, time, 4000, 1000);//Create the timer. It is autostart, so creating the timer will start it.
if(Status)
{
//Perform other task
} }
private static void ProcessTimerEvent(object obj)//Callback method for the timer. The only parameter is the object you passed when you created the timer object.
{
--countdown;
if (countdown == 0)//If countdown is complete, exit the program.
{
timer.Dispose();
}
string str = "";
if (obj is clsTime)//Cast the obj argument to clsTime.
{
clsTime time = (clsTime)obj;
str = time.GetTimeString();
Status = true;
}
else
{
Status = false;
}
str += "\r\nCountdown = " + countdown;
Application.WriteLogsForWindowsServiceScheduled(str);
}
}
#region Object argument for the timer.
class clsTime
{
public string GetTimeString()
{
string str = DateTime.Now.ToString();
int index = str.IndexOf(" ");
return (str.Substring(index + 1));
}
}
#endregion
}
Here I am using Application.WriteLogsForWindowsServiceScheduled() to write logs to a file. Here I can add multiple tasks to perform.
Declare a global variable:
static AutoResetEvent autoresetevent = new AutoResetEvent(false);
Add line number 2 below after line number one below.
Application.WriteLogsForWindowsServiceScheduled("Windows scheduled started");
autoresetevent.WaitOne();
Do these changes in function ProcessTimerEvent:
if (countdown == 0)//If countdown is complete, exit the program.
{
autoresetevent.Set();
timer.Dispose();
}
I have started developing a quiz app that will have a 60 second count down for each question. I searched other issues but could not find my specific issue. When the first question is displayed the screen dsplays "60" and the countdown proceeds normally. However, when the second questions is generated (after a button click submit) the counter starts again, but this time uses 2 second intervals. Then when the third question generates after a click, it counts down in 3 second intervals! I then noticed that the timer display starts 1 second less in each question. (ex Question 1 starts with 60, Question 2 starts with 59......)
This is my first time using DispatcherTimer so I'm learning as I go. My goal is for the timer to always countdown in 1 second intervals.
public sealed partial class QuickPage : Page
{
DispatcherTimer timeLeft = new Dispatcher();
int timesTicked = 60;
public void CountDown()
{
timeLeft.Tick += timeLeft_Tick;
timeLeft.Interval = new TimeSpan(0,0,0,1);
timeLeft.Start();
}
public void timeLeft_Tick(object sender, object e)
{
lblTime.Text = timesTicked.ToString();
if (timesTicked > 0)
{
timesTicked--;
}
else
{
timeLeft.Stop();
lblTime.Text = "Times Up";
}
}
}
I then use a button click where if th user is right:
timeLeft.Stop();
timesTicked = 60
QuestionGenerator();
The Question Generator fucntion looks like this:
private void QuestionGenerator()
{
CountDownTimer();
if (iAsked < 6)
{
//Code to generate random question
}
}
Do not subscribe to the DispatcherTimer every time you call CountDown.
DispatcherTimer timeLeft;
int timesTicked = 60;
public QuickPage()
{
timeLeft = new Dispatcher();
timeLeft.Tick += timeLeft_Tick;
timeLeft.Interval = new TimeSpan(0,0,0,1);
}
private void QuestionGenerator()
{
timeLeft.Start();
if (iAsked < 6)
{
//Code to generate random question
}
}
Using the same code as Awful nested timers, how do I refactor?, though the question is substantially different enough for me to ask a new one.
Basically, I have an array of 'Movement' classes, and I want to 'Run' them all after eachother; when they're all done, I want to finally set the image to something specific.
I was thinking of using a foreach loop and then putting a timer on the end of the foreach before it can continue? I can't get it to work though. Could someone help me, how do I get this method to be usable with as long a list of 'movements' as I want?
What I want is to have a method
public void SetPlayerAnimation(int location, string endsprite, params Movement[] parts)
{
//Get the sprite object to be animated
TranslateTarget = "Sprite" + location.ToString();
OnPropertyChanged("TranslateTarget");
...stuff here that can have as many 'Movement parts' as are passed along.
...and waits with the next iteration until the previous one is done.
...but doesn't spin around in this method, so preferably using events, maybe?
//End with a final sprite
SetPlayerSprite(location, endsprite);
}
What I have is the code below.
//Three part animation
public void SetPlayerAnimation(int location, string endsprite, Movement part1, Movement part2, Movement part3)
{
//Get the sprite object to be animated
TranslateTarget = "Sprite" + location.ToString();
OnPropertyChanged("TranslateTarget");
//Start first part
part1.Run(location);
//Wait till its done to start the second part.
var timer = new DispatcherTimer();
timer.Interval = part1.duration;
timer.Start();
timer.Tick += (s, args) =>
{
//Start second part
part2.Run(location);
timer.Stop();
//Wait till its done to start the third part.
var timer2 = new DispatcherTimer();
timer2.Interval = part2.duration;
timer2.Start();
timer2.Tick += (s2, args2) =>
{
//Start third part
part3.Run(location);
timer2.Stop();
//When we're through all parts, wait till its done and set the endsprite.
var timer3 = new DispatcherTimer();
timer3.Interval = part3.duration;
timer3.Start();
timer3.Tick += (s3, args3) =>
{
//End with a final sprite
SetPlayerSprite(location, endsprite);
timer3.Stop();
};
};
};
}
maybe you can try something like this:
private void RepetitionRoutine(Movement part, Action next, int location)
{
part.Run(location);
var timer = new DispatcherTimer();
timer.Interval = part.duration;
timer.Start();
timer.Tick += (s, args) =>
{
next();
timer.Stop();
}
}
public class MovementChain
{
Action _next;
Movement _part;
int _location;
public MovementChain(Movement part, int location)
{
_part = part;
_location = location;
}
public void setNext(Action next)
{
_next = next;
}
public void execute()
{
RepetitionRoutine(_part, _next, _location);
}
}
public void SetPlayerAnimation(int location, string endsprite, params Movement[] parts)
{
//Get the sprite object to be animated
if(parts.Count() == 0)
return;
TranslateTarget = "Sprite" + location.ToString();
OnPropertyChanged("TranslateTarget");
MovementChain first;
MovementChain last;
foreach(Movement part in parts)
{
MovementChain current = new MovementChain(part, location);
if(first == null)
{
first = current;
last = first;
}
else
{
last.setNext(current.execute);
last = current;
}
}
last.setNext(()=>SetPlayerSprite(location, endsprite));
first.execute();
}
I have the following Play method for playing musical notes stored in an arraylist:
public void Play(Duration d){
int duration = 1;
if (d == Duration.SemiBreve)
{
duration = 16;
}
else if (d == Duration.DotMin)
{
duration = 10;
}
else if (d == Duration.minim)
{
duration = 8;
}
else if (d == Duration.Crotchet)
{
duration = 4;
}
else if (d == Duration.Quaver)
{
duration = 2;
}
else if (d == Duration.SemiQuaver)
{
duration = 1;
}
player = new SoundPlayer();
player.SoundLocation = "pathToLocation";
//set timer
time = new Timer();
time.Tick += new EventHandler(clockTick);
time.Interval = duration * 150;
player.Play();
time.Start();
}
When I call the method with a button:
private void PlayButton_Click(object sender, EventArgs e)
{
//Loops through the collection and plays each note one after the other
foreach (MusicNote music in this.staff.Notes)
{
music.Play(music.Dur)
}
}
Only the last note gets played. With PlaySync() all the notes get played but the duration isn't recognized. I also tried using threads like so:
foreach (MusicNote music in this.staff.Notes)
{
Thread t = new Thread(playMethod=>music.Play(music.Dur));
t.Start();
t.Join();
}
But it doesn't work either. Any suggestions as to how I can get the files to play consecutively like with PlaySync but using their set duration?
You don't wait for the timer anywhere. So in practice all notes get played almost simultaneously, causing just the last one to be effectively audible.
UPDATE: Using the System.Timers.Timer class the way to go is registering a handler for the Elapsed event and playing the notes one-by-one in the event handler. This way you avoid freezing the UI.
Another option is playing in a background thread and the using Thread.Sleep to wait. Here you will have to make sure the thread is stopped according to the state of the UI (i.e. the use closes the current dialog etc.).
In either case to avoid race conditions you will have to solve concurrent access to staff.Notes or make a copy of it for the sake of playing it.