Kel*_*lan 1 java opengl user-input lwjgl glfw
因此,我最近刚从LWJGL 2升级到3,并且在获取键盘和鼠标输入时遇到了一些困难。顺便说一下,我正在使用它进行相机的移动和旋转。
我的问题是,如果我使用GLFW回调,则移动似乎非常不稳定且缓慢。这不是一个稳定的速度,只是感觉不对。此外,当我按下一个键(例如w)向前移动时,从GLFW_PRESS到的转换之间大约有半秒的延迟。GLFW_REPEAT这会导致在按下键时相机在前半秒内不会移动。
顺便说一下,我有一个InputHandler类,该类具有用于keyDown,keyPressed,keyReleased等的方法。在一个invoke方法中,我没有所有的键检查。invoke方法将键事件添加到存储键的列表中,以及事件状态枚举,该枚举可以是DOWN,TAPPED,RELEASED,NONE之一。上课很大程度上是基于对这个问题的回答
我花了过去2个小时的时间来寻找解决方案,但没有发现太多。我确实找到了一些使用回调方法的替代方法,例如:
if (glfwGetKey(window, key) == GLFW_PRESS)
Run Code Online (Sandbox Code Playgroud)
和
if (glfwGetKey(windowm key) == GLFW_RELEASE)
Run Code Online (Sandbox Code Playgroud)
但是我找不到一种方法来检测单个按键,即GLFW_REPEAT状态,因为该glfwGetKey方法只能检测GLFW_PRESS和GLFW_RELEASE。
如果有人可以告诉我一种方法来检测单个按键敲击glfwGetKey,或者使GLFW回调更轻松,更流畅,我将不胜感激。
谢谢 :)
所以我解决了这个问题,这要归功于布雷特·黑尔(Brett Hale)的建议,即假设钥匙一直按下直到 GLFW_RELEASE事件触发。这是我的工作实现:
public final class InputHandler
{
private static long window;
private static final int KEYBOARD_SIZE = 512;
private static final int MOUSE_SIZE = 16;
private static int[] keyStates = new int[KEYBOARD_SIZE];
private static boolean[] activeKeys = new boolean[KEYBOARD_SIZE];
private static int[] mouseButtonStates = new int[MOUSE_SIZE];
private static boolean[] activeMouseButtons = new boolean[MOUSE_SIZE];
private static long lastMouseNS = 0;
private static long mouseDoubleClickPeriodNS = 1000000000 / 5; //5th of a second for double click.
private static int NO_STATE = -1;
protected static GLFWKeyCallback keyboard = new GLFWKeyCallback()
{
@Override
public void invoke(long window, int key, int scancode, int action, int mods)
{
activeKeys[key] = action != GLFW_RELEASE;
keyStates[key] = action;
}
};
protected static GLFWMouseButtonCallback mouse = new GLFWMouseButtonCallback()
{
@Override
public void invoke(long window, int button, int action, int mods)
{
activeMouseButtons[button] = action != GLFW_RELEASE;
mouseButtonStates[button] = action;
}
};
protected static void init(long window)
{
InputHandler.window = window;
resetKeyboard();
resetMouse();
}
protected static void update()
{
resetKeyboard();
resetMouse();
glfwPollEvents();
Engine.getInput();
}
private static void resetKeyboard()
{
for (int i = 0; i < keyStates.length; i++)
{
keyStates[i] = NO_STATE;
}
}
private static void resetMouse()
{
for (int i = 0; i < mouseButtonStates.length; i++)
{
mouseButtonStates[i] = NO_STATE;
}
long now = System.nanoTime();
if (now - lastMouseNS > mouseDoubleClickPeriodNS)
lastMouseNS = 0;
}
public static boolean keyDown(int key)
{
return activeKeys[key];
}
public static boolean keyPressed(int key)
{
return keyStates[key] == GLFW_PRESS;
}
public static boolean keyReleased(int key)
{
return keyStates[key] == GLFW_RELEASE;
}
public static boolean mouseButtonDown(int button)
{
return activeMouseButtons[button];
}
public static boolean mouseButtonPressed(int button)
{
return mouseButtonStates[button] == GLFW_RELEASE;
}
public static boolean mouseButtonReleased(int button)
{
boolean flag = mouseButtonStates[button] == GLFW_RELEASE;
if (flag)
lastMouseNS = System.nanoTime();
return flag;
}
public static boolean mouseButtonDoubleClicked(int button)
{
long last = lastMouseNS;
boolean flag = mouseButtonReleased(button);
long now = System.nanoTime();
if (flag && now - last < mouseDoubleClickPeriodNS)
{
lastMouseNS = 0;
return true;
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
如果需要,请随意使用此代码。不过,只有一些注意事项:应该在每一帧都调用update方法。另外,如果您glfwPollEvents()认为还有其他地方,那么您需要保持重置键盘/鼠标的顺序,然后进行轮询,然后进行getinput()。
编辑:我的Engine.getInput()方法就是告诉场景图中需要输入的节点(即播放器)查询该输入。
小智 5
虽然 Kelan 的回答很完美,但我想我会分享我的解决方案,因为我在玩游戏时遇到了同样的问题。我实现了自己的键盘类并包含以下方法
public static boolean isKeyPressed(int key)
{
return (GLFW.glfwGetKey(Game.window.handle, key) == KEY_PRESS);
}
public static boolean isKeyReleased(int key)
{
return (GLFW.glfwGetKey(Game.window.handle, key) == KEY_RELEASE);
}
Run Code Online (Sandbox Code Playgroud)
由于 GLFW 保存每个键的最后一个事件,您只需要查看最后一个事件是 PRESS 还是 RELEASE。GLFW 不会使用此方法报告 REPEAT 事件,但您可以假设它一直在重复,直到触发 RELEASE 事件。