Java 3D LWJGL 〜Tutorial #2 入力を受け付ける〜

前回作成したコードでは、画面を表示するだけでした。
今度は、入力を受け付ける処理を追加します。
参考にするチュートリアルは動画ですが、こちらになります。

入力を受け付ける

入力、つまりボタンを押下した時のハンドリング部分の実装になります。
くだけた言い方をすると、ボタンを押した時の動きを実装する部分(メソッド)を作る準備をするということです。

早速、コードを写経したので、それを見て見ましょう。
<メインクラス>

public class GameMain {
    public static void main(String[] args) {
        Window win = new Window(800, 500, "LWJGL Tutorial");
        win.create();

        //// ゲームループ ////
        while (!win.closed()) {
            win.update();
            if (win.isKeyPressed(GLFW.GLFW_KEY_A)) {
                System.out.println("Pressed Key A");
            }
            if (win.isKeyReleased(GLFW.GLFW_KEY_A)) {
                System.out.println("Released Key A");
            }
            win.swapBuffers();
        }
    }
}

<ウィンドウクラス>

public class Window {
    /** 画面の幅 */
    private int width;
    /** 画面の高さ */
    private int height;
    /** 画面のタイトル */
    private String title;
    /** 画面の(プログラムレベルの)番号 */
    private long window;

    /** キーボート配列の数だけ配列を用意 */
    private boolean[] keys = new boolean[GLFW.GLFW_KEY_LAST];
    /** マウスのボタン数だけ配列を用意 */
    private boolean[] mouseButtons = new boolean[GLFW.GLFW_MOUSE_BUTTON_LAST];

    /**
     * 画面を作成する、コンストラクター。
     * 
     * @param width 画面の幅
     * @param height 画面の高さ
     * @param title 画面のタイトル
     */
    public Window(int width, int height, String title) {
        this.width = width;
        this.height = height;
        this.title = title;
    }

    /**
     * 画面を作成する処理。
     */
    public void create() {
        if (!GLFW.glfwInit()) {
            System.err.println("Error: Coudn not GLFW");
            System.exit(-1);
        }
        window = GLFW.glfwCreateWindow(width, height, title, 0, 0);
        if (window == 0) {
            System.err.println("Error: window coud not be created");
            System.exit(-1);
        }
        GLFWVidMode videoMode = GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor());
        GLFW.glfwSetWindowPos(window, (videoMode.width() - width) / 2, (videoMode.height() - height) / 2);
    }

    /** 画面を閉じる */
    public boolean closed() {
        return GLFW.glfwWindowShouldClose(window);
    }

    /** 画面を更新する */
    public void update() {
        for (int i = 0; i < GLFW.GLFW_KEY_LAST; i++) keys[i] = isKeyDown(i);
        for (int i = 0; i < GLFW.GLFW_MOUSE_BUTTON_LAST; i++) keys[i] = isMouseDown(i);
        GLFW.glfwPollEvents();
    }

    public void swapBuffers() {
        GLFW.glfwSwapBuffers(window);
    }

    /** 
     * キーボートの入力を受付
     * @param keyCode this{@link #keys}の配列番号
     * @return キーボードが押下されているか判定した結果
     */
    public boolean isKeyDown(int keyCode) {
        return GLFW.glfwGetKey(window, keyCode) == 1;
    }

    /** 
     * マウスの入力を受付
     * @param mouseButton this{@link #mouseButtons}の配列番号
     * @return マウスのボタンが押されているか判定した結果
     */
    public boolean isMouseDown(int mouseButton) {
        return GLFW.glfwGetMouseButton(window, mouseButton) == 1;
    }

    /** キーボードのボタンが押下されているか判定 */
    public boolean isKeyPressed(int keyCode) {
        return isKeyDown(keyCode) && !keys[keyCode];
    }

    /** キーボードのボタンが離されているか判定 */
    public boolean isKeyReleased(int keyCode) {
        return isKeyDown(keyCode) && keys[keyCode];
    }

    /** マウスのボタンが押下されているか判定 */
    public boolean isMouseButtonPressed(int mouseButton) {
        return isKeyDown(mouseButton) && !mouseButtons[mouseButton];
    }

    /** マウスのボタンが離されているか判定 */
    public boolean isMouseButtonReleased(int mouseButton) {
        return isKeyDown(mouseButton) && mouseButtons[mouseButton];
    }

    /** マウスのX軸座標取得 */
    @Deprecated
    public double getMouseX() {
        DoubleBuffer buf = BufferUtils.createDoubleBuffer(1);
        GLFW.glfwGetCursorPos(window, buf, null);
        return buf.get(0);
    }

    /** マウスのY軸座標取得 */
    @Deprecated
    public double getMouseY() {
        DoubleBuffer buf = BufferUtils.createDoubleBuffer(1);
        GLFW.glfwGetCursorPos(window, null, buf);
        return buf.get(0);
    }
}

とりあえず写経して動かして見ました。

しかし、マウスのイベントが取れない事象に遭遇したので、それをなんとかしてどうにかしました。

原因は、イベントが取得できるであろうと思った下のコードでイベントが取得できなかったところです。

/** 
 * マウスの入力を受付
 * @param mouseButton this{@link #mouseButtons}の配列番号
 * @return マウスのボタンが押されているか判定した結果
 */
public boolean isMouseDown(int mouseButton) {
    return GLFW.glfwGetMouseButton(window, mouseButton) == 1;
}

こちらのサイトで見てみると、イベントハンドラが実装されているようなので、そちらを使用します。
コードは下の2種類あるようです。
PatternA: コールバッククラスを設定する

= new GLFWCursorPosCallback() {
    @Override
    public void invoke(long window, double xpos, double ypos) {

    }
});

PatternB: ラムダ式でコールバック処理を設定する

// Java 8
glfwSetCursorPosCallback(window, posCallback = GLFWCursorPosCallback.create((window, xpos, ypos) -> {
    // ここにマウスが押下された時の処理を実装する
}));

背景の実装

下の2つの動画で、出てきた。変数FPSについて自分が理解したことを記載します。

この動画のはじめの部分

最終的に、追加実装したコードは下のようなものです。GetterとSetterを覗きます。(フィールド変数のGetterを作成しました。)
Githubにソースをコミットしました。

一部抜粋してきます。
FPSをWindowクラスに追加してやりました。これは、ボタン押下時の反応速度?(フレーム数)がなんとかとチュートリアルで言っていたのを聞いた程度しか理解していません。

public boolean isUpdating() {
    double nextTime = getTime();
    double passedTime = nextTime - time;
    processedTime += passedTime;
    time = nextTime;

while(processedTime >  1.0/fps_cap) {
processedTime -= 1.0/fps_cap;
        return true;
    }
    return false;
}

この処理で、どうやらフレーム数がなんとか。。。課題として今後理解する必要がありそうだ。

実行した結果は下のような形で、背景も赤くなりました。

関連ページ一覧

http://zenryokuservice.com/wp/2018/10/27/java-game-lwjgl-gitbook-chapter5-2%E3%80%9C%E3%83%AC%E3%83%B3%E3%83%80%E3%83%AA%E3%83%B3%E3%82%B0%E8%A9%B3%E7%B4%B0%E3%80%9C/

<開発準備>

http://zenryokuservice.com/wp/2018/05/02/set-up-1-eclipse-java/

<LWJGLのGitBokに関して>

  1. Chapter1[外枠の表示のみ]
  2. Chapter2-1〜クラスの構成〜
  3. Chapter2-2〜インターフェースの使い方と詳細〜
  4. Chapter2-3〜GameEngineクラス(サンプルクラス)〜/li>
  5. Chapter2-4〜Windowクラス(サンプルクラス)〜
  6. Chapter3〜描画処理を読む〜
  7. Chapter4〜シェーダについて〜
  8. Chapter5-1〜レンダリングについて〜

<Java Basic>

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 8.5 〜Array〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜