2018年6月9日土曜日

LWJGL3で3Dゲーム開発のすすめ日記(2)

2.ゲームループ(説明)

前回かき逃げしたコードについてちょっとだけ説明しようかなぁーって思います
ちょっとだけ...
全体のコードは前回記事のゲームループ1に載せてありますのでご参照ください

分かる範囲で自分なりの理解を書いていくので間違っててもご了承願います.
ではプログラムの実行順でいきますのでファイルが前後左右するとおもいます.


とりあえずmain.javaから
public class Main {
 
    public static void main(String[] args) {
        try {
            boolean vSync = true;
            IGameLogic gameLogic = new DummyGame();
            GameEngine gameEng = new GameEngine("GAME", 600, 480, vSync, gameLogic);
            gameEng.start();
        } catch (Exception excp) {
            excp.printStackTrace();
            System.exit(-1);
        }
    }
}

javaでのmainは最初に実行されるところですね.
ここではまず
"boolean vSync = true;"というのがあります.
このコードは画面の描画で垂直同期をどうするかという変数です.

次に,
IGameLogic gameLogic = new DummyGame();
ですが,ここにでてくるDummyGame()をたどると次は
Dummy.java
public DummyGame() {
        renderer = new Renderer();
}
といううのが出てきます.
また"Renderer()"を追うと,
Renderer.java
public class Renderer {
 
    public Renderer() {        
    }
     
    public void init() throws Exception {        
    }
 
    public void clear() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }
}
となりなにも書かれていないので,ここまで書いといてなんですがmainの
IGameLogic gameLogic = new DummyGame();
は今の所無視でいいと思います.

mainにもどり,
GameEngine gameEng = new GameEngine("GAME", 600, 480, vSync, gameLogic);
です
これお追うと,GameEngine.javaにいきますね
public GameEngine(String windowTitle, int width, int height, boolean vSync, IGameLogic gameLogic) throws Exception {
        gameLoopThread = new Thread(this, "GAME_LOOP_THREAD");
        window = new Window(windowTitle, width, height, vSync);
        this.gameLogic = gameLogic;
        timer = new Timer();
}

public void start() {
        String osName = System.getProperty("os.name");
        if ( osName.contains("Mac") ) {
            gameLoopThread.run();
        } else {
            gameLoopThread.start();
        }
 }
ここから徐々にゲームっぽい動きをしていきます.
gameLoopThread = new Thread(this, "GAME_LOOP_THREAD");
最初の行でスレッドを作成します.
スレッドとは簡単に言うとプログラムの並行処理です.
通常のプログラムは書かれた順に上から下に実行するところ,
スレッドを使うことによりゲーム(座標など)の処理と描画処理を同時進行で処理してくれます.


次は
window = new Window(windowTitle, width, height, vSync);
ここではmainから渡された引数を基に()内のウィンドウを作成します
windowTitlie : ウィンドウにのタイトル
width : 画面幅
hight :画面の高さ
vSync : 垂直同期の有無

timer = new Timer();
次はタイマーです
Timer.javaを呼び起こします
package org.lwjglb.engine;
 
public class Timer {
 
    private double lastLoopTime;
     
    public void init() {
        lastLoopTime = getTime();
    }
 
    public double getTime() {
        return System.nanoTime() / 1000_000_000.0;
    }
 
    public float getElapsedTime() {
        double time = getTime();
        float elapsedTime = (float) (time - lastLoopTime);
        lastLoopTime = time;
        return elapsedTime;
    }
 
    public double getLastLoopTime() {
        return lastLoopTime;
    }
}
Timerでフレームレートの計算を行います.

main.javaに戻って
ameEng.start();
これでGmeEngin.javaのstart()クラスを起動します
public void start() {
        String osName = System.getProperty("os.name");
        if ( osName.contains("Mac") ) {
            gameLoopThread.run();
            System.out.println( osName);

        } else {
            gameLoopThread.start();
            System.out.println( osName);
            System.out.println("To Start");
        }
    }
ここの処理でクライアントのOSを判断し,OSごとに違う動作をさせます.
Macで動かす場合はRetinaディスプレイを使用しているためドットbyドット
とはいかず座標関係の計算がWindowsとは異なってきます.
今回の環境はwindowsなのでelse側の処理が行われます.
gameLoopThread.start();
でGmeEngin.javaのpublic void run()クラスが起動します.
@Override
    public void run() {
        try {
            init();
            gameLoop();
        } catch (Exception excp) {
            excp.printStackTrace();
        }
    }
ここが並行処理されるクラスです.

init();でwindow,timer,gameLogicの初期化(initialize)が行われます.
protected void init() throws Exception {
        window.init();
        timer.init();
        gameLogic.init();
    }

gameloop();がゲームの動きそのものです
protected void gameLoop() {
        float elapsedTime;
        float accumulator = 0f;
        float interval = 1f / TARGET_UPS;
 
        boolean running = true;
        while (running && !window.windowShouldClose()) {
            elapsedTime = timer.getElapsedTime();
            accumulator += elapsedTime;
 
            input();
 
            while (accumulator >= interval) {
                update(interval);
                accumulator -= interval;
            }
 
            render();
 
            if (!window.isvSync()) {
                sync();
            }
        }
    }

ここでキーボード入力の監視,画面の描画の処理が行われています.


大雑把にコードの流れは以上です.
次は3D空間の描画について書きたいと思います.






0 件のコメント:

コメントを投稿