C++ 如何处理所有可能的玩家移动输入?

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

本文关键字:有可能 玩家 移动 输入 何处理 处理 C++      更新时间:2023-10-16

我正在尝试清理我从从未完成的视频教程系列中遵循的运动代码。我的目的是让角色在任何给定时间只能在 X 或 Y 上移动(所以没有对角线(。角色有方向要记住。

我的问题是玩家仍然可以按他们想要的任何键,或者不小心同时按下两个键。

例如,如果您向上移动并右转,请在放开向上之前不小心按右键。

或者,如果按向上,按下并向右松开以在继续按向上的同时向右移动轻微,则玩家在向右松开后应继续向上移动,而不必重新按向上等。

只是为了确保直观地处理所有可能的输入情况。

编辑:这是到目前为止的代码,我遇到了奇怪的错误,我不知道出了什么问题

#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();
}

};

严重性代码说明项目文件行抑制状态 错误(活动(E0304 没有重载函数"std::list<_Ty、_Alloc>::p ush_back [with _Ty=SDL_Event, _Alloc=std::allocator]"的实例与参数列表 Sandbox C:\file_path\KeyboardController.h 31

严重性代码说明项目文件行抑制状态 错误(活动(E0415 不存在合适的构造函数来从"SDL_Keycode"转换为"SDL_Event"沙箱 C:\file_path\键盘控制器.h 34

基本上,您应该通过分离关键事件和玩家移动之间的逻辑来清理代码。因此,您的update()方法可能如下所示:

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

由于您希望播放器仅垂直或水平移动(从不对角线(,因此必须将按键顺序存储在易于访问的数据结构中。我认为您可以使用双向链表:

std::list<SDL_Event> keyDownList;

我们还应该存储最后按下的键,以恢复播放器的空闲动画:

SDL_Event lastDirection;

updateKeyState()方法应在链表中添加或删除键。我们还应该通过按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);
}
}

updatePlayerMovement()方法是魔术发生的地方。我们基本上应该检查先按下了哪个键,并相应地更新玩家位置。我们还将向下键保存在lastDirection字段中,以便在不按键时使用它。

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;
}
}
}

注意:我还没有测试过这段代码,因为我没有你们游戏中的代码和结构。因此,您可能需要在这里和那里编辑一个片段才能使其为您工作。