0
\$\begingroup\$

I am attempting to make a game in C# in windows forms, and need for the character to react to key input. I have implemented a very basic code which changes the position of a picture box on key pressed, and then displays the picture box in a new position:

    public Form1()
    {
        InitializeComponent();

        KeyDown += new KeyEventHandler(keyDown);
    }
    void keyDown(object sender, KeyEventArgs e)
    {
        int x = SpriteCharacter.Location.X;
        int y = SpriteCharacter.Location.Y;

        if (e.KeyCode == Keys.Right) x += 1;
        else if (e.KeyCode == Keys.Left) x -= 1;
        else if (e.KeyCode == Keys.Up) y -= 1;
        else if (e.KeyCode == Keys.Down) y += 1;
        else if (e.KeyCode == Keys.Escape) Close();

        SpriteCharacter.Location = new Point(x, y);
    }

The problem you can probably immediately spot is that this script cannot handle user input if two keys are pressed at the same time. E.g. if you press right and down, the character will not move diagonally, but will either go right or down, depending on which key was pressed last.

What would be a more advanced way to handle key input, to make something like this possible? Is these anything I could read up on?

\$\endgroup\$
4
  • \$\begingroup\$ add keys to a list and evaluate separately \$\endgroup\$ – Leggy7 May 24 '16 at 10:46
  • \$\begingroup\$ thanks for a comment, but I have NO idea how this can be done. Can't find any help anywhere else either. \$\endgroup\$ – guy120334913 May 24 '16 at 11:17
  • \$\begingroup\$ I am not sure why you are doing this in winforms. Winforms aren't really designed for games. Monogame framework will provide a lot of the boiler plate code to run a game in. \$\endgroup\$ – Jonathan Kaufman May 24 '16 at 20:10
  • \$\begingroup\$ @JonathanKaufman I'm just starting out with C# coding and I'm trying a lot of different stuff :) I know there are simpler and quicker ways to go about making games, but I actually wanted to start out with winforms, since it seems very basic and I thought it would be a nice learning experience to try and wrestle with it a bit \$\endgroup\$ – guy120334913 May 24 '16 at 22:22
1
\$\begingroup\$

The main problem here is that you don't have some sort of game loop. You record the keypress, but not the continious keydown (thus, if the letter 'A' is pressed for 10 seconds, only 1 event is triggered). Now this could be expected behaviour (only move one square one keypress at a time). With a gameloop you can have the object moving independant of the keypress events.

Here is a solution: Create a moveX and a moveY global variable.

Add the event OnKeyDown: if the Left key is pressed, set the moveX to -1, if the Right key is pressed set the moveX to +1. Do the same for the vertical movements.

Add the event OnKeyUp: if the Left key is let go, set the moveX to 0, same for the other keys.

What you now have, is a moveX and moveY that hold the direction the player wants to go.

Now, add a timer that elapses every 1/60th second (for 60 frames per second). When that timer expires, update the gameobject position according to the set moveX and moveY variables. This timer is effectively providing you a gameloop, in which you can do many other things; such as moving the enemies or other things that need to happen continiously.

\$\endgroup\$
1
  • \$\begingroup\$ I actually came up with something like this right before you posted this answer, but nevertheless thank you a lot.I assigned a private integer for each of the keys, and modified the KeyDown method to change the value of the given int to 1, and implemented KeyUp method that resets the value of the integer to 0 for the given key. I then used a Timer to make a recurring event that updates the position of the picture box each 10ms depending on which keys are currently pressed. \$\endgroup\$ – guy120334913 May 24 '16 at 13:47
0
\$\begingroup\$

When you use else you are preventing two if blocks to be evaluated at the same time. For your code you should use else only for the opposing axes, for example:

if (e.KeyCode == Keys.Right) x += 1;
else if (e.KeyCode == Keys.Left) x -= 1;

if (e.KeyCode == Keys.Up) y -= 1;
else if (e.KeyCode == Keys.Down) y += 1;

if (e.KeyCode == Keys.Escape) Close();
\$\endgroup\$
1
  • \$\begingroup\$ thanks, but that does not seem to help in any way. it does not change the fact that only the last pressed key is being handled. It seems like what I am trying to do would need to be implemented in a completely different way to what I came up with. \$\endgroup\$ – guy120334913 May 24 '16 at 12:38
0
\$\begingroup\$

If you wanted to know if the user held CTRL, SHIFT or ALT down whilst pressing another button then you could check the Modifiers:

            if(e.KeyCode == Keys.Up && e.Modifiers == Keys.Control)
                Debug.WriteLine("Up and Ctrl");

But your question is about right and down, if the user presses both at the same time one will trigger first and then the other, which will result in a diagonal move but via two moves instead of one. Is that what you want to achieve...a diagonal move in one? If so I'd use something other than the arrows, ideally the number pad if that's an option, then 3 is diagonal down/right in one move, 6 being move right.

The KeyDown event will only give you one key down at a time, unless the 'other' key is a modifier such as CTRL, SHIFT or ALT. So unless you want to write in some kind of delay and also hook into the KeyUp event (so you know they have released the key) so that...if the user clicks right and down fast enough then they move diagonally...your best bet is to have different keys to move diagonally...assuming that's what you want to achieve...

\$\endgroup\$
0
\$\begingroup\$

What you can do is create separate timers for each movement instance.

For example, for going up, down, right and left, you can create a timer that goes like:

private void up_Tick(object sender, EventArgs e)
        {
            //this makes the player go up
            player.Top -= 3;
        }
 private void down_Tick(object sender, EventArgs e)
        {
            //this makes the player go down
            player.Top += 3;
        }
 private void left_Tick(object sender, EventArgs e)
        {
            //this makes the player go left
            player.Left -= 3;
        }
 private void right_Tick(object sender, EventArgs e)
        {
            //this makes the player go right
            player.Left += 3;
        }

After creating the timers, you can create key up and key down events to handle the movement with keys -

private void yourFormName_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.W)
    {
    \\this starts the timer to go up and if you press the W key then the player goes up
    up.Start();
    }
    if (e.KeyCode == Keys.S)
    {
    \\this starts the timer to go down and if you press the S key then the player goes down
    down.Start();
    }
    if (e.KeyCode == Keys.D)
    {
    \\this starts the timer to go right and if you press the D key then the player goes right
    right.Start();
    }
    if (e.KeyCode == Keys.A)
    {
    \\this starts the timer to go left and if you press the W key then the player goes left
    left.Start();
    }

}

Hope this helped!

\$\endgroup\$
1
  • \$\begingroup\$ Please format your code. See the help center if you need guidance for how to ensure your code is displayed as you intend. \$\endgroup\$ – DMGregory Apr 26 '20 at 11:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.