我正在尝试清理我从一个从未完成的视频教程系列中学习的 Action 代码。我的意图是让角色在任何给定时间只能在 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>::push_back [with _Ty=SDL_Event, _Alloc=std::allocator]”与参数列表 Sandbox C:\file_path\KeyboardController.h 匹配31
严重性代码描述项目文件行抑制状态 错误(事件)E0415 不存在从“SDL_Keycode”转换为“SDL_Event”的合适的构造函数沙盒 C:\file_path\KeyboardController.h 34
最佳答案
您基本上应该通过分离关键事件和玩家移动之间的逻辑来清理您的代码。所以您的 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;
}
}
}
注意:我没有测试此代码,因为我没有您游戏中的代码和结构。因此,您可能需要在这里和那里编辑一段以使其适合您。
关于C++ 如何处理所有可能的玩家移动输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52267019/