2016-04-11 75 views
0

之間的延遲,而且我有一定的困難,有越來越鍵盤和鼠標輸入。順便說一下,我正在使用它來進行相機移動和旋轉。LWJGL 3 GLFW鍵盤和鼠標輸入是緩慢的,有那麼我剛纔最近提出從LWJGL 2至3 GLFW_PRESS和GLFW_REPEAT

我的問題是,如果我使用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) 

,但我不能找到一種方法,使用這種檢測單個按鍵敲擊,即因爲glfwGetKey方法只能檢測到GLFW_PRESSGLFW_RELEASE

如果有人能告訴我用glfwGetKey方法檢測單個按鍵的方法,或者使GLFW回調遠不如以往更平滑,我將不勝感激。

謝謝:)

+0

據推測,如果你動畫(使用'glfwPollEvents'在一個循環中),您可以假設鍵被按下直到鍵處理程序回調收到'RELEASE'該鍵。否則,循環中的'glfwWaitEvents'不會執行任何操作,直到窗口系統確定足夠長的時間間隔來響應REPEAT。 –

+0

有沒有辦法縮短註冊'GLFW_REPEAT'所用的時間? – Kelan

+0

不使用glfw。可能有與操作系統有關的方式來執行此操作,但glfw只響應操作系統提供的事件。我懷疑它會產生全球效應,而不是按應用程序。 –

回答

4

所以我的問題解決了,感謝假設關鍵是,直到一個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; 
    } 
} 

如果您願意,可以隨意使用此代碼。儘管如此:更新方法應該每幀調用一次。另外,如果您在其他地方(我認爲可能)有glfwPollEvents(),則需要保留重置鍵盤/鼠標的順序,然後輪詢,然後執行getinput()。

編輯: 我的Engine.getInput()方法告訴場景圖中的節點需要輸入,即播放器來查詢該輸入。

+0

我不太明白你的意思。我對GLFW和OpenGL 3還是很新的,所以我以前沒見過'glfwWaitEvents()'。我遵循[本指南](https://www.lwjgl.org/guide)設置我的窗口。 'glfwWaitEvents()'應該在哪裏? – Kelan

2

雖然珂蘭的回答完美的作品,我想我會分享我的解決方案,這是我遇到了同樣的問題,在遊戲中工作時。我實現了我自己的鍵盤類,幷包括以下方法

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節省了每個按鍵的最後一場比賽,你只需要看看最後一次是擠壓或者釋放。 GLFW不會使用此方法報告REPEAT事件,但您可以假定它正在重複,直到發佈RELEASE事件。