3
\$\begingroup\$

I'm working on a Pong game and right now I'm working on being able to register multiple KeyDown presses simulatenously. I used the Win32 native method GetKeyBoardState first to loop through all of the virtual keys and see if any of the keys matched the game input keys. Now this worked just fine but in the interest of optimization I figured that it would be quicker to use GetKeyState since there are only 4 valid input keys and then simply check if any of those keys are pressed down.

Surprisingly it is incredibly slow and choppy, a lot worse than GetKeyBoardState so I'm wondering if there's something in my code that's slowing it down. Here's the complete implementation

NativeMethods.cs

internal static class NativeMethods
    {
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool GetKeyboardState(byte[] lpKeyState);

        [DllImport("user32.dll")]
        internal static extern short GetKeyState(int nVirtKey);
    }

Keyboard.cs

static class Keyboard
{
    public static bool GetKeyState(Keys vKey)
    {
        short results = NativeMethods.GetKeyState((int)vKey);
        // We're only going to use this to look for arrow keys so
        // No need to differntiate results based on low or high order bits
        switch (results) 
        {
            case 0: //KEY STATE: NOT PRESSED
                return false;
            case -127: //KEY STATE: PRESSED
                return true;
        }
        return false;
    }

GameForm.cs

 private void GameForm_KeyDown(object sender, KeyEventArgs e)
        {
            var movementData = new Tuple<int, Move>(-1, Pong.Move.Down);

            //Check how many keys that are pressed down (for example both players might be moving their paddles simulatenously)
            var pressedKeys = inputKeys.Where(key => Keyboard.GetKeyState(key));

            //Check if pressed key equals any of the player assigned keys.. If so call MovePaddle()

            foreach (Keys key in pressedKeys)
            {
                switch (key)
                {
                    case Keys.Up:
                        movementData = Tuple.Create(0, Pong.Move.Up);
                        break;
                    case Keys.Down:
                        movementData = Tuple.Create(0, Pong.Move.Down);
                        break;
                    case Keys.W:
                        movementData = Tuple.Create(1, Pong.Move.Up);
                        break;
                    case Keys.S:
                        movementData = Tuple.Create(1, Pong.Move.Down);
                        break;
                }
                gameController.MovePaddle(movementData.Item1, movementData.Item2);
            }           
        }
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Your bool GetKeyState is incorrect. The reason for this is that the comment

No need to differntiate results based on low or high order bits

is wrong. The low bit will alternate between 0 and 1 for all keys, not just caps-lock/num-lock/scroll-lock. So the method will return false for every second key-press.

Replace it by:

public static bool GetKeyState(Keys vKey)
{
    short state = NativeMethods.GetKeyState((int)vKey);
    return (state & 0x80) != 0;
}
\$\endgroup\$
2
\$\begingroup\$

What is impacting you performance so heavily is the creation of Tuples everytime you recieve a keypressed event.

creating objects is slow. What you should do instead is, directly apply the changes to the moving objects (your two pong-thingies).

private void GameForm_KeyDown(object sender, KeyEventArgs e)
{
   var pressedKeys = inputKeys.Where(key => Keyboard.GetKeyState(key));
   foreach(Keys key in pressedKeys)
      switch(key){
         case Keys.Up:
             leftPong.Positon += FIXEDVALUE;
             break;
         case Keys.Down:
             leftPong.Position -= FIXEDVALUE;
             break;
         //continue...
\$\endgroup\$
3
  • \$\begingroup\$ Are you saying that there's a big difference in performance inbetween creating one instance of an integer, one instance of an enum and create one instance of a tuple to hold aforementioned instances? I must admit I didn't think that tuples would take up a lot of resources. \$\endgroup\$ Apr 18, 2014 at 9:46
  • \$\begingroup\$ @Overly It's not the creation in itself, but the interval in which it's perfomed \$\endgroup\$
    – Vogel612
    Apr 18, 2014 at 10:09
  • 1
    \$\begingroup\$ Sounds unlikely. Creating objects only matters if you do it millions of times per second. \$\endgroup\$ Apr 20, 2014 at 19:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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