0
\$\begingroup\$

I just decided to give coding a go, and I am using C# in Visual Studio 2017. After some online tutorials, I tried to make a Windows Form App with simple movement. The only problem I have is that if you hold down a key for around a second, the player suddenly moves super quickly in that direction.

private void inGameKeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.A)
        {
            MoveSpeedX -= 3;
        }

        if (e.KeyCode == Keys.D)
        {
            MoveSpeedX += 3;               
        }

        if (e.KeyCode == Keys.W)
        {
            MoveSpeedY -= 3;
        }

        if (e.KeyCode == Keys.S)
        {
            MoveSpeedY += 3;
        }
    }

The movement code. How can I fix this issue? Any help would be appreciated! :D

P.S. If you could also show me a way for more efficient movement, that would be greatly appreciated as well! :D

\$\endgroup\$

2 Answers 2

0
\$\begingroup\$

Note: this is significant overkill for your current Windows Form Application implementation of movement, but if you're going to start getting into game development this is often how movement is managed. For example, I believe the first Unity tutorial covers this with a simple ball-moving game.

Note 2: this is a highly OOP implementation. Don't even get started between OOP vs. procedural (answer by S. Tarık Çetin), because all I'm trying to do is present the current game development convention of movement implementations. In the original poster's case, yes, procedural is the easiest, fastest, and most light-weight implementation. In large projects with a framework that has these classes already available, OOP is in my opinion easier and faster.

Note 3: this is by no means a perfect implementation, probably not even that good. It was created quickly to illustrate Vector movement.


I'm a bit late to reply, but I would consider starting to work with Vector objects. There is no such object in basic .NET framework to my knowledge, but engines like Unity/Unreal have frameworks that utilize similar implementations.

The reason I suggest this is because assigning movement is often done by applying a Vector value to a position in 2-space, x and y components, or 3-space x, y, and z components. You're just using 2D movement so I'll stick with that.

Here is a very basic implementation of a Vector class you could use (but any framework you'd use for real game development will already have one for your to use):

public class Vector2 //the number 2 indicates this only 2-space components
{
    public int X { get; private set; }
    public int Y { get; private set; }
    //this Clamp only covers min/max values being the same magnitude in each dimension
    private Vector2 Clamp;

    public Vector2(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }

    //I've put the clamp in the Vector, but depending on your needs, assigning min/max to the Player may be better
    public void Clamp(int magnitude)
    {
        this.Clamp = new Vector2(Math.Abs(magnitude), Math.Abs(magnitude));
    }
    public void Clamp(Vector2 vector)
    {
        this.Clamp = new Vector2(Math.Abs(vector.X), Math.Abs(vector.Y));
    }

    public void Add(int x, int y)
    {
        this.X += (Clamp != null && Clamp.X > Math.Abs(x)) ? x : Clamp.X;
        this.Y += (Clamp != null && Clamp.Y > Math.Abs(y)) ? y : Clamp.Y;
    }
    public void Add(Vector2 vector)
    {
        Add(vector.X, vector.Y);
    }
}

Again, please note that this is overkill for your basic application, this is just to familiarize you with vector movements. Here's an implementation of a player object:

public class Player
{
    public Vector2 Position;
    public Vector2 Velocity;

    public Player()
    {
        this.Position = new Vector2(0, 0);
        this.Velocity = new Vector2(0, 0);
    }
    public Player(Vector2 startPosition, Vector2 startVelocity)
    {
        this.Position = startPosition;
        this.Velocity = startVelocity;
    }

    public void Move()
    {
        this.Position.Add(this.Velocity);
    }
}

This implementation of Player is missing the 'size' of the object, so you'd have to adjust for that in other ways for proper collision/bounds checking.

Then your movement could be handled like this:

private void InGameKeyDown(object sender, KeyEventArgs e)
{
    var movement = new Vector(0, 0);

    if (e.KeyCode == Keys.A)
    {
        movement.Add(-1, 0);
    }
    if (e.KeyCode == Keys.D)
    {
        movement.Add(1, 0);
    }
    if (e.KeyCode == Keys.W)
    {
        movement.Add(0, -1);
    }
    if (e.KeyCode == Keys.S)
    {
        movement.Add(0, 1);
    }

    //this is assuming you have the player1 Player object globally assigned, instead of your MoveSpeedX/MoveSpeedY objects
    player1.Velocity.Add(movement);
}

Whatever method you're using to move the object (where you're currently applying your MoveSpeedX and MoveSpeedY) will then only need to do player1.Move(), since the Player object updates its own position with its own velocity.

This is essentially how movement is being handled (for the value of Player.Position, assume each step # is 1 frame of the game, or tick, or update period for animation/rendering, progressing):

  1. Game start:
    • Player.Velocity = (0,0)
    • Player.Position = (0,0)
  2. Press 'S' Key:
    • Player.Velocity = (0,1)
    • Player.Position = (0,1)
  3. Press 'S' Key:
    • Player.Velocity = (0,2)
    • Player.Position = (0,3)
  4. Game time progresses:
    • Player.Velocity = (0,2)
    • Player.Position = (0,5)
  5. Press 'W' Key:
    • Player.Velocity = (0,1)
    • Player.Position = (0,6)
  6. Press 'D' Key:
    • Player.Velocity = (1,1)
    • Player.Position = (1,7)
  7. Press 'W' Key:
    • Player.Velocity = (1,0)
    • Player.Position = (2,7)
  8. Game time progresses:
    • Player.Velocity = (1,0)
    • Player.Position = (3,7)
  9. Game time progresses:
    • Player.Velocity = (1,0)
    • Player.Position = (4,7)
  10. Press 'W' Key:
    • Player.Velocity = (1,-1)
    • Player.Position = (5,6)
  11. Press 'W' Key:
    • Player.Velocity = (1,-2)
    • Player.Position = (6,4)
  12. Game time progresses:
    • Player.Velocity = (1,-2)
    • Player.Position = (7,2)
  13. Game time progresses:
    • Player.Velocity = (1,-2)
    • Player.Position = (8,0)

(It should be noted, as well, that Windows Forms treats the origin, (0,0), as the top left corner of the window, which is why 'S' increases the y-value and 'W' decreases it.)

As can be seen in the values I've shown above, this implementation assumes that your object has persistent velocity; like a car, it's moving until decelerated to 0 velocity. If you want it to only move when a key is pressed, change the player1.Velocity.Add(movement) to player1.Position.Add(movement).


If you are interested in game development, definitely check out the Unity tutorials and Learn section. It will help get you started, and provide a much better description than I could, as well as walking you through the steps of creating games.

The best part: it's free! No, I'm not affiliated with Unity in any way (other than using their engine occasionally).

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

Try this:

private void inGameKeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.A)
    {
        MoveSpeedX = -3;
    }

    if (e.KeyCode == Keys.D)
    {
        MoveSpeedX = 3;               
    }

    if (e.KeyCode == Keys.W)
    {
        MoveSpeedY = -3;
    }

    if (e.KeyCode == Keys.S)
    {
        MoveSpeedY = 3;
    }
}

Explanation

Speed = Distance traveled for the time period / Time passed

When you increase speed, you are increasing the amount of distance you travel for a given period of time.

I imagine your inGameKeyDown function gets called constantly as you hold down the key. This causes the speed to get incremented over and over again, instead of being clamped between -3 and +3.

There is a little issue: if you press D while pressing down A, your object will travel in the positive X direction instead of staying put. You can fix it like this:

private void inGameKeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.A)
    {
        MoveSpeedX -= 3;
        MoveSpeedX = Math.Clamp(MoveSpeedX, -3, +3);
    }

    if (e.KeyCode == Keys.D)
    {
        MoveSpeedX += 3;  
        MoveSpeedX = Math.Clamp(MoveSpeedX, -3, +3);             
    }

    if (e.KeyCode == Keys.W)
    {
        MoveSpeedY -= 3;
        MoveSpeedY = Math.Clamp(MoveSpeedY, -3, +3);
    }

    if (e.KeyCode == Keys.S)
    {
        MoveSpeedY += 3;
        MoveSpeedY = Math.Clamp(MoveSpeedY, -3, +3);
    }
}

There is another problem: The object keeps moving when we release all keys. You can't solve this inside inGameKeyDown method because it will not get called if no keys are down.

Inside your game loop, you can reset the speed to 0 every frame before processing speed increments, so when no keys are pressed the speed will be 0 all the time.

Please note that both of these code pieces are not tested and written quickly. There are much better ways to handle this situation.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the help! The bit about not being able to stop is fine, i already have a piece of code that handles that. \$\endgroup\$ Jun 30, 2017 at 20:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .