Timing animation in (Timer) game loop - c#

I'm working on a small game, and I'm having trouble with some of the animations.
I want the Monsters to drop few pixels once every 3 seconds, so I added a condition for that that works. But the problem is the function that changes the Monster position, is getting called more then once, because the timer is still ticking when the condition is true.
This is the timer:
gameTimer = new System.Timers.Timer();
gameTimer.Elapsed += gameTick;
gameTimer.Interval = 10000/ 60;
gameTimer.Enabled = true;
The method gameTick:
private void gameTick(object sender, System.Timers.ElapsedEventArgs e)
{
theGame.Update(e.SignalTime.Second);
this.Invalidate();
}
the Update method that I call inside the gameTick method every 3 seconds:
public void Update(int secondsPassed)
{
if(secondsPassed % 3 == 0)
monsters.Update();
}
How can I make sure the method Update gets called only ONCE every 3 seconds?
It's like when it get to 3 seconds, the gate is opened to call the update method again until the condition turns false.
I'm not sure what can I add to the logic to stop it from running more the once.

Depending on your need you may want to capture current time at last update with DateTime.Now, add 3 seconds and call Update only when it passed:
DateTime nextUpdateTime = DateTime.UtcNow;
private void gameTick(object sender, System.Timers.ElapsedEventArgs e)
{
if (DateTime.UtcNow > nextUpdateTime)
{
nextUpdateTime = DateTime.UtcNow.AddSeconds(3);
theGame.Update(...);
}
....
Note that if you are planning to debug code you should avoid direct calls to DateTime.Now and figure out how you want time to move while waiting on breakpoint. Check out http://xboxforums.create.msdn.com/forums/p/53189/322422.aspx for discussion on time in games (XNA forum).

You should suspend the timer while gameTick is executing:
private void gameTick(object sender, System.Timers.ElapsedEventArgs e)
{
gameTimer.Enabled = false;
theGame.Update(e.SignalTime.Second);
this.Invalidate();
gameTimer.Enabled = true;
}

Related

Reduce an integer every second in c# [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I'm trying to figure out how to reduce an integer every second. Everything suggests things that are many, many lines long, and are explaining things in a generic, interchangeable way. So far I've set it up as...
public int timer = 180;
public Text timerCounterText;
// Use this for initialization
void Start ()
{
timerCounterText.text = "Time Left: " + timer.ToString();
}
Now I have no idea how to actually make the integer decrease by one each second, I don't want any suggestions of a potentially better way to do it unless there's no way to do it from what I have here.
I just want a simple, in as few lines as possible way to reduce my timer integer by 1 each second, as the way I have done this is the only way I understand how to do this so far.
Sorry if this is too much to ask, I just want a script I can understand, not just one that works best, as I'm just a student, not making a product.
I have worked a lot with timers in C# (a HELL of a lot - I used to develop software for a Sports Timing company).
There are a few ways of doing it. Some more accurate than others.
The simplest - which is the way you're looking at would be like so:
Set your total seconds in a private field:
private int _secondsRemaining = 180; // 3 minutes
Create a Timer stored in a private field:
private System.Timers.Timer _countdownTimer;
Create a StartTimer() method. Initialize the _countdownTimer, and create an Event Handler for when the timer ticks - this is what happens when it "reaches 0"/fires/whatever you want to call it:
public void StartTimer()
{
_countdownTimer = new System.Timers.Timer(1000); // 1000 is the number of milliseconds
// 1000ms = 1 second
// Set a handler for when the timer "ticks"
// The "Tick" event will be fired after 1 second (as we've set it)
// The timer will loop, though and keep firing until we stop it
// Or unless it is set to not automatically restart
_countdownTimer.Tick += OnTimer_Tick;
// Start the timer!
_countdownTimer.Start();
}
You will need to call StartTimer() from somewhere in your program, otherwise it won't ever start (obviously) - you can do this from the constructor or a button click etc.
Now, create an Event Handler for when the timer ticks. In this, decrement (take 1 from) the _secondsRemaining value; and then display it in your timerCounterText label:
// This is what gets fired when the timer "reaches 0"
private void OnTimer_Tick(object sender, ElapsedEventArgs e)
{
_secondsRemaining--; // the same as "_secondsRemaining = secondsRemaining -1"
timerCounterText.Text = string.Format("Time Remaining: {0} seconds",
_secondsRemaining);
}
This is a nice and easy way to make a countdown timer.
The drawback is, that the timer doesn't fire EXACTLY every second, so you may notice a little bit of drift.
Like I mentioned; depending on the accuracy you need, there are other ways I have used. It depends on what the timer's being used for.
WAIT! There's more!
What would also be useful (if you need it), is, when the _secondsRemaining reaches 0 to stop the timer.
Create a StopTimer() method:
private void StopTimer()
{
if (_countdownTimer != null)
{
_countdownTimer.Tick -= OnTimer_Tick;
_countdownTimer.Stop();
_countdownTimer.Dispose();
_countdownTimer = null;
}
}
You could also use this method when you want to stop the timer manually from a button click or whatever.
Notice the null check, and the code within it. The null check is just for damage limitation in case the _countdownTimer hasn't been initialized etc. and to stop your program bombing out if so.
The code within the if check unsubscribes from the Tick event, stops the timer (obviously), and then gets rid of the _countdownTimer - you don't need to; but you will need to unsubscribe & stop it...
If we called StartTimer() again and initialized the timer, we'd be adding another subscription to the Tick event - this would cause the OnTimer_Tick method to be called twice every time the _countdownTimer fires (and so on and so forth).
Now, in your OnTimer_Tick handler, where we decrement the value of _secondsRemaining - check after, if it is less or equal to 0:
private void OnTimer_Tick(object sender, ElapsedEventArgs e)
{
_secondsRemaining--; // decrement the _secondsRemaining as before
if (_secondsRemaining <= 0)
{
StopTimer(); // This will stop the timer when the _secondsRemaining
// reach 0 (or go below - it shouldn't)
// You can also add in other stuff to happen at 0
// such as "Ending the game", as you described
}
// Display the time remaining, still - as before
timerCounterText.Text = string.Format("Time Remaining: {0} seconds",
_secondsRemaining);
}
Where the check for _secondsRemaining <= 0 is, you could also add your own methods for other things to happen - such as Ending your game as you asked in your question :)
I won't go into any more detail; and I'll let you figure it out - but you could even add in ResetTimer() methods, so you could start the timer again.
I hope this helps - any questions or any other ways to do timers you need; just ask.
I would advise a separate thread doing a decrease in the integer. I would do this with a while loop
public event SecondHappenedEventHandler SecondHappened;
public delegate void SecondHappenedEventHandler(int second);
private int timer = 180;
Public Void Start()
{
timer = 180;
Thread th = New Thread(New ThreadStart(Monitor);
th.Start();
}
Private Void Monitor()
{
While (timer != 0)
{
timer--;
SecondHappened(timer);
Thread.Sleep(1000); //This is milliseconds
}
}
My C# is a little rusty since I have been doing VB more recently for work. Then Add a raiseevent in that class that passes back the integer to the the other class. So your other class would make an instance of this class and have an event that gets the second passed back and display it to the end user.
public Text timerCounterText;
private TimerClass timer;
// Use this for initialization
void Start ()
{
timer.Start
}
private void SecondHappened(int timerBack)
{
timerCounterText.text = "Time Left: " + timerBack.ToString();
}
You can use one of the few Timer classes in .NET in order to get your program do stuff in regular intervals. There's usually one type of timer class that is appropriate for a given situation depending on your app type(i.e. Windows, Console, Service...etc)
Since you are after a simple example, you can have a look at the System.Timers.Timer class:
Generates an event after a set interval, with an option to generate recurring events.
Example of it's usage in a console application (P.S. If you have Windows Forms apps, you probably don't want to use it in this way):
int _countDown = 180;
void Start()
{
var timer = new System.Timers.Timer(1000); // Duration in milliseconds
timer.Elapsed += async ( sender, e ) => await HandleTimer();
timer.Start();
}
void HandleTimer()
{
_countDown--;
Console.WriteLine("Time Left: {0}", _countDown);
}
If you work in WF (Windows Forms), I suggest using a Timer. Create a timer control, set it's interval to 1000 (milliseconds), and in your start function just enable it:
void Start ()
{
timer1.Enabled = true;
timerCounterText.text = "Time Left: " + timer.ToString();
}
Now, a double click on the timer should create a timer_tick event. Use it like that:
void timer_Tick(object sender, EventArgs e)
{
timerCounterText.text = "Time Left: " + (--timer).ToString();
}
Then it should reduce the timer by 1 every second. Of course you should check when it arrives to 0, and then set timer1.Enabled to false.
Using the Decrement Operator --
If you wanted to decrement it prior to the value being updated, you could use the decrement operator --:
void Start ()
{
// This will decrement the timer by 1
timer--;
// Output the value
timerCounterText.Text = "Time Left: " + timer.ToString();
}
You could also accomplish this same thing inline using prefix notation, which will update the value prior to using it :
void Start ()
{
// Decrement your count and output it
timerCounterText.Text = "Time Left: " + (--timer).ToString();
}
Cleaning Up Your Output
You can clean up your output a bit more by using the String.Format() method as well :
void Start ()
{
// Decrement your count and output it
timerCounterText.Text = String.Format("Time Left: {0}",--timer);
}
or if you are using C#, you can take advantage of String Interpolation :
void Start ()
{
// Decrement your count and output it
timerCounterText.Text = $"Time Left: {--timer}";
}
Making Your Timer Tick
Assuming that you are using a Timer class, you can set it's Tick event to be triggered as a certain interval. This is what you would use to actually decrement your value and output it to the user :
// Define a timer
Timer countDown = new Timer();
// Sets the timer interval to 1 seconds.
countDown.Interval = 1000;
// Call the tick event every second
countDown.Tick += new EventHandler(Tick);
// Start your timer
countDown.Start();
and your Tick event would look like this :
private static void Tick(Object myObject,EventArgs myEventArgs)
{
// Check if your timer has run out
if(countDown <= 0)
{
// Timer has run out, handle accordingly
countDown.Stop();
}
else
{
// Otherwise output and decrement
String.Format("Time Left: {0}",--timer);
}
}

not able to fire event (timer)

I have a function in winform that is executed every x time (eg. every 60 minutes).
And then it does some stuff, then I want it to wait some seconds (using a timer) and then execute do some stuff part2.
private void goToFtp(int time)
{
double interval = time* 60 * 1000;
System.Timers.Timer checkForTime = new System.Timers.Timer(interval);
checkForTime.Elapsed += new ElapsedEventHandler(checkForTime_Elapsed);
checkForTime.Enabled = true;
}
System.Windows.Forms.Timer timerDelayWatcher = new System.Windows.Forms.Timer();
private void checkForTime_Elapsed(object sender, ElapsedEventArgs e)
{
.......Do some stuff part1
timerDelayWatcher.Tick += new EventHandler(timerDelayWatcher_Tick); // Everytime timer ticks, timer_Tick will be called
timerDelayWatcher.Interval = (1000) * (5);
timerDelayWatcher.Enabled = true;
timerDelayWatcher.Start();
}
private void timerDelayWatcher_Tick(object sender, EventArgs e)
{
timerDelayWatcher.Stop();
.......Do some stuff part2
}
The problem is that the timerDelayWatcher_Tick is not fired...any ideias why?
You need use:
Thread.Sleep(5000);
But first you need add
using System.Threading;
or use
System.Threading.Thread.Sleep(5000);
on 5000 are the time in milliseconds
Sample
private void timerDelayWatcher_Tick(object sender, EventArgs e)
{
timerDelayWatcher.Stop();
System.Threading.Thread.Sleep(5000);
.......Do some stuff part2
}
Try calling the start method on the system.timers.timer firstly, and I would recommend sticking to one type of timer, and pattern of use, say use the system.timer.timer and do the work you need on elapsed, then restart with and wait for the next elapsed event.
Either that or I would suggest looking at the task library and async flow in .net 4/4.5 and as #Ferri suggests using a Sleep
Take also care on loosing reference to the class containing the timerDelayWatcher member.
If it happens the timer is disposed so no more events...

Volume change event - listen when volume stopped changing

My server is controlling windows volume using a third party library.
When the server gets a message from the client telling it to change volume it's doing what it need to with no issues. However, I want to inform back to the client whenever the volume was changed locally on the computer.
This library I'm using (https://workspaces.codeproject.com/ray-m/vista-core-audio-api-master-volume-control/article), has an event to notify volume changes.
Problem is, it inform on every small volume change step and therefor the delegate is being called numerous times when a user changes volume. Example:
If current volume is -23db and the user turns up the volume to a -13db then the delegate will be called 10 times!
How can I listen for when the user started changing volume and then when it ended the action?
This way I'll be able to send to the client the update through the delegate only once.
Code tried:
void AudioEndpointVolume_OnVolumeNotification(AudioVolumeNotificationData data)
{
VolumeTimer.Interval = 300;
VolumeTimer.Stop();
VolumeTimer.Start();
}
private void VolumeTimer_Tick(object sender, EventArgs e)
{
VolumeTimer.Stop();
lock (_lock)
{
++_volumeCalledCounter;
if (_volumeCalledCounter <= 1)
{
Console.WriteLine("Fired");
_volumeCalledCounter = 0;
}
}
}
Yes, a Timer can fire repeatedly. Therefore you should Stop and Start it each time you get a volumeChange notification. While these come in faster than the Timer.Interval nothing else will happen. Once they stop coming, the Timer.Tick will finally fire. Here you stop the Timer one last time and fire your own event.
Using a Timer VolumeTimer and the original sources:
defaultDevice.AudioEndpointVolume.OnVolumeNotification += new
AudioEndpointVolumeNotificationDelegate(
AudioEndpointVolume_OnVolumeNotification);
void AudioEndpointVolume_OnVolumeNotification(AudioVolumeNotificationData data)
{
VolumeTimer.Interval = 100; // ms, test to gauge!
VolumeTimer.Stop();
VolumeTimer.Start();
}
private void VolumeTimer_Tick(object sender, EventArgs e)
{
VolumeTimer.Stop();
// whatever you want to do, when the volume no longer changes:
yourEvent();
}
Edit:
The above code should solve the original question.
However, if the user changes the volume slowly but for a prolonged time, your event won't fire all this time. If you want to enforce an UI update a little extra code will do that, using a second Timer VolumeUiTimer :
void AudioEndpointVolume_OnVolumeNotification(AudioVolumeNotificationData data)
{
VolumeTimer.Interval = 100; // ms, test to gauge!
VolumeTimer.Stop();
VolumeTimer.Start();
if (!VolumeUiTimer.Enabled)
{ VolumeUiTimer.Interval = 500; VolumeUiTimer.Start();
}
private void VolumeTimer_Tick(object sender, EventArgs e)
{ // no more changes: all timers stop, update UI
VolumeTimer.Stop();
VolumeUiTimer.Stop();
// whatever you want to do, when the volume no longer changes:
yourEvent();
}
private void VolumeUiTimer_Tick(object sender, EventArgs e)
{ //restart timer1, stop timer2, update UI
VolumeTimer.Stop();
VolumeTimer.Start();
VolumeUiTimer.Stop();
// whatever you want to do, when the volume no longer changes:
yourEvent();
}
I set the Intervals here just for demonstration; they could be moved to after InitializeComponent() or simply into the designer.
Aside on multiple Timers: There was a time when the number of Timers an application could create was limited to, I think 16. That is long gone and there is no problem creating a second Timer.

How can i make my TimerAction to work? (Windows Form Application)

I'm working at a Windows Forms application and i need to use timers.
I have this method to set the timer in order to do something at a certain time:
private void SetTimerValue()
{
// trigger the event at 7 AM. For 7 PM use 19 i.e. 24 hour format
// Console.Read();
DateTime requiredTime = DateTime.Today.AddHours(7).AddMinutes(00);
if (DateTime.Now > requiredTime)
{
requiredTime = requiredTime.AddDays(1);
}
// initialize timer only, do not specify the start time or the interval
myTimer = new System.Threading.Timer(new TimerCallback(TimerAction));
// first parameter is the start time and the second parameter is the interval
// Timeout.Infinite means do not repeat the interval, only start the timer
myTimer.Change((int)(requiredTime - DateTime.Now).TotalMilliseconds, Timeout.Infinite);
}
And this is the TimerAction:
private void TimerAction(object e)
{
// do some work with my webcam(start recording)
// now, call the set timer method to reset its next call time
SetTimerValue();
}
I call SetTimerValue() in my Form (Form1):
public Form1()
{
InitializeComponent();
SetTimerValue();
}
But after I run the application and timer reaches his time, the application closes.
It's something with my TimerAction method and with the parameters (object e) ?
The same action of the TimerAction I have it in a button1_Click_1(object sender, EventArgs e) and it works.
Can you help me?
Thanks
You need to use the right timer, i.e. one that will be executed on the UI thread.

Reset the count of inactive time in C#

I found this post and created a class that used it to detect inactive time and it works great. I set it for one minute and after one minute I can get it to "do stuff". What I am trying to do is only do something every "x" minutes of inactive time; i.e. every 5 minutes do this if things have been inactive and do not repeat again 'til X time has elapsed.
Now, I could set my timer to fire every 5 minutes instead of every second, but I would like to be able to "reset" the count of inactive time instead. Any suggestions?
This is for using the DispatchTimer in C# and WPF.
Just create a class level variable, increment it on your timer, and reset it when you get activity. Create a timer, say tmrDelay with an increment of 10000 milliseconds, and a button, btnActivity to reset the count, and do this:
private int tickCount = 0;
private const int tick_wait = 30;
private void tmrDelay_Tick(object sender, EventArgs e)
{
tickCount++;
if (tickCount > tick_wait)
{
DoSomething();
tickCount = 0;
}
}
private void btnActivity_Click(object sender, EventArgs e)
{
tickCount = 0;
}
It sounds like you want something like the following:
static DispatcherTimer dt = new DispatcherTimer();
static LastInput()
{
dt.Tick += dt_Tick;
}
static void dt_Tick(object sender, EventArgs e)
{
var timer = (DispatcherTimer)sender;
var timeSinceInput = TimeSpan.FromTicks(GetLastInputTime());
if (timeSinceInput < TimeSpan.FromMinutes(5))
{
timer.Interval = TimeSpan.FromMinutes(5) - timeSinceInput;
}
else
{
timer.Interval = TimeSpan.FromMinutes(5);
//Do stuff here
}
}
This will poll every 5 minutes to see if the system has been idle for 5 minutes or more. If it's been idle for less than 5 minutes it will adjust the time so that it will go off again at exactly the 5 minute mark. Obviously then if there has been activity since the timer was set it will be adjusted again so it will always aim for 5 minutes of idleness.
If you really want to reset the active time then you will actually need to trigger some activity either by moving the mouse or sending a keypress

Categories

Resources