I'm trying to move PictureBox "hero", with the WSAD keys. Its working, but it whenever there are 2 buttons pressed, it moves in the direction of the oldest button pressed (as it should), but when one of the buttons are released, there is a slight delay before it moves again. Does anyone have any idea how to fix this?
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.S:
hero.SetDirection("down");
break;
case Keys.W:
hero.SetDirection("up");
break;
case Keys.D:
hero.SetDirection("right");
break;
case Keys.A:
hero.SetDirection("left");
break;
}
hero.heroTimer.Start();
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.S || e.KeyCode == Keys.W || e.KeyCode == Keys.A || e.KeyCode == Keys.D)
{
hero.SetDirection("");
hero.heroTimer.Stop();
}
}
And this is from class Hero
private void heroTimer_Tick(object sender, EventArgs e)
{
switch (direction)
{
case "down":
this.Top = 5;
break;
case "up":
this.Top -= 5;
break;
case "left":
this.Left -= 5;
break;
case "right":
this.Left = 5;
break;
}
}
P.S I'm very sorry if the code is messy, I'm quite new to this.
CodePudding user response:
but when one of the buttons are released, there is a slight delay before it moves again
Probably because releasing any of the buttons stops the timer. One way to solve this would be to keep a list of keys that are pressed, and only stop the timer when all keys are released. This could also allow you to apply multiple movements, i.e. down left would move the picture diagonally. You might also want to call the heroTimer_Tick
method directly when a key is pressed, to start the movement on the same frame as the key press.
I would also suggest scaling your movement with the actual time between events. Winforms timer events can be delayed if the UI thread is busy doing other stuff, or even omitted altogether. So a stopwatch might be useful to accurately measure the time between each event and allow you to scale the movement.
It is fairly common in games to use a common update clock. Instead of multiple components using different timers you would just use a single one that either ticks at a fixed rate, as fast as possible, or as fast as possible up to some maximum framerate. This timer would then call update methods on all your game-components, often with a delta-time parameter. This tend to give a more consistent behavior since all components are updated in the same order every frame.
Finally, using strings to store the movement is not a good practice, and may result in issues not detected by the compiler. An enum would be much more appropriate type to describe movement with. Optionally using the [Flags] attribute and separate bits to describe multiple movements at the same time.