我正在尝试使用glfwSetKeyCallback函数创建基本的相机移动。问题是它不能同时处理多个键的输入,例如W和A应该沿对角线左上方向移动。相反,它的行为就像只知道最后输入的密钥。所以,假设我按A向左移动,向左移动,然后按W向对角线左上方移动,而不是'忘记'关于A按下并向上移动。
float cameraSpeed = 0.02f;
if (key == GLFW_KEY_ESCAPE && (action == GLFW_PRESS || action == GLFW_REPEAT))
glfwSetWindowShouldClose(window, GLFW_TRUE);
if (key == GLFW_KEY_W && (action == GLFW_PRESS || action == GLFW_REPEAT))
Game::GetInstance()->cameraY += cameraSpeed;
if (key == GLFW_KEY_A && (action == GLFW_PRESS || action == GLFW_REPEAT))
Game::GetInstance()->cameraX -= cameraSpeed;
if (key == GLFW_KEY_S && (action == GLFW_PRESS || action == GLFW_REPEAT))
Game::GetInstance()->cameraY -= cameraSpeed;
if (key == GLFW_KEY_D && (action == GLFW_PRESS || action == GLFW_REPEAT))
Game::GetInstance()->cameraX += cameraSpeed;
我想到的一个解决方案就是创建我自己的键盘输入布尔选项卡,并使用GLFW函数来设置它们,如:
if (key == GLFW_KEY_A && action == GLFW_PRESS)
// set 'A' to true;
if (key == GLFW_KEY_A && action == GLFW_RELEASE)
// set 'A' to false;
然后在完全独立的函数/类/中执行我想要的操作。虽然它看起来并不干净。什么是解决问题的好方法?
答案 0 :(得分:4)
我遇到了同样的问题,并决定使用回调来设置一个值为关键状态的数组。 GLFW_REPEAT
仅发送给最后一个按下的键。我的回调直接委托给Input
类,但这不相关:它们传递所有参数。
void key_callback(GLFWwindow *win, int key, int scancode, int action, int mods){
Input *input = (Input*)glfwGetWindowUserPointer(win);
input->keys(win, key, scancode, action, mods);
}
在输入中定义的按键阵列:
bool pressed[KEYS]; // KEYS = 349 (last GLFW macro, GLFW_KEY_MENU = 348)
实际的处理方法,我也处理需要窗口指针的特殊键:
Input::keys(GLFWwindow *win, int key, int scancode, int action, int mods){
if(key == GLFW_UNKNOWN) return; // Don't accept unknown keys
if(action == GLFW_PRESS)
pressed[key] = true;
else if(action == GLFW_RELEASE)
pressed[key] = false;
switch(key){
case GLFW_KEY_EXCAPE:
if(action == GLFW_PRESS)
glfwSetWindowShouldClose(win, true);
}
}
然后我使用Input::handle(void)
进行每次渲染操作后处理主循环内的每个键,像Input in(); in.handle()
一样使用:
void Input::handle(void){ // Things to do every frame
for(int i = 0; i < KEYS; i++){
if(!pressed[i]) continue; // Skip if not pressed
switch(i){
case GLFW_KEY_SPACE:
cam->ascend(1.0); // Ascend with camera
}
}
}
我计划包含一个时间常数来处理不同帧速率的问题,但这是它的要点。
结果:即使按下多个键,相机也会在各个方向上平稳移动。
答案 1 :(得分:0)
我实现了我的键盘句柄类版本:
enum EVENT{
PRESS = 1,
RELEASE = 2,
REPEAT = 4,
NONE = 8
};
static std::map<int, EVENT> event_map = {{GLFW_PRESS, PRESS}, {GLFW_RELEASE, RELEASE}};
class Input{
public:
Input() {}
Input(GLFWwindow *w) : window(w) {}
void set_window(GLFWwindow *w) {window = w;};
void add_key_input(int key, std::function<void(int, float)> f, int events){
// if (key == -1) {std::cout << "undefinet key : " << key << '\n'; return;}
keys[key] = KEY(f, event_map[events]);
}
void process(float delta){
for (auto& [key, info] : keys) {
int e = glfwGetKey(window, key);
std::cout << key << " " << e << " " << info.action << " " << info.event << " ";
if (e == GLFW_RELEASE && info.action == NONE) info.action = NONE;
else if (e == GLFW_RELEASE && (info.action == PRESS || info.action == REPEAT)) info.action = RELEASE;
else if (e == GLFW_PRESS && (info.action == PRESS || info.action == REPEAT)) info.action = REPEAT;
else if (e == GLFW_PRESS && (info.action == NONE || info.action == RELEASE)) info.action = PRESS;
std::cout << info.action << "\n";
if (info.event & info.action) {
info.callback(key, delta);
}
}
}
private:
struct KEY{
KEY():action(RELEASE) {}
KEY(std::function<void(int, float)> f, EVENT e): callback(f), action(RELEASE) ,event(e) {}
std::function<void(int, float)> callback;
EVENT action;
EVENT event;
};
GLFWwindow *window;
std::map<int, KEY> keys;
};
使用它。初始化:
key_input.set_window(window);
key_input.add_key_input(GLFW_KEY_ESCAPE, [this](int key, float delta){glfwSetWindowShouldClose(this->window, true);}, PRESS);
在主循环中:
glfwPollEvents();
key_input.process(delta_time); // in my case delta time is time in secs since last frame
您可以将 std::function