In my WP7 app, player draws a line and then CPU draws a line. I want CPU to wait for 5 sec before processing and drawing the line. I use this System.Threading.Thread.Sleep(5000);just after player is done drawing. But the player's line is not drawn completely and system goes to sleep and after 5 sec both lines are drawn. How to complete the player's line and then to start the delay ?
System.Threading.Thread.Sleep(5000) will freeze your app and your UI. Your app will surely not pass certification because of this.
Use DispatcherTimer.
Follow this link for more info.
You can use DispatcherTimer to add some delay immediately after the player's turn.
This is typically what you could do:
Class Variables:
DispatcherTimer delayTimer = new DispatcherTimer();
int timesTicked = 0;
In your Constructor:
delayTimer.Interval = new TimeSpan(0, 0, 0, 0, 5000);
delayTimer.Tick += new EventHandler(timer_Tick);
Handler:
void delayTimer_Tick(object sender, EventArgs e)
{
timesTicked++;
if(timesTicked == 2)
{
timesTicked = 0;
delayTimer.Stop();
RunCPU();
}
}
The above tracks the amount of times the Timer has ticked and after two ticks, it calls the RunCPU method. Note that the above will 10 seconds. You can play around with the numbers to find a niche for the delay.
Try with Application.DoEvents(); before sleep.
Related
I want my game's screen to have a timer on screen that shows how many seconds have passed (representing the player's point score). I am able to get the timer on screen, however, the counter freaks out and my console doesn't print the result correctly either. Any ideas?
I've tried to use timer.Elapsed however SplashKit (what i must use) does not seem to recognise that.
Sorry if this is a repeated question, I am new to programming and have searched around but couldn't find anything I could comprehend/assist.
public void Timer()
{
//begin timer and print results
timer.Start();
//write to console how many milliseconds have passed, and divide by 1000 for seconds.
Console.WriteLine($":{timer.Ticks} milliseconds have passed");
Console.WriteLine($"which is {timer.Ticks /1000} seconds");
//covert timer.Ticks to string and store into string 'score
score = Convert.ToString(timer.Ticks);
//assign font
Font Quicksand = SplashKit.LoadFont("Quicksand", "Resources\\fonts\\Quicksand-Regular.otf");
//use SplashKit to print to screen..
SplashKit.DrawText(score, Color.Black, Quicksand, 70, 700, 900);
}
+1 to Eric j's comment- all the Timer types the framework that I know of are not for providing stopwatch style "the game has been running 5 minutes" type functions directly themselves. They're classes that raise an event at some predefined interval. The actual timing of the game, if using a Timer, would be done by you by recording the start time and differencing the time now to it upon the timer elapsing it's interval:
public class Whatever{
private Timer _t = new Timer();
private DateTime _start;
public Whatever(){ //constructor
_t.Elapsed += TimerElapsed; //elapsed event handled by TimerElapsed method
_t.Interval = 1000; //fire every second
}
public void StartGame(){
_start = DateTime.UtcNow;
_t.Start();
}
private void TimerElapsed(){
Console.WriteLine("Game has been running for " + (DateTime.UtcNow - _start));
}
The timer interval merely controls how often the clock will update on screen. If you're offering game times of 10.1,10.2 seconds etc then make the timer interval less than 100 (updates more than once every 0.1 seconds) for example
It's not clear what type timer is, but the property Elapsed is probably a TimeSpan.
The total seconds including decimal amount is present in the double value:
timer.Elapsed.TotalSeconds
You can truncate that to an integer by casting it
var seconds = (int)timer.Elapsed.TotalSeconds;
I'm programming a tetris game. So far I have implemented a timer with a very short interval of around 50 ms. Every tick the current falling tetromino gets moved one position in the game matrix downwards. Then the game checks if there is a collision, if so the tetromino gets marked as "landed" and new tetromino is spawned.
No I have the problem that I want to give the player the chance to move the tetromino to the left or right for let's say 0.5 seconds after it landed to have the possibility to move the tetromino underneath an overhanging already landed tetromino.
But with my current code I have the problem that as soon as there is a collision detected the timer continues and spawns the next tetromino. My idea now was to try to implement a second timer that gets activated for 0.5 seconds everytime a collision is detected to allow for additional keyboard input bevore the main timer continues. So basically pausing the main timer for 0.5 seconds and allow the program to detect keyboard input during that time and then continue with the main timer.
Everything I tried so far didn't really work. It seems like the first timer always continues running while I have a second timer active.
This is how my first timer looks like:
private void TimerBrick_Tick(object sender, EventArgs e)
{
ResetGameBoard(jaggedTetrisBricks[rnd-1][rotation], _brickX, _brickY, xLengthBrick, yLengthBrick);
_brickX++;
CollisionCheck(jaggedTetrisBricks[rnd - 1][rotation], _brickX, _brickY, xLengthBrick, yLengthBrick);
LineCheck();
Invalidate();
}
Now I somehow need to implement inside my CollisionCheck() method a way to wait for 0.5 seconds before the code continues with LineCheck().
Or is there another way that I'm not seeing right now?
In addition to my previous comment - here is a bit of pseudo-code :
enum GameState
{
Starting,
CreateBrick,
BrickFalling,
MoveSideways
}
private GameState curState = Starting;
private ushort ctSideways;
private void TimerBrick_Tick(object sender, EventArgs e)
{
switch (curState)
{
case Starting:
InitialiseGame();
curState = CreateBrick;
break;
case CreateBrick:
CreateNewBrick();
curState = BrickFalling;
break;
case BrickFalling:
.....
.....
if (CollisionCheck())
{
ctSideways = 0;
curState = MoveSideways;
}
break;
case MoveSideways:
.....
.....
ctSidways++;
if (ctSideways == 10)
curState = CreateBrick;
break;
}
}
Alright, so I've done some research into this topic and most of the solutions I've found claim to fix the problem but I am finding that they aren't quite working right. I'm in the early stages of implementing just a simple little particle engine, nothing crazy I'm just doing it out of boredom. I have not done anything like this with WinForms before, I have certainly with C/C++ but this is a new thing for me. The following is the code I am using to draw the particles to the screen, the boiler plate code for the particles is not relevant as it works fine, I am more curious about my actual game loop.
Here is the main code for updates and redraws
public MainWindow()
{
this.DoubleBuffered = true;
InitializeComponent();
Application.Idle += HandleApplicationIdle;
}
void HandleApplicationIdle(object sender, EventArgs e)
{
Graphics g = CreateGraphics();
while (IsApplicationIdle())
{
UpdateParticles();
RenderParticles(g);
g.Dispose();
}
}
//Variables for drawing the particle
Pen pen = new Pen(Color.Black, 5);
Brush brush = new SolidBrush(Color.Blue);
public bool emmiter = false;
private void EmitterBtn_Click(object sender, EventArgs e)
{
//Determine which emitter to use
if (emmiter == true)
{
//Creates a new particle
Particle particle = new Particle(EmitterOne.Left, EmitterOne.Top, .5f, .5f, 20, 20);
emmiter = false;
}
else if(emmiter == false)
{
Particle particle = new Particle(EmitterTwo.Left, EmitterTwo.Top, -.5f, .5f, 20, 20);
emmiter = true;
}
}
public void RenderParticles(Graphics renderer)
{
Invalidate();
Thread.Sleep(0);
//Iterate though the static list of particles
for (int i = 0; i < Particle.activeParticles.Count; i++)
{
//Draw Particles
renderer.DrawRectangle(pen, Particle.activeParticles[i].x,
Particle.activeParticles[i].y,
Particle.activeParticles[i].w,
Particle.activeParticles[i].h);
}
}
public void UpdateParticles()
{
for (int i = 0; i < Particle.activeParticles.Count; i++)
{
//Move particles
Particle.activeParticles[i].MoveParticle();
}
}
The issue I am running into is that anytime the screen is getting cleared and updated, it gets this awful flickering, and not only that but it sometimes won't whenever I emit a particle.
The form is basically just using labels as invisible locations on the screen to say where to render each particle.
Anyway, I've seen this topic before but nothing has fixed anything, the current implementation is the least flickery/laggy but is not solving the issue.
Any help is appreciated, thanks!
EDIT* I realized I was never deallocating the graphics object each loop so I did that and there is no more delay whenever I click the emitter button, however the flicker is still there, I updated the code accordingly.
Getting rid of the visible paint artifacts requires double-buffering. In other words, render the scene into a back-buffer that, when ready, gets quickly blitted to the screen surface in a single step. That's a built-in feature in Winforms, simply set the DoubleBuffered property to true in the form constructor. You must use the Paint event to take advantage of that. Override OnPaint() and call RenderParticles(e.Graphics).
You need to take care of timing, right now your UI thread is burning 100% core and animation speed completely depends on the number of particles and the speed of the machine. Instead of Application.Idle, drop a Timer from the toolbox onto your form. In the Tick event handler, call UpdateParticles() and this.Invalidate() to get the Paint event to fire again. The timer's Interval property value is critical, you get the most reproducible update rate by picking 15 or 31 msec (64 or 32 FPS).
You are not always going to get the desired FPS rate, the timer will simply delay or skip a Tick event if the machine gets busy or is too slow or other code on the UI thread needs to run. To make sure that doesn't affect the animation, you must measure actual elapsed time instead of moving the particles by a fixed amount. Either Environment.TickCount, DateTime.UtcNow or Stopwatch are suitable ways to measure true elapsed time.
pretty new here...
I am making a program that will allow a user to control a sprite (walking on a surface/jumping/falling - the usual... pretty basic i know)
To make the sprite jump in such a way, so that the human eye can actually see a rise and fall on the form, i need to slow the process by which the program translated the sprite upwards.
I decided to use a timer, not SLEEP because i don't want the whole program to freeze.
Here's what i came up with:
private void jump()
{
global.CharacterY = global.CharacterY - 1;
framer_Tick(null, new EventArgs()); //pause program without freezing
}
private void framer_Tick(object sender, EventArgs e)
{
sprite.Location = new Point(global.CharacterX, global.CharacterY);
}
Called by this:
private void Stage_KeyDown(object sender, KeyEventArgs e)
{
if (global.counter >= 1 & e.KeyCode.ToString() == "D")
{
global.CharacterX = global.CharacterX + 1;
jump();
}
if (e.KeyCode.ToString() == "W")
{
while (global.counter < 50)
{
jump();
global.counter = global.counter + 1;
}
global.counter = 0;
}
if (e.KeyCode.ToString() == "D")
{
global.CharacterX = global.CharacterX + 1;
sprite.Location =
new Point(global.CharacterX, global.CharacterY);
}
if (e.KeyCode.ToString() == "A")
{
global.CharacterX = global.CharacterX - 1;
sprite.Location =
new Point(global.CharacterX, global.CharacterY);
}
}
Now, the timer doesn't seem to have any effect. I assumed that placing the code to translate the sprite inside the timer would make it fire once every time the timer ticked.
- Unfortunately i don't have the experience make the timer pause the program (preferably 30 times a second, at an interval of 33(ish)) -
Simply changing the location of the sprite will not do anything. You have to call Invalidate() on whatever control the sprite is being drawn on to see the effect.
Also, you don't call framer_tick to get the process started. You have to call Start and Stop methods on the timer object. When you call Start, the tick handler will start getting called. When you call Stop, it will stop.
To make all of your animation smooth and logic less problematic your tick timer should be going off all the time because you should be redrawing the screen all the time. With the screen refreshing itself you just change the location of the sprite and the animation will behave as you expect it.
Simply changing the location of the sprite will not do anything. You have to call Invalidate() on whatever control the sprite is being drawn on to see the effect. Also, you don't call framer_tick to get the process started. You have to call start/stop on the timer object. When you call start, the tick handler will start getting called. When you call stop, it will stop. But I agree with #Chris. Your tick timer should be going off all the time because you should be redrawing the screen all the time. After that you just change the location of the sprite and everything will be fine. – Paul Sasik
I have a user control that shows a speed in a dial format (An image).
It has a single method: SetSpeed(int speed);
It then makes the dial move to the desired speed, from the last set speed. It does then in incriments. That is, it moves to the new speed.
Problem is, if the car is going 10km/h, and then goes (very quickly) to 100km/h, it takes the dial maybe 2 seconds to reach that speed... (It's not 100% real time - which is realistic .. it moves to the new speed).
But, if, before the dial gets to 100km/h, the person slows to 50km/h, I need to interupt the movement to 100, and start moving to 50. Regardless of the current position (not speed) of the dial, I need to change the 'target speed'.
My control is using a BackgroundWorker to handle the refreshing, and not lock the UI.
So, my call is very basic from the UI:
dial1.SetSpeed(int.Parse(value));
And then the user control does this:
BackgroundWorker bw = new BackgroundWorker();
public void SetSpeed(int speed)
{
while(bw.IsBusy)
{
Thread.Sleep(50);
}
bw.RunWorkerAsync(speed);
}
And the method that does the work:
private void UpdateSpeed(object sender, DoWorkEventArgs e)
{
var oldSpeed = airSpeed;
var newSpeed = (int) e.Argument;
if(oldSpeed <= newSpeed)
{
for (int i = oldSpeed; i < newSpeed; i++)
{
airSpeed++;
this.Invoke(new MethodInvoker(Refresh));
}
}
else
{
for (int i = oldSpeed; i > newSpeed; i--)
{
airSpeed--;
this.Invoke(new MethodInvoker(Refresh));
}
}
airSpeed = newSpeed;
}
It locks when I send it two values in quick succession...
How do I interrupt the thread, if it's running, and change the value?
(Also, I think my code to change the speed is bad - can that be made neater?)
You do not. You handle it in a proper way, with locks, and checking whether the value needs changing. You do NOT interrupt it.
Basically, you need a lock area between SetSpeed and the Refresh method, so that one blocks the other. Then, when you set speed and the thread is currently in a critical area, it simply waits until the update is finished.
And your UpdateSpeed makes no sense - the change (airspeed-- and airspeed++) should be timer driven... you currently change them in a "arbitrary" speed, depending on processor speed. No timing.