我正在尝试清理从未完成的视频教程系列中遵循的运动代码。我的目的是使角色在任何给定时间只能在X或Y上移动(因此,没有对角线)。角色要牢记面对的方向。
我的问题是,玩家仍然可以按任意键,或者不小心同时按两个键。
例如如果您向上移动并向右转,则在松开向上键之前不小心按向右键。
或者,如果您按Up键,则在继续按Up的同时按放开Right键即可向右微动,放开Right键后,玩家应继续向上移动,而不必重新按Up键。等
只需确保直观地处理所有可能的输入用例即可。
编辑:到目前为止,这是代码,我遇到奇怪的错误,我不知道怎么了
#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> :: push_back [with _Ty = SDL_Event,_Alloc = std :: allocator]”的实例与参数列表沙箱C:\ file_path \ KeyboardController.h匹配31
严重性代码描述项目文件行抑制状态 错误(活动)E0415不存在合适的构造函数,无法从“ SDL_Keycode”转换为“ SDL_Event”沙箱C:\ file_path \ KeyboardController.h 34
答案 0 :(得分:2)
基本上,您应该通过将按键事件和玩家移动之间的逻辑分开来清理代码。因此,您的update()
方法可能如下所示:
void update() override
{
updateKeyState();
updateMovement();
}
由于您只希望播放器垂直或水平移动(绝不对角移动),因此必须将按键顺序存储在易于访问的数据结构中。我认为您可以使用doubly-linked list:
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;
}
}
}
注意:我没有测试此代码,因为我没有您游戏中的代码和结构。因此,您可能需要在此处和此处进行编辑,以使其适合您。