Merge pull request #17 from nitta-lab/feature/#11_sync_frame_rate
Feature/#11 sync frame rate
commit fca060fce875815b4db25d051cb9923a8b82676a
2 parents da23416 + 95f664b
fujii kouta authored on 16 Nov 2021
Showing 14 changed files
View
82
src/main/java/GLWindow.java 0 → 100644
import entities.GLConfigVariable;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
 
import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.NULL;
 
//---------------------------------------------------------------
// ウィンドウ
public class GLWindow {
 
private long hWnd; // ウィンドウハンドル
 
//---------------------------------------------------------------
//---------------------------------------------------------------
//
public void init() {
initWindow();
initRender();
}
 
//---------------------------------------------------------------
// 画面のスワップ
public void swapWindow() {
glfwSwapBuffers(hWnd); // バッファのスワップ
glfwPollEvents(); // 入力とかイベントの取得
}
 
//---------------------------------------------------------------
// ウィンドウの破棄
public void destroyWindow() {
glfwFreeCallbacks(hWnd); // ウィンドウコールバックの解放
glfwDestroyWindow(hWnd); // ウィンドウの破棄
glfwTerminate(); // GLFWの破棄
glfwSetErrorCallback(null).free(); // エラーコールバックの解放
}
 
//---------------------------------------------------------------
// ウィンドウが起動しているかどうか
public boolean windowShouldClose() {
return glfwWindowShouldClose(hWnd);
}
 
//---------------------------------------------------------------
// ウィンドウの初期化
private void initWindow() {
GLFWErrorCallback.createPrint(System.err).set(); // エラーコールバックの設定
 
 
// GLFWの初期化
if (!glfwInit()) throw new IllegalStateException("Unable to initialize GLFW");
 
// ウィンドウの設定
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
 
// ウィンドウの作成
hWnd = glfwCreateWindow(GLConfigVariable.WIDTH, GLConfigVariable.HEIGHT, GLConfigVariable.TITLE_NAME, GLConfigVariable.IS_FULL_SCREEN ? glfwGetPrimaryMonitor() : NULL, NULL);
if (hWnd == NULL)
throw new RuntimeException("Failed to create the window.");
 
glfwMakeContextCurrent(hWnd); //起動したウィンドウをターゲットに
glfwSwapInterval(1); // v-syncの適応
 
glfwShowWindow(hWnd); // ウィンドウの表示
}
 
//---------------------------------------------------------------
// 描画プロセス初期化
private void initRender() {
GL.createCapabilities();
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // 背景色設定
 
// OpenGLの初期化
glEnable(GL_TEXTURE_2D); // 二次元テクスチャの有効化
glEnable(GL_BLEND); // アルファブレンディングの有効化
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // ブレンドモードの設定
}
//---------------------------------------------------------------
}
View
47
src/main/java/GameEngine.java 0 → 100644
import static org.lwjgl.opengl.GL11.*;
 
//---------------------------------------------------------------
// ゲームループ提供
public abstract class GameEngine {
 
private GLWindow glWindow = new GLWindow();
 
//---------------------------------------------------------------
//---------------------------------------------------------------
// 初期化
protected void init() {
}
 
//---------------------------------------------------------------
// ゲームループ
protected void update() {
}
 
//---------------------------------------------------------------
// 破棄処理
protected void destroy() {
}
 
//---------------------------------------------------------------
//---------------------------------------------------------------
// 実行系の本体
protected void run() {
 
// 初期化
glWindow.init();
init();
 
// メインループ
while (!glWindow.windowShouldClose()) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // バッファのクリア
update();
glWindow.swapWindow();
}
 
// 終了処理
destroy(); // デストラクタ
glWindow.destroyWindow(); // ウィンドウの破棄
}
//---------------------------------------------------------------
}
View
3
■■
src/main/java/JumpGame.java
//---------------------------------------------------------------
//---------------------------------------------------------------
//
public void gravity(double y) {
// this.force.gravity(y);
// this.time.gravity(y);
PlayerModel playerModel = (PlayerModel) models.get(ModelType.PLAYER_MODEL);
playerModel.updateGravity(y);
}
// Space キーのインプット
//
// マイフレーム更新
 
// gravity(0.01); //重力
gravity(-256); //重力
}
 
//---------------------------------------------------------------
// デストラクタのような処理
View
194
src/main/java/Main.java
import entities.WindowConfig;
import entities.GLConfigVariable;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
 
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.*;
 
public class Main {
//---------------------------------------------------------------
// 実行本体
public class Main extends GameEngine {
 
private long variableYieldTime, lastTime;
// ウィンドウハンドル
private long hWnd;
 
//
private JumpGame jumpGame = new JumpGame();
 
// フルスクリーン
public boolean fullScreen;
 
//---------------------------------------------------------------
//---------------------------------------------------------------
// エントリーポイント
public static void main(String[] args) {
new Main().run(false);
}
 
//---------------------------------------------------------------
// メイン関数
public void run(boolean fullScreen) {
// フルスクリーンの真偽値を貰う
this.fullScreen = fullScreen;
 
// 色々初期化
initWindow();
initRender();
jumpGame.init();
 
// メインループ
while (!glfwWindowShouldClose(hWnd)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // バッファのクリア
 
jumpGame.update();
 
glfwSwapBuffers(hWnd); // バッファのスワップ
glfwPollEvents(); // 入力とかイベントの取得
 
}
 
// 終了処理
delete(); // デストラクタ
glfwFreeCallbacks(hWnd); // ウィンドウコールバックの解放
glfwDestroyWindow(hWnd); // ウィンドウの破棄
glfwTerminate(); // GLFWの破棄
glfwSetErrorCallback(null).free(); // エラーコールバックの解放
new Main().run();
}
 
//---------------------------------------------------------------
//---------------------------------------------------------------
// ウィンドウの初期化
private void initWindow() {
GLFWErrorCallback.createPrint(System.err).set(); // エラーコールバックの設定
 
 
// GLFWの初期化
if (!glfwInit())
throw new IllegalStateException("Unable to initialize GLFW");
 
// ウィンドウの設定
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
 
// ウィンドウの作成
hWnd = glfwCreateWindow(WindowConfig.WIDTH, WindowConfig.HEIGHT, WindowConfig.TITLE_NAME, fullScreen ? glfwGetPrimaryMonitor() : NULL, NULL);
if (hWnd == NULL)
throw new RuntimeException("Failed to create the window.");
 
// ウィンドウをタゲにするのか?
glfwMakeContextCurrent(hWnd);
// v-syncの適応
glfwSwapInterval(1);
 
// ウィンドウの表示
glfwShowWindow(hWnd);
 
 
// 初期化
@Override
protected void init(){
jumpGame.init();
}
 
//---------------------------------------------------------------
// 描画プロセス初期化
private void initRender() {
GL.createCapabilities();
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // 背景色設定
 
// OpenGLの初期化
glEnable(GL_TEXTURE_2D); // 二次元テクスチャの有効化
glEnable(GL_BLEND); // アルファブレンディングの有効化
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // ブレンドモードの設定
// 更新処理
@Override
protected void update(){
jumpGame.update();
}
 
//---------------------------------------------------------------
// デストラクタ
public void delete() {
// 破棄
@Override
protected void destroy() {
jumpGame.delete();
}
 
//---------------------------------------------------------------
//
private void sync(int fps) {
if (fps <= 0) return;
 
long sleepTime = 1000000000 / fps; // nanoseconds to sleep this frame
// yieldTime + remainder micro & nano seconds if smaller than sleepTime
long yieldTime = Math.min(sleepTime, variableYieldTime + sleepTime % (1000*1000));
long overSleep = 0; // time the sync goes over by
 
try {
while (true) {
long t = System.nanoTime() - lastTime;
 
if (t < sleepTime - yieldTime) {
Thread.sleep(1);
}else if (t < sleepTime) {
// burn the last few CPU cycles to ensure accuracy
Thread.yield();
}else {
overSleep = t - sleepTime;
break; // exit while loop
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
lastTime = System.nanoTime() - Math.min(overSleep, sleepTime);
 
// auto tune the time sync should yield
if (overSleep > variableYieldTime) {
// increase by 200 microseconds (1/5 a ms)
variableYieldTime = Math.min(variableYieldTime + 200*1000, sleepTime);
}
else if (overSleep < variableYieldTime - 200*1000) {
// decrease by 2 microseconds
variableYieldTime = Math.max(variableYieldTime - 2*1000, 0);
}
}
}
//---------------------------------------------------------------
}
View
40
src/main/java/entities/Acceleration.java
package entities;
 
public class Acceleration {
private double massValue;
private Pair<Double> forceValue;
private double massValue = 1.0;
private Pair<Double> forceValue = new Pair<>(0d, 0d);
private Velocity velocity;
private Onground onground;
private Pair<Double> value;
private Pair<Double> value = new Pair<>(0d, 0d);
 
//---------------------------------------------------------------
//
public void updateByMass(double mass) {
this.massValue = mass;
Pair temp_l0;
if (this.onground.getOnground()) {
temp_l0 = new Pair((forceValue.getFirst() / mass), 0.0);
} else {
temp_l0 = new Pair((forceValue.getFirst() / mass), (forceValue.getSecond() / mass));
}
value = temp_l0;
Pair<Double> temp_l0;
 
if (this.onground.getOnground()) temp_l0 = new Pair((forceValue.getFirst() / mass), 0.0);
else temp_l0 = new Pair((forceValue.getFirst() / mass), (forceValue.getSecond() / mass));
 
this.value = temp_l0;
velocity.updateByAcceleration(value);
}
 
//---------------------------------------------------------------
//
public void updateByForce(Pair<Double> force) {
this.forceValue = force;
Pair temp_l1;
if (this.onground.getOnground()) {
temp_l1 = new Pair((force.getFirst() / massValue), 0.0);
} else {
temp_l1 = new Pair((force.getFirst() / massValue), (force.getSecond() / massValue));
}
Pair<Double> temp_l1;
 
if (this.onground.getOnground()) temp_l1 = new Pair((force.getFirst() / massValue), 0.0);
temp_l1 = new Pair((force.getFirst() / massValue), (force.getSecond() / massValue));
 
value = temp_l1;
velocity.updateByAcceleration(value);
}
 
//---------------------------------------------------------------
//---------------------------------------------------------------
public Acceleration(Velocity velocity, Onground onground) {
this.velocity = velocity;
this.onground = onground;
}
 
//---------------------------------------------------------------
//
public Pair<Double> getValue() {
return value;
}
}
View
2
■■■
src/main/java/entities/Force.java
package entities;
 
public class Force {
private Acceleration acceleration;
private Pair<Double> value;
private Pair<Double> value = new Pair<>(0.0d, 0.0d);
 
public Force(Acceleration acceleration) {
this.acceleration = acceleration;
}
View
18
src/main/java/entities/GLConfigVariable.java 0 → 100644
package entities;
 
//---------------------------------------------------------------
// 画面設定定数
public class GLConfigVariable {
//---------------------------------------------------------------
//---------------------------------------------------------------
private GLConfigVariable() {
}
 
//---------------------------------------------------------------
public static final String TITLE_NAME = "JumpGame";
public static final int WIDTH = 1280;
public static final int HEIGHT = 720;
public static final int DEPTH = 100; // 追加。深度
public static final double TARGET_FPS = 60d; //フレームレート
public static final boolean IS_FULL_SCREEN = false;
}
View
4
src/main/java/entities/Image2D.java
// プロジェクションモード
glMatrixMode(GL_PROJECTION);
// 行列の設定
glLoadIdentity(); // 単位行列化
glOrtho(0, WindowConfig.WIDTH, 0, WindowConfig.HEIGHT, -WindowConfig.DEPTH, WindowConfig.DEPTH); // 正射影投影
glOrtho(0, GLConfigVariable.WIDTH, 0, GLConfigVariable.HEIGHT, -GLConfigVariable.DEPTH, GLConfigVariable.DEPTH); // 正射影投影
 
// ビューポートの範囲
glViewport(0, 0, WindowConfig.WIDTH, WindowConfig.HEIGHT);
glViewport(0, 0, GLConfigVariable.WIDTH, GLConfigVariable.HEIGHT);
 
// ポリゴンの色
glColor4d(color.getR(), color.getG(), color.getB(), alpha);
 
View
2
■■■
src/main/java/entities/Move.java
package entities;
 
public class Move {
private Velocity velocity;
private Pair<Double> value;
private Pair<Double> value = new Pair<>(0d, 0d);
 
public Move(Velocity velocity) {
this.velocity = velocity;
}
View
4
src/main/java/entities/Position.java
//---------------------------------------------------------------
//
public class Position {
private Ground ground;
private Pair<Double> value;
private Pair<Double> value = new Pair<>(0d, 0d);
 
//---------------------------------------------------------------
//---------------------------------------------------------------
//
public void updateByVelocity(Pair<Double> velocity) {
Pair temp_l3;
Pair<Double> temp_l3;
if (((this.ground.getValue() == true) && ((this.value.getSecond() + (0.01 * velocity.getSecond())) < 0.0))) {
temp_l3 = new Pair((this.value.getFirst() + (0.01 * velocity.getFirst())), 0.0);
} else {
temp_l3 = new Pair((this.value.getFirst() + (0.01 * velocity.getFirst())), (this.value.getSecond() + (0.01 * velocity.getSecond())));
View
2
■■■
src/main/java/entities/Velocity.java
//---------------------------------------------------------------
//---------------------------------------------------------------
public void updateByMove(Pair<Double> move) {
this.moveValue = move;
Pair temp_l2;
Pair<Double> temp_l2;
if ((this.onground.getOnground() && (move.getSecond() >= 0.0))) {
temp_l2 = move;
} else {
temp_l2 = this.value;
View
16
src/main/java/entities/WindowConfig.java 100644 → 0
package entities;
 
//---------------------------------------------------------------
// 画面設定定数
public class WindowConfig {
//---------------------------------------------------------------
//---------------------------------------------------------------
private WindowConfig() {
}
 
//---------------------------------------------------------------
public static final String TITLE_NAME = "JumpGame";
public static final int WIDTH = 1280;
public static final int HEIGHT = 720;
public static final int DEPTH = 100; // 追加。深度
}
View
3
■■
src/main/java/models/PlayerModel.java
 
//---------------------------------------------------------------
//
public void jump() {
this.move.moveY(jumpPower);
this.move.moveX(jumpPower);
}
 
//---------------------------------------------------------------
//
public void updateGravity(double gravity) {
this.force.gravity(gravity);
System.out.println("swapWindow Gravity");
}
}
View
8
src/main/java/views/TileMapRenderer.java
package views;
 
import entities.WindowConfig;
import entities.GLConfigVariable;
import entities.Pair;
import entities.TileType;
import models.IModel;
 
private void createTile(TileType tileType) {
 
switch (tileType) {
case CLOSE:
newTile = new TileRenderer("resources/tile.png", new Pair<>((double) WindowConfig.WIDTH, 0d), 2);
newTile = new TileRenderer("resources/tile.png", new Pair<>((double) GLConfigVariable.WIDTH, 0d), 2);
break;
 
case OPEN:
newTile = new TileRenderer("resources/hole.png", new Pair<>((double) WindowConfig.WIDTH, 0d),2);
newTile = new TileRenderer("resources/hole.png", new Pair<>((double) GLConfigVariable.WIDTH, 0d),2);
break;
}
 
tiles.add(newTile);
//---------------------------------------------------------------
// 初期タイル作成
private void initTiles() {
 
for (double x = 0; x <= WindowConfig.WIDTH; x += 32 * newTile.getScaleValue()) {
for (double x = 0; x <= GLConfigVariable.WIDTH; x += 32 * newTile.getScaleValue()) {
newTile = new TileRenderer("resources/tile.png", new Pair<>(x, offsetY));
newTile.setScaleValue(2);
tiles.add(newTile);
}