LWJGL 3 GLFW键盘和鼠标输入很慢,并且在GLFW_PRESS和GLFW_REPEAT之间有延迟

问题描述 投票:1回答:3

所以我最近刚从LWJGL 2迁移到3,并且在获取键盘和鼠标输入方面有些困难。顺便说一下,我正在使用它进行相机的移动和旋转。

我的问题是,如果我使用GLFW回调,则移动似乎非常不稳定且缓慢。这不是一个稳定的速度,只是感觉不对。此外,当我按下一个键(例如w向前移动)时,从GLFW_PRESSGLFW_REPEAT的过渡之间大约有半秒的延迟,这导致当键按下时相机在前半秒内不会移动被按下。

顺便说一下,我有一个InputHandler类,该类具有用于keyDown,keyPressed,keyReleased等的方法。在一个invoke方法中,我没有所有的键检查。invoke方法将键事件添加到存储列表的列表中键,以及一个事件状态枚举,该枚举可以是DOWN,TAPPED,RELEASED,NONE之一。该类主要基于对this question

的响应

我花了过去2个小时的时间来寻求解决方案,但没有发现太多。我确实找到了一些使用回调方法的替代方法,例如:

if (glfwGetKey(window, key) == GLFW_PRESS)

if (glfwGetKey(windowm key) == GLFW_RELEASE)

但是我无法找到一种方法来检测单个按键,即GLFW_REPEAT状态,因为glfwGetKey方法只能检测GLFW_PRESSGLFW_RELEASE

[如果有人可以告诉我一种可以通过glfwGetKey方法检测单个按键敲击或使GLFW回调更轻松,更流畅的方式,我将不胜感激。

谢谢:)

java opengl user-input lwjgl glfw
3个回答
6
投票

所以我解决了这个问题,这要归功于布雷特·黑尔(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;
    }
}

如果需要,请随意使用此代码。不过,只有一些注意事项:应该在每一帧都调用update方法。另外,如果您认为glfwPollEvents()在其他地方(我认为可能是这样),则需要保持重置键盘/鼠标的顺序,然后进行轮询,然后进行getinput()。

编辑:我的Engine.getInput()方法只是告诉场景图中需要输入的节点(即播放器)查询该输入。


4
投票

虽然Kelan的回答非常完美,但我认为我会分享自己的解决方案,因为我在开发游戏时遇到了同样的问题。我实现了自己的Keyboard类,并包含以下方法

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

由于GLFW为每个键保存了最后一个事件,因此您只需要查看最后一个事件是PRESS还是RELEASE。 GLFW不会使用此方法报告REPEAT事件,但是您可以假定它正在重复,直到触发RELEASE事件为止。]


0
投票

其他答案不是我遇到的问题的根本原因。交换缓冲区时,绘制简单的四边形似乎阻塞了输入处理。我只是glfwSwapInterval(0)关闭了垂直同步,这不一定是一个好习惯,但是在我的程序的当前阶段,我希望屏幕撕裂而不是不良的输入滞后,并且似乎可以解决此问题。

© www.soinside.com 2019 - 2024. All rights reserved.