FXGL 学习笔记一 《GameApplication的执行顺序》

前言

学习使用java开发游戏。FXGL是基于javaFX的一个游戏引擎框架。对于java开发来说,上手简单。本笔记为记录FXGL中常用的一些API和注意要点。后续自己开发过程中,如果发现问题或者描述不对的地方,再进行修改。

学习过程参考 LeeWyatt 的 FXGL基础入门教程

环境

  • JDK:openjdk-17
  • fxgl: 17

依赖


    com.github.almasb
    fxgl
    17

正文

编写一个最简单的游戏启动类,

  • 创建一个maven项目
  • 添加fxgl依赖
  • 编写TestApp主类(一般启动类使用App结尾)
  • 在module-info.java模块类中,开启并引入fxgl
  • 代码

    package com.cah.api;
    
    import com.almasb.fxgl.app.GameApplication;
    import com.almasb.fxgl.app.GameSettings;
    import com.almasb.fxgl.dsl.FXGL;
    import com.almasb.fxgl.time.LocalTimer;
    import javafx.util.Duration;
    
    import java.util.Map;
    
    /**
     * 
    <p> Api主类 </p>
     *
     * @author hongtool
     * @date 2023/8/13
     */
    public class ApiApp extends GameApplication {
    
        /** 计时器 */
        private LocalTimer timer;
    
        public static void main(String[] args) {
            // 开始执行
            launch(args);
        }
    
        /** 最先执行 */
        public ApiApp() {
            System.out.println("构造器==》" + Thread.currentThread().getName());
        }
    
        /** 第二步,执行游戏初始化设置 */
        @Override
        protected void initSettings(GameSettings gameSettings) {
            // 可以设置 游戏的 标题、图标、版本、宽度、高度等,具体的内容稍后参考《GameSettings》学习资料
            // 图标资源,参考 《FXGL 资源分类》学习资料
            System.out.println("ApiApp.initSettings==》" + Thread.currentThread().getName());
            // 注意:在此方法中,不要执行“FXGL.”的静态方法。会出错。因为这时候FXGL的相关属性引擎尚未加载
        }
    
        /** 第三步,执行游戏的输入监听 */
        @Override
        protected void initInput() {
            // 包括键盘输入,鼠标输入等
            System.out.println("ApiApp.initInput==》" + Thread.currentThread().getName());
        }
    
        /** 第四步,资源预加载初始化 */
        @Override
        protected void onPreInit() {
            // 预加载游戏背景音乐,设置是否开启背景音乐和音效等。
            System.out.println("ApiApp.onPreInit==》" + Thread.currentThread().getName());
        }
    
        /** 第五步,初始化游戏参数 */
        @Override
        protected void initGameVars(Map vars) {
            // 通过map的形式,保存游戏中的通用参数。
            // 在其他地方使用 FXGL.getip(key)的方式进行获取,FXGL.set(key,value)的方式进行重新赋值
            System.out.println("ApiApp.initGameVars==》" + Thread.currentThread().getName());
        }
    
        /** 第六步,初始化游戏(重点) */
        @Override
        protected void initGame() {
            // 初始化计时器(为什么要在这里初始化呢?因为)
            timer = FXGL.newLocalTimer();
            System.out.println("ApiApp.initGame==》" + Thread.currentThread().getName());
        }
    
        /** 第七步,初始化游戏物理引擎(重点) */
        @Override
        protected void initPhysics() {
            // 物理碰撞事件等
            System.out.println("ApiApp.initPhysics==》" + Thread.currentThread().getName());
        }
    
        /** 第八步,初始化UI界面 */
        @Override
        protected void initUI() {
            System.out.println("ApiApp.initUI==》" + Thread.currentThread().getName());
        }
    
        /** 最后一步,游戏每一帧都会调用改方法。默认为60帧 */
        @Override
        protected void onUpdate(double tpf) {
            // 如果计时器走过1秒,则打印
            if(timer.elapsed(Duration.seconds(1))) {
                // 重置计时器
                timer.capture();
                System.out.println("ApiApp.onUpdate==》" + Thread.currentThread().getName());
            }
        }
    
    }
    

    结果

    运行main方法,查看执行结果

    构造器==》main
    ApiApp.initSettings==》main
    
    ApiApp.initInput==》JavaFX Application Thread
    ApiApp.onPreInit==》JavaFX Application Thread
    ApiApp.initGameVars==》FXGL Background Thread 1
    ApiApp.initGame==》FXGL Background Thread 1
    ApiApp.initPhysics==》FXGL Background Thread 1
    ApiApp.initUI==》FXGL Background Thread 1
    22:50:57.515 [FXGL Background Thread 1 ] INFO  FXGLApplication      - Game initialization took: 0.002 sec
    
    ApiApp.onUpdate==》JavaFX Application Thread
    ApiApp.onUpdate==》JavaFX Application Thread
    ApiApp.onUpdate==》JavaFX Application Thread
    ApiApp.onUpdate==》JavaFX Application Thread
    

    开发菜单页面

    initSettings方法中,添加开启菜单代码

    @Override
    protected void initSettings(GameSettings gameSettings) {
        gameSettings.setMainMenuEnabled(true);
        System.out.println("ApiApp.initSettings==》" + Thread.currentThread().getName());
    }
    

    操作过程

  • 运行main方法
  • 等待游戏启动,观察日志为运行了四分方法,顺序为:构造器>initSettings>initInput>onPreInit;其他的方式都没有执行
  • 点击【NEW GAME】按钮,发现执行了initGameVars>initGame>initPhysics>initUI>一直调用onUpdate
  • 这时按【Esc】按键,暂停游戏,发现onUpdate没有执行
  • 点击【MAIN MENU】按钮,返回主菜单界面。
  • 再次点击【NEW GAME】按钮,发现也是执行了第3点的方法。但是线程名称名称不一样,说明启动了新线程执行,但是onUpdate还是主线程在执行。
  • 总结

    通过重写方法,打印日志,和操作分析,可以观察 GameApplication 各个方法的执行顺序与用途。