I have a Windows form program which controls a light. This light has its own class. I can do things like turn it on an off and change the color etc. This I can do without issue. What I want to be able to do, however, is make the light go on for a specific amount of time, i.e. 100 milliseconds or 300 milliseconds (depending on use).
I have tried to used stopwatch to do this, but when I click on the button that is meant to do this, it freezes the program. The light goes on, then doesn't turn off, and I can't use the stop button I have which is meant to turn it off.
The program loads the light, and initialises it, and displays an alert saying it has done this and detected one light. Then I use this:
private void Red_Click_1(object sender, EventArgs e)
{
//Displays Red
System.Threading.Tasks.Task.Factory.StartNew((Action)delegate()
{
displayRedDot();
});
}
This is the displayRedDot()
public void displayRedDot()
{
System.Diagnostics.Stopwatch clock1 = new System.Diagnostics.Stopwatch();
long elapsedTime = clock1.ElapsedMilliseconds;
clock1.Start();
while (elapsedTime < 100)
{
oBlynclightController.Display(BlynclightController.Color.Red);
}
oBlynclightController.Display(BlynclightController.Color.Off);
clock1.Stop();
}
I have some other functions, which are identical this with a different time, which I haven't invoked anywhere yet because I can't get this to work.
Your code will never work since you are blocking the UI thread by busy waiting. This is the reason for your program seems to freeze. Use a timer or async/await instead
async void DisplayRedDot(int duration)
{
oBlynclightController.Display(BlynclightController.Color.Red);
await Task.Delay(duration);
oBlynclightController.Display(BlynclightController.Color.Off);
}
elapsedTime will never change its value. You initialize it right after creating the stopwatch, but never assign a new value to it. Stopwatch.ElapsedMilliseconds is a long. long is a value type. A copy is created and assigned to elapsedTime. You need:
while (clock1.ElapsedMilliseconds < 100)
{
oBlynclightController.Display(BlynclightController.Color.Red);
}
Note that this loop is going to run very quickly until that check returns false. Is this really what you want? I don't know exactly what your code is doing (you don't show us), but why not just set the color to red, wait 100ms, and then set it to... erm, Off.
It's also difficult for humans to pick up a change that only lasts 100ms. It's going to be a flicker at best.
Related
I am currently experimenting with Godot C# making a basic shooter and for the gun's fire rate I have been experimenting with different delay systems. Node Timers work although I'm trying to make the script generic, and the Timer calls seem to only call functions in the parent script.
I'm now looking at C#'s Task.Delay method and it also seems to work, with it being an async action it does not look to be affected by the frame rate or slow down the game.
My question is, is there any known issue for using Task.Delay in game applications: like is it unreliable or can it crash if too many instances of the method are called?
Here's the code below although I don't think it’s important:
private void shoot() {
//if "canShoot" spawn bullet
ShootCooledDown();
}
private async void ShootCooledDown() {
TimeSpan span = TimeSpan.FromSeconds((double)(new decimal(shotDelay)));
canShoot = false;
await Task.Delay(span);
canShoot = true;
}
My question is, is there any known issue for using Task.Delay in game applications: like is it unreliable or can it crash if too many instances of the method are called?
Not per se. There is nothing in particular wrong with Task.Delay in games, nor too many instances of it.
However, what you are doing after Task.Delay can be a problem. If you execute await Task.Delay(span);, the code that comes after might run in a different thread, and thus it could cause a race condition. This is because of await, not because of Task.Delay.
For example, if after await Task.Delay(span); you will be adding a Node to the scene tree (e.g. a bullet), that will interfere with any other thread using the scene tree. And Godot will be using the scene tree every frame. A quick look at Thread-safe APIs will tell you that the scene tree is not thread-safe. By the way, the same happen with virtually any widget API out there.
The solution is use call_deferred (CallDeferred in C#) to interact with the scene tree. And, yes, that could offset the moment it happens to the next frame.
I'll give you a non threading alternative to do that.
There are method get_ticks_msec and get_ticks_usec (GetTicksMsec and GetTicksUsec in C#) on the OS class, that give you monotone time which you can use for time comparison.
So, if you make a queue with the times it should shoot (computed by taking the current time plus whatever interval you need). Then in your process or physics process callback, you can check the queue. Dequeue all the times that are overdue, and create those bullets.
If you don't want to solve this with Godot APIs, then start a Stopwatch at the start of the game, and use its elapsed time.
But perhaps that is not the mechanic you want anyway. If you want a good old cool-down, you can start the Stopwatch when you need the cool-down, and then compare the elapsed time with the cool-down duration you want to know if it is over.
I don't have any experience with Godot.. but my idea would be....
instead of using a timer, you could store the last shoottime in a variable/field. If you're trying to shoot within the lastTimeShot+coolDown, just ignore the shoot command.
For example:
private DateTime _lastShot = DateTime.MinValue;
private void shoot()
{
TimeSpan span = TimeSpan.FromSeconds((double)(new decimal(shotDelay)));
// if the time when the last shot has fire with the cooldown time
// is greater than the current time. You are still in the cooldown time.
if(_lastShot.Add(span) > DateTime.UtcNow)
return; // within cooldown, do nothing
//if "canShoot" spawn bullet
ShootCooledDown();
_lastShot = DateTime.UtcNow;
}
Due to a valid comment of Theodor, about changing the system time would lead bug-prone gameplay.
I wrote a second version.
private Stopwatch _shootingCooldownStopwatch = default;
private void shoot()
{
var shotDelayMs = shotDelay * 1000;
// if the _shootingCooldownStopwatch is ever started
// and the ElapsedMilliseconds are in the showDelay
// we're not allowed to fire again. So exit the method.
if (_shootingCooldownStopwatch?.ElapsedMilliseconds < shotDelayMs)
return;
_shootingCooldownStopwatch = Stopwatch.StartNew();
//if "canShoot" spawn bullet
ShootCooledDown();
}
I think this would be a better solution.
When you develop games in Godot or any other game engine, you shouldn't use any timer based in the computer clock, like the Stopwatch or Task.delay. Instead, you have to manage yourself the time elapsed using the delta time from the previous frame, which is received in the _Process(float delta) or _PhysicsProcess(float delta) methods. The reason are:
The time will be more accurate in case of frame-rate drop.
If you pause the game, timer will pause too.
That's the main reason Godot offers you a Timer component that you have to attach to the current scene in order to work with it.
If you don't want to add anything to the scene, which completely reasonable, you have to get the delta, storing the elapsed time in a variable and check if this variable reach some limit.
In my games, I use my own timers with this very simple class:
public class Timer {
public float Elapsed { get; private set; } = 0;
public bool Stopped { get; private set; } = true;
public float Alarm { get; private set; } = float.MaxValue;
public Timer Start() {
Stopped = false;
return this;
}
public Timer Stop() {
Stopped = true;
return this;
}
public Timer Reset() {
Elapsed = 0;
return this;
}
public Timer ClearAlarm() {
Alarm = float.MaxValue;
return this;
}
public Timer SetAlarm(float finish) {
Alarm = finish;
return this;
}
public bool IsAlarm() => Elapsed > Alarm;
public Timer Update(float delta) {
if (!Stopped) {
Elapsed += delta;
}
return this;
}
}
```
You have to Update the timer in every frame
I am no expert in Godot but I can tell that Task.Delay() is considered better than alternatives like Thread.Sleep() for example because being asynchronous i releases the thread to the thread pool and when the time has passed it continues execution, in contrast to the latter option that blocks the thread instead.
The problem I can see is that each web server can accept a max limit of concurrent requests, by using Task.Delay() in your code you can start accumulating requests "just waiting" due to the delay. So if your app starts receiving a big amount of requests coupled with a long Delay time that might be an issue with requests queued up (delay) or even denied.
If the delay is a number of seconds (significant time) then I would probably think about storing user in a cache (you can also store in a dictionary Dictionary<string, bool> where string is the userId but this solution will not scale out, that is why I suggest a distributed cache), and check (TryGetValue()) your cache if user is allowed to shoot. If delay is a couple of microseconds (affordable time) still not an ideal solution but it will probably be a problem.
In contrast to the answer by #Theraot and its approach via await Task.Delay(span) and according to my understanding, asynchronous does NOT equal to multi-threading. Using await Task.Delay(span) won't cause your code executing in another thread. So you don't really need to use CallDeferred in this case.
Reference:
What is the difference between asynchronous programming and multithreading?
Does Task delay create new Thread?
Does the use of async/await create a new thread?
Even though i have some experience in c#, this is my First game in C#. I am trying to set up the minimal skeleton of the game. I heard that Tick Event is a bad approarch for creating the main game loop.
This is the main concept of what I am trying to implement:
Program.cs
//Program.cs calls the Game Form.
Application.Run(new Game());
Game.cs
public partial class Game : Form
{
int TotalFramesCount = 0;
int TotalTimeElapsedInSeconds = 0;
public Game()
{
InitializeComponent();
GameStart();
}
public void GameStart()
{
GameInitialize();
while(true)
{
GameUpdate();
TotalFramesCount++;
CalculateTotalTimeElapsedInSeconds();
//Have a label to display FPS
label1.text = TotalFramesCount/TotalTimeElapsedInSeconds;
}
}
private void GameInitialize()
{
//Initializes variables to create the First frame.
}
private void GameUpdate()
{
// Creates the Next frame by making changes to the Previous frame
// depending on users inputs.
}
private void CalculateTotalTimeElapsedInSeconds()
{
// Calculates total time elapsed since program started
// so that i can calculate the FPS.
}
}
Now, this will not work because the while(true) loop blocks the Game Form from initializing. I found some solutions to this, by using System.Threading.Thread.Sleep(10); or Application.DoEvents();, but I didn't manage to make it work.
To explain why I want to implement this code here is an example of the above code in use:
Lets say I want my game to do the following:
Smoothly move a 100x100 Black colored Square from point (x1,y1) to (x2,y2) and backwards, in a loop and display the FPS in the label1 of the above code. With the above code in mind, I could possibly use TotalTimeElapsedInSeconds variable to set the speed of the movement to be relevant with the Time and not the Frames, as the Frames will differ on each machine.
// Example of fake code that moves a sqare on x axis with 20 pixels per second speed
private void GameUpdate()
{
int speed = 20;
MySquare.X = speed * TotalTimeElapsedInSeconds;
}
The reason i though of using a while(true) loop is that I will get the best FPS I can on each machine.
How could I implement my idea on actual code ? (just the basic skeleton is what i am looking for)
How could I set a max of, lets say 500 FPS to make the code "lighter" to run? instead of trying to produce as many frames as possible which I suspect will needlesly over-use the CPU(?)
Frame rate has nothing to do with smoothness. Even if you accomplish 500 frames/sec the movement will be choppy or worse. The trick is to synchronize with your monitor refresh rate. So for a monitor with 60Hz you need 60 frames/sec no more no less. You can't do that by using a loop in C#. You need DirectX or XNA. These frameworks can synchronize your drawings with the vertical scan of your monitor.
You need to make own thread to that while(true)-loop:
Thread thread = new Thread(new ThreadStart(GameStart));
thread.Priority = ThreadPriority.Lowest;
InitializeComponent();
thread.Start();
Check this blog post to get more coding intuition:
https://praybook2.blogspot.com/2020/04/this-now-advanced-stuff.html
Tough it loop fast. There are many disadvantages by using the threads, consider using some ready built game engine --like Godot; where all these kinds of small problems are fixed beforehand, use threads only when they are needed.
I'm writing a program to help with a game. I need it to update the text box that shows the current exp value, on the forum load it does show the exp, I need it to update the exp like every 3 seconds.
How would I go about doing that?
Here is what I have so far:
Client C = Client.GetClients()[0];
Player P;
P = C.GetPlayer();
expTextBox.Text = ("Experience: " + P.Experience.ToString());
I am not sure if I need a timer (which i have tried and I am very bad at making) or if a backGroundWorker would be best.
Based on your comments, I would recommend that you update your UI when your player/s are attacking, and not use a timer. This will keep your UI the most up-to-date and will probably serve you better than a 3 or 10 second timer. You will have a method like this:
public void Attack(Enemy e)
{
//do your attack code
//did the enemy die?
KillEnemy();
//add exp just for landing a successful attack
AddExp(e);
}
public void AddExp(Enemy e)
{
CurrentPlayer.Exp += e.ExperienceGain;
//update the UI with the new exp
GameWindow.ExperienceBox.Text = CurrentPlayer.Exp;
}
This is of course more pseudocode, because I have no idea what your design looks like, but I've made quite a few games, and this is how I always do it.
Good Luck!
I would encourage you to use Timer if you go to the background worker with infinite loop that is okay but you need to take care of two things when you use background workers:
Updating textbox or any other UI won't work as it needs to be done from the main thread. so you need to check myTextbox.requireInvoke() function before.
Check if the background worker got a cancel signal to exist the infinite loop.
on the other side. you will consume some time when you use timers to update the text box. as the timer would go to the event processing cycle in the windows then fire the event and finally you will write the code in the timer event.
I searched a few links for Timer Control for both Windows and WPF applications but I would appreciate some advice on my situation...
As I'm using WPF it seems initial options are either System.Windows.Threading.DispatcherTimer or System.Diagnostics.Stopwatch
What I need to achieve is for each WPF DocumentPanel to request an update from an external API at a defined interval between typically 100ms Min - anytime Max with the interval unique to each DocumentPanel. Eg DP1 could be 100ms, DP2 could be 20,000ms etc.
Normally my app would start with 1 DocumentPanel but the user can expand panels without limit so it's the users judgement on CPU ability and speed of app.
Criteria include:
Multiple DocumentPanels - Typically 1 - 20 minimum but any advice on scalability is welcome.
Variable event interval (Iv) (Minimum event interval 100ms - Max < 1day)
Accuracy - 1ms (cannot have interval below (Iv)ms under ANY circumstances, over is not as much concern but needs to be be within several ms) EDIT: 1ms is not strictly a requirement but average (Iv) must be maintained over a short timescale.
Each DocumentPanel must display live date/time but produce events based on set interval
I'm really after help with design consideration rather than actual code at the moment as WPF is confusing matters for me.
Currently, I'm verging towards using a single instance of System.Diagnostics.Stopwatch and allow each panel to act on the stopwatch event whether the interval time has been reached.
Can anyone advise?
Thank you
O
its better to use just one System.Windows.Threading.DispatcherTimer with 100ms as ticks, then use Tags to determine its own interval, for example you can use
struct IntervalComparer
{
int myinterval; //the individual update interval (300ms for example)
int currentinterval;
public IntervalComparer(int myinterval)
{
this.myinterval=myinterval;
this.currentinterval=0;
}
public void TickMe()
{
currentinterval++;
}
public void ResetkMe()
{
currentinterval = 0;
}
public bool CanIUpdate()
{
return myinterval == currentinterval;
}
}
on the creation
.... Form_Loaded....
{
.....
mypanel=new Panel();
mypanel.Tag= new IntervalComparer(2); // 2 * 100ms
.....
}
.... Timer_Tick....
{
....
(mypanel.Tag as IntervalComparer).TickMe();
if((mypanel.Tag as IntervalComparer).CanIUpdate())
{
UpdateMyPanel();//your update method
(mypanel.Tag as IntervalComparer).ResetMe();
}
....
}
Generally in a case like this I would have a single timer which when then check for the elapsed time for each DocumentPanel. I'm guessing 100% accuracy is not critical, if they select 999ms then they won't notice if you main timer fires every 50ms so can only give them increments of 50ms. Windows does not give that sort of accuracy anyway, I learnt this when trying to trigger a flash once.
I've used the following approach to achieve something similar in a Silverlight app:
Single timer which ticks at a small interval (you're discretion, but would need to be lower than the lowest supported update interval), and then have each DocumentPanel subscribe to this timer's tick event.
When the tick event is fired, each DocumentPanel would then determine if an update is required based on it's update frequency (E.G. (last update - now ) > interval).
There's a comparison of some timer classes here:
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx
DispatcherTimer isn't mentioned, but the important difference between DispatcherTimer and System.Timers.Timer is:
If a System.Timers.Timer is used in a WPF application, it is worth
noting that the System.Timers.Timer runs on a different thread then
the user interface (UI) thread. In order to access objects on the user
interface (UI) thread, it is necessary to post the operation onto the
Dispatcher of the user interface (UI) thread using Invoke or
BeginInvoke. Reasons for using a DispatcherTimer opposed to a
System.Timers.Timer are that the DispatcherTimer runs on the same
thread as the Dispatcher and a DispatcherPriority can be set on the
DispatcherTimer.
(from http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchertimer.aspx).
Without knowing how you are currently handling UI updates and how you're program is structured, it's hard to say which timer you should use.
I'm not hugely familiar with the using the StopWatch, but my opinion is (after reading http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx) that using a single StopWatch isn't something that is particularly suited to this problem
use can inherit from DocumentPanel if you need the Tag property & for more encapsulation
class UpdatableDocumentPanel : DocumentPanel
{
public int myinterval { get; set; }//the individual update interval (300ms for example)
int currentinterval;
public void Update()
{
currentinterval++;
if (myinterval == currentinterval)
{
currentinterval = 0;
UpdateMyPanelMethod();
}
}
}
and
.... Form_Loaded....
{
.....
mypanel.myinterval = 2; // 2 * 100ms
.....
}
.... Timer_Tick....
{
....
mypanel.Update(); // simply
....
}
Let's say I have a Windows Forms timer configured with a 10 second (10k ms) interval:
myTimer.Interval = 10000;
I want to start it and fire off the Tick event right away:
myTimer.Start();
myTimer_Tick(null, null);
The last line works but is there a better or more appropriate way?
The only thing I'd do differently is to move the actual Tick functionality into a separate method, so that you don't have to call the event directly.
myTimer.Start();
ProcessTick();
private void MyTimer_Tick(...)
{
ProcessTick();
}
private void ProcessTick()
{
...
}
Primarily, I'd do this as direct calling of events seems to me to be a Code Smell - often it indicates spagetti structure code.
There are at least 4 different "Timers" in .NET. Using System.Threading you can get one that specifically allows you to set the initial delay.
var Timer = new Timer(Timer_Elapsed, null, 0, 10000);
There are benefits to using the different timers and here is a good article discussing them all.
You could set the interval to 1 (0 probably means infinite timeout) and set it to 10k when it ticks for the first time.
The timer will tick "very soon" (depending what type of Timer you are using, see this) but the execution will not continue with the click handler as in your solution.
(I suppose you knew about the solution from Bevan).
Use two timers.
The First that has the normal interval you want to use and just enables the Second timer.
The Second timer has an interval of 100ms and is normally disabled. It runs your code and then disables itself.
To manually trigger, just enabled the Second timer.
This also allows you to trigger the code from another form using full qualification naming to the Second timer. I use this when calling from one form to another.