1 Keypresses
Tim Young edited this page 2017-10-03 02:15:09 +02:00

Keypresses

Handling keypresses is always an interesting thing. The SpriteController has some code to do this for you, but you can also roll your own.

C# has a strange issue. If you have a key pressed and then the form loses focus, the form will not register a “key up” event for that key. This means it is entirely possible for you to release a key and for C# to think that the key is still pressed.

The main code for handling keypresses is SpriteController.IsKeyPressed(Key).

Below is some code. We define a SpriteController, and give it a “DoTick” function. That function is called many times a second by the SpriteController. To keep things sane, we exit out of the function if less than 100 milliseconds has passed. (We do this by storing the time we last did something, and then subtracting that from the current time and comparing the milliseconds.)

Finally, we check for a few particular keypresses and act upon them.

SpriteController MySpriteController;
DateTime LastMovement = DateTime.Now; //Used to give a slight delay in checking for keypress.

public partial class ShootingField : Form
{
    MainDrawingArea.BackgroundImage = Properties.Resources.Background;
    MainDrawingArea.BackgroundImageLayout = ImageLayout.Stretch;
    MySpriteController = new SpriteController(MainDrawingArea);
    MySpriteController.DoTick += CheckForKeyPress;
}

private void CheckForKeyPress(object sender, EventArgs e)
{
    bool left = false;
    bool right = false;
    bool space = false;
    bool didsomething = false;
    TimeSpan duration = DateTime.Now - LastMovement;
    if (duration.TotalMilliseconds < 100)
        return;
    LastMovement = DateTime.Now;
    if (MySpriteController.IsKeyPressed(Keys.A) || MySpriteController.IsKeyPressed(Keys.Left))
    {
        left = true;
    }
    if (MySpriteController.IsKeyPressed(Keys.D)||MySpriteController.IsKeyPressed(Keys.Right))
    {
        right = true;
    }
    if (left && right) return; //do nothing if we conflict
    if (left)
    {               
        if (LastDirection != MyDir.left)
        {
            Spaceship.SetSpriteDirectionDegrees(180);
            //We want to only change animation once.  Every time we change
            //the animation, it starts at the first frame again.
            Spaceship.ChangeAnimation(0);
            LastDirection = MyDir.left;
        }
        didsomething = true;
        Spaceship.MovementSpeed = 15;
        Spaceship.AutomaticallyMoves = true;
    }
    if (right)
    {                
        if (LastDirection != MyDir.right)
        {
            Spaceship.SetSpriteDirectionDegrees(0);
            Spaceship.ChangeAnimation(0);
            LastDirection = MyDir.right;
        }
        didsomething = true;
        Spaceship.AutomaticallyMoves = true;
        Spaceship.MovementSpeed = 15;
    }
    if(!didsomething)
    {
        LastDirection = MyDir.stopped;
        //No keys pressed.  Stop moving
        Spaceship.MovementSpeed = 0;
    }
}

One of the things that the above code does, which is probably not immediately apparent, is that it does not repeatedly tell something to do what it is already doing. It tracks the “LastDirection”, which is the direction the spaceship was traveling previously. If we are already going the same direction that our key-presses are telling us we should be going, the code leaves the sprite alone. The sprite has a direction and speed, and will continue to go that direction at that speed until the key is released, or something stops it. The ShootingDemo, from which the above code was pulled, has the SpaceShip set to not be able to go outside the bounds of the PictureBox. So it will stop at the edge.

The reason we do not tell the SpaceShip to move every time is because it takes a little bit of time for it to get started. There is just a little bit of housecleaning that needs to be done before it starts off on its way. If you tell it to move again, it starts the housecleaning again. It will barely move if you tell it to move the same direction every 10th of a second. And the animation stuff looks terrible if you tell it to restart the movement every 10th of a second.

The right way to do it is to tell it which way to go, and only change the direction when something acts on the sprite to change the direction.