Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ How do I Handle all possible Player Movement inputs?

Tags:

c++

I am trying to clean up movement code I followed from a video tutorial series that was never finished. My intent is for the character to only ever be able to move on X or Y at any given time (so no diagonal). The character has direction facing to keep in mind.

My issue is the player can still press any key they want, or accidently press two keys at the same time.

Ex. if you move Up and make a right turn, accidentally press Right before letting go of Up.

Or if you press Up, press and let go Right to make a slight movement right while continuing to press Up, the player should continue to move up after letting go of Right without having to re-press Up. etc.

Just to make sure all possible input cases are handled intuitively.

EDIT: This is the code so far and I'm getting weird errors I don't know what's wrong

#pragma once
#include "../game.h"
#include "ECS.h"
#include "Components.h"
#include <list>

using namespace std;




class KeyboardController : public Component
{
public:
    TransformComponent *transform;
    SpriteComponent *sprite;

    std::list<SDL_Event> keyDownList;
    SDL_Event lastDirection;

    void updateKeyState()
    {
        if (Game::event.type == SDLK_ESCAPE) {
            Game::isRunning = false;
        }
        else if (Game::event.type == SDL_KEYDOWN) {
            keyDownList.push_back(Game::event.key.keysym.sym);
        }
        else if (Game::event.type == SDL_KEYUP) {
            keyDownList.remove(Game::event.key.keysym.sym);
        }
    }

    void init() override
    {
        transform = &entity->getComponent<TransformComponent>();
        sprite = &entity->getComponent<SpriteComponent>();






    }




    void update() override
    {
        void updateKeyState();
        void updateMovement();

    }



};

Severity Code Description Project File Line Suppression State Error (active) E0304 no instance of overloaded function "std::list<_Ty, _Alloc>::push_back [with _Ty=SDL_Event, _Alloc=std::allocator]" matches the argument list Sandbox C:\file_path\KeyboardController.h 31

Severity Code Description Project File Line Suppression State Error (active) E0415 no suitable constructor exists to convert from "SDL_Keycode" to "SDL_Event" Sandbox C:\file_path\KeyboardController.h 34

like image 619
coffeemancer Avatar asked Jan 29 '26 16:01

coffeemancer


1 Answers

You should basically clean up your code by separating the logic between key events and player movement. So your update() method could look like this:

void update() override
{
    updateKeyState();
    updateMovement();
}

Since you want the player to move only vertically or horizontally (never diagonally), you have to store the key press order in a data structure that can be easily accessed. I think you could use a doubly-linked list:

std::list<SDL_Event> keyDownList;

and we should also store the last key pressed in order to restore the idle animation of the player:

SDL_Event lastDirection;

The updateKeyState() method should add or remove the key to/from the linked list. We should also check if the player wants to leave the game by pressing ESC:

void updateKeyState() {
    if (Game::event.type == SDLK_ESCAPE) {
        Game::isRunning = false;
    } else if (Game::event.type == SDL_KEYDOWN) {
        keyDownList.push_back(Game::event.key.keysym.sym);
    } else if (Game::event.type == SDL_KEYUP) {
        keyDownList.remove(Game::event.key.keysym.sym);
    }
}

The updatePlayerMovement() method is where the magic happens. We should basically check which key was pressed first and update the player position accordingly. We also save the down key in the lastDirection field in order to use it when no key is pressed.

void updateMovement() {
    // if any key is down
    if (keyDownList.size() > 0) {
        const SDL_Event downKey = keyDownList.front();
        switch (downKey) {
            case SDLK_w:
                transform->velocity.y = -1;
                transform->velocity.x = 0;
                sprite->Play("BackWalk");
                lastDirection = downKey;
                break;
            case SDLK_a:
                transform->velocity.x = -1;
                transform->velocity.y = 0;
                sprite->Play("SideWalk");
                sprite->spriteFlip = SDL_FLIP_HORIZONTAL;
                lastDirection = downKey;
                break;
            case SDLK_s:
                transform->velocity.y = 1;
                transform->velocity.x = 0;
                sprite->Play("FrontWalk");
                lastDirection = downKey;
                break;
            case SDLK_d:
                transform->velocity.x = 1;
                transform->velocity.y = 0;
                sprite->Play("SideWalk");
                sprite->spriteFlip = SDL_FLIP_NONE;
                lastDirection = downKey;
                break;
        }
    } else {
        // no key is down, handle idle situations
        transform->velocity.x= 0;
        transform->velocity.y = 0;

        switch (lastDirection) {
            case SDLK_w:
                sprite->Play("BackIdle");
                break;
            case SDLK_a:
                sprite->Play("SideIdle");
                break;
            case SDLK_s:
                sprite->Play("FrontIdle");
                break;
            case SDLK_d:
                sprite->Play("SideIdle");
                break;
        }
    }
}

Note: I haven't tested this code because I don't have the code and structures from your game. So you may have to edit a piece here and there to make it work for you.

like image 140
HugoTeixeira Avatar answered Feb 01 '26 06:02

HugoTeixeira