0
\$\begingroup\$

I am currently creating a small game using C#, and I am having some trouble working out how to handle user input. I can move my model around the map normally, however I am looking to implement a system where the user can input a number of different commands, and then when they hit enter, the string of commands will be executed. I have tried to implement a queue system to take the user input, and pass them to the model, but I haven't been able to get it to work. My input handler class:

class InputHandler
{

    Queue<int> userCommands;

    /*
     *  FORWARD     = 1
     *  REVERSE     = 2
     *  RIGHT TURN  = 3
     *  LEFT TURN   = 4
     */

    public InputHandler()
    {
        //userCommands = new Queue<Keys>();
        userCommands = new Queue<int>();

    }

    public void EmptyQueue()
    {
        userCommands.Clear();
    }

    public Queue<int> GetUserCommands()
    {
        KeyboardState ks = Keyboard.GetState();
        int move;

        while(ks.IsKeyUp(Keys.Enter))
        {
            if(ks.IsKeyDown(Keys.W))
            {
                move = 1;
                userCommands.Enqueue(move);
            }
            if(ks.IsKeyDown(Keys.S))
            {
                move = 2;
                userCommands.Enqueue(move);
            }
            if(ks.IsKeyDown(Keys.D))
            {
                move = 3;
                userCommands.Enqueue(move);
            }
            if(ks.IsKeyDown(Keys.A))
            {
                move = 4;
                userCommands.Enqueue(move);
            }

        }
        return userCommands;

    }
}

The Update method for the model:

   public void Update(GameTime gametime, BoundingSphere bounding, int move)
    {
        KeyboardState ks = Keyboard.GetState();

        oldModelYaw = modelYaw;
        oldModelPosition = modelPosition;


        if (!isMoving)
        {
            if (move == 1)
            {
                isMoving = true;
                moveType = FORWARD;
            }
            if (move == 2)
            {
                isMoving = true;
                moveType = REVERSE;
            }
            if (move == 3)
            {
                isMoving = true;
                moveType = RIGHT_TURN;
            }
            if (move == 4)
            {
                isMoving = true;
                moveType = LEFT_TURN;
            }

        }

        if (isMoving)
        {
            switch (moveType)
            {
                case FORWARD:
                    if (count <= 100)
                    {
                        modelPosition += modelRotation * velocity;
                        count++;
                    }
                    else
                    {
                        count = 0;
                        isMoving = false;
                    }
                    break;

                case REVERSE:
                    if (count <= 100)
                    {
                        modelPosition -= modelRotation * velocity;
                        count++;
                    }
                    else
                    {
                        count = 0;
                        isMoving = false;
                    }
                    break;

                case RIGHT_TURN:
                    if (count <= 180)
                    {
                        modelYaw -= MathHelper.ToRadians(0.5f);

                        modelRotation = Vector3.Transform(modelDirection, Matrix.CreateFromYawPitchRoll(modelYaw, 0.0f, 0.0f));

                        count++;
                    }
                    else
                    {
                        count = 0;
                        isMoving = false;
                    }
                    break;

                case LEFT_TURN:
                    if (count <= 180)
                    {
                        modelYaw += MathHelper.ToRadians(0.5f);
                        modelRotation = Vector3.Transform(modelDirection, Matrix.CreateFromYawPitchRoll(modelYaw, 0.0f, 0.0f));

                        count++;
                    }
                    else
                    {
                        count = 0;
                        isMoving = false;
                    }
                    break;
            }

            modelPosition.Y = GetHeight();
            translation = Matrix.CreateTranslation(modelPosition);
            rotation = Matrix.CreateRotationY(modelYaw) * GetModelNormal();
            bounding.Center = modelPosition;

            if (scenery.TestCollision(bounding))
            {
                modelPosition = oldModelPosition;
                modelYaw = oldModelYaw;

                modelPosition.Y = GetHeight();

                translation = Matrix.CreateTranslation(modelPosition);
                rotation = Matrix.CreateRotationY(modelYaw) * GetModelNormal();

                bounding.Center = modelPosition;

            }
        }
    }

The Update method in the game class

protected override void Update(GameTime gameTime)
    {
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
            Exit();

        if(commandQueue.Count <= 0)
        {
            commandQueue = input.GetUserCommands();
        }

        else
        {

            model.Update(gameTime, rock.GetBoundingSphere, userCommands.Dequeue());


            camera.Update(gameTime, m_model.GetPosition, m_model.GetDirection);

            base.Update(gameTime);
        }
    }

If anyone could give me some help with this, or point me in the right direction, I would greatly appreciate it.

\$\endgroup\$
1
  • \$\begingroup\$ "I haven't been able to get it to work." What part exactly are you stuck on, or how is the current behaviour differing from what you want? \$\endgroup\$
    – DMGregory
    Commented May 23, 2019 at 11:37

2 Answers 2

1
\$\begingroup\$
  1. The general answer to your question is: use a state machine for character movement to get rid of those deep nested if and switches.
  2. If you need to perform special actions on input combinations like in fighting games you need a system that records your inputs and each stored input has a timestamp. In order to trigger a combo state! Two conditions must be true: the order of input and datetime.now - firstTimestamp must be lower than whatever timeframe is allowed to trigger the combo.
  3. Flush your expired inputs from the queue.
  4. Test your command queue by using high expiration times and drawing the commands to screen, also draw which move6state is current and which was last.

A great explanation of state machines for game so can be found in the book "programming game so by example "

\$\endgroup\$
1
  • \$\begingroup\$ That's a good explanation of what is needed but I'm going to have to stop you at datetime.now -- it's too granular and returns the same result if called in too tight a loop. Using a Stopwatch and getting elapsed Ticks is much more accurate. \$\endgroup\$
    – Brett
    Commented Mar 24, 2022 at 5:40
0
\$\begingroup\$

There are many approaches for your situation. Below is one possible way (using GetPressedKeys method):

Initialise: string stringCommand = string.Empty;

In your Update() method:

var keyboardState = Keyboard.GetState();
var keyString = keyboardState.GetPressedKeys();

if(keyString .Length > 0)
{
    var keyValue = keyString[0].ToString();
    stringCommand += keyValue;
}

Then you compare this string with whatever you want to achieve your desire result.

I think you can create a command line windows to show what users are typing after they press Enter (for example). Another method is that you create a textbox (or a GUI if needed) then read the input of your textbox then do your comparison things.

\$\endgroup\$

You must log in to answer this question.

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