Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Move a control smoothly using KeyDown event

I am trying to make a simple game in C# using Visual Studio Windows Form Application. I want to let the user be able to move the blue box upwards, rightwards, downwards, and leftwards freely using the corresponding keys.

I am using a Timer which detects the new location of the box every 0.1 seconds, and a keydown event that actually changes the location of the box. The box needs to keep moving in the corresponding direction while the key is held down.

My problem is, my current program does the job except that when the user first presses a key, the box moves a little bit once and pauses for a moment before it keeps moving. I want to make this box move more smoothly from the first key press without pausing like that. This might be difficult to explain by words so I added a gif file.

enter image description here

Is there a way to fix this? Here is my current code.

private int posX, posY; //Both initialized in Form Load event

private void Form1_KeyDown(object sender, KeyEventArgs e)
{ 
    if (e.KeyCode == Keys.Up)
        posY -= 3;
    else if (e.KeyCode == Keys.Right)
        posX += 3;
    else if (e.KeyCode == Keys.Down)
        posY += 3;
    else if (e.KeyCode == Keys.Left)
        posX -= 3;
}

//Timer ticks every 0.1 second
private void Timer_Tick(object sender, EventArgs e)
{
    Box.Location = new Point(posX, posY);
    labelPosX.Text = posX.ToString(); //Testing purposes
    labelPosY.Text = posY.ToString(); //Testing purposes
}

I would love to use KeyDown event to achieve this, but if there is a better or more common way actually used in real game worlds, I would love to know about it too!

like image 639
Mika Jones Avatar asked Dec 26 '17 15:12

Mika Jones


1 Answers

Use Keyboard.IsKeyDown method in your Timer_Tick method, and don't listen for the keydown event.

Like so:

double posX, posY;

private void Timer_Tick(object sender, EventArgs e)
{
    double velocity = /*(speed: pixels per seconds)*/ 100 * /*(timer tick time in seconds)*/ 0.003;

    if (Keyboard.IsKeyDown(Keys.Up))
    {
        posY -= velocity;
    }
    else if (Keyboard.IsKeyDown(Keys.Down))
    {
        posY += velocity;
    }
    //Also, don't put else here, so you can go diagonally.
    if (Keyboard.IsKeyDown(Keys.Left))
    {
        posX -= velocity;
    }
    else if (Keyboard.IsKeyDown(Keys.Right))
    {
        posX += velocity;
    }

    Box.Location = new Point((int)posX, (int)posY);
    labelPosX.Text = posX.ToString(); //Testing purposes
    labelPosY.Text = posY.ToString(); //Testing purposes
}

public static class Keyboard
{
    private static readonly HashSet<Keys> keys = new HashSet<Keys>();

    public static void OnKeyDown(object sender, KeyEventArgs e)
    {
        if (keys.Contains(e.KeyCode) == false)
        {
            keys.Add(e.KeyCode);
        }
    }

    public static void OnKeyUp(object sender, KeyEventArgs e)
    {
        if (keys.Contains(e.KeyCode))
        {
            keys.Remove(e.KeyCode);
        }
    }

    public static bool IsKeyDown(Keys key)
    {
        return keys.Contains(key);
    }
}

And to use the Keyboard class, sets the Form1's KeyDown and KeyUp events in the InitializeComponent method.

KeyDown += Keyboard.OnKeyDown;
KeyUp += Keyboard.OnKeyUp;

You can control it's speed by changing the velocity.

like image 167
rokkerboci Avatar answered Oct 11 '22 14:10

rokkerboci