欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

了解和探索GameApplication:FXGL17指南

最编程 2024-07-23 21:40:59
...

PS:禁止拷贝形式转载,转载请以URL形式

PS:FXGL 准备写成一个系列,所以在该系列未完成前,该系列文章除了目录会被修改其他内容均可能被删改。

1. 简介

本章主要总结游戏运行的大致流程以及相关函数的使用,最后编写一个简单的DEMO 达到认识FXGL表层是怎么运行和FXGL大致是怎么开发的。

2. GameApplication 运行流程

PS:本小节描述FXGL 规定下游戏的大致运行流程以及各个流程相关含义

2.1. 流程分析

graph LR
    Start --> initSettings
    
    subgraph 程序初始化
        initSettings
        --> initInput
        --> onPreInit
    end
 
    onPreInit --> initGameVars
    
    subgraph 游戏初始化
        initGameVars
        --> initGame
        --> initPhysics
        --> initUI
        --> onUpdate -- 循环 --> onUpdate
    end

    onUpdate --> Stop

流程对应函数

  • initSettings :游戏设置(全局的游戏设置如标题、版本、图标等)
  • initInput :初始化绑定 输入/控制事件(游戏里面的按键事件绑定如w按键按下代表物体向上移动)
  • onPreInit :游戏预先资源初始化(游戏里面对大文件资源如地图的预先加载)
  • initGameVars :初始化游戏变量(游戏里面使用到的变量如击杀敌人数量、死亡次数等相关变量的初始化)
  • initGame :初始化游戏(游戏中需要创建的ENTITY玩家进行初始化)
  • initPhysics :初始化绑定 碰撞事件(对具有可碰撞的相关ENTITY进行事件绑定处理 )
  • initUI :初始化UI(界面的初始元素设置)
  • onUpdate :游戏更新UI时调用的钩子函数,FXGL 每1帧动画的更新都会调用该函数

2.2. 涉及代码

代码

import com.almasb.fxgl.app.GameApplication;
import com.almasb.fxgl.app.GameSettings;
import com.almasb.fxgl.dsl.FXGL;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;

import java.util.Map;

/**
 * @ClassName
 * @Description
 * @Author dyf
 * @Date 2022/6/30
 * @Version 1.0
 */
public class KnowGAApp extends GameApplication {

    private int updateNums = 0;

    @Override
    protected void initSettings(GameSettings gameSettings) {
        System.out.println("KnowGAApp.initSettings");
        gameSettings.setTitle("KnowGAApp");
        gameSettings.setVersion("1.0");
        gameSettings.setMainMenuEnabled(true);
    }


    @Override
    protected void initInput() {
        System.out.println("KnowGAApp.initInput");
    }

    @Override
    protected void onPreInit() {
        System.out.println("KnowGAApp.onPreInit");
    }

    @Override
    protected void initGameVars(Map<String, Object> vars) {
        System.out.println("KnowGAApp.initGameVars");
    }

    @Override
    protected void initGame() {
        System.out.println("KnowGAApp.initGame");
    }

    @Override
    protected void initPhysics() {
        System.out.println("KnowGAApp.initPhysics");
    }

    @Override
    protected void initUI() {
        System.out.println("KnowGAApp.initUI");
        Text text = FXGL.getUIFactoryService().newText("HELLO FXGL", Color.BLACK, 22);
        FXGL.addUINode(text, FXGL.getAppCenter().getX(), FXGL.getAppCenter().getY());
    }

    @Override
    protected void onUpdate(double tpf) {
        if (updateNums<=2) {
            System.out.println("KnowGAApp.onUpdate");
            updateNums++;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

输出

KnowGAApp.initSettings
16:09:51.059 [JavaFX Application Thread] INFO  Engine               - FXGL-17.1 (24.03.2022 17.34) on WINDOWS (J:17 FX:17.0.2-ea)
16:09:51.060 [JavaFX Application Thread] INFO  Engine               - Source code and latest versions at: https://github.com/AlmasB/FXGL
16:09:51.060 [JavaFX Application Thread] INFO  Engine               -       Ask questions and discuss at: https://github.com/AlmasB/FXGL/discussions
16:09:51.061 [JavaFX Application Thread] INFO  Engine               -              Join the FXGL chat at: https://gitter.im/AlmasB/FXGL
16:09:51.864 [FXGL Background Thread 1 ] INFO  FXGLApplication      - FXGL initialization took: 0.557 sec
KnowGAApp.initInput
KnowGAApp.onPreInit
KnowGAApp.initGameVars
KnowGAApp.initGame
KnowGAApp.initPhysics
KnowGAApp.initUI
16:09:53.013 [FXGL Background Thread 2 ] INFO  FXGLApplication      - Game initialization took: 0.001 sec
KnowGAApp.onUpdate
KnowGAApp.onUpdate
KnowGAApp.onUpdate

3. 拾取金币game

PS:本小节写一个demo将对应流程的函数串联使用起来,demo内容为展示游戏角色由用户控制拾取金币并显示当前金币数量

3.1 涉及代码

package priv.dyf.fxgl.helloworld;

import com.almasb.fxgl.app.GameApplication;
import com.almasb.fxgl.app.GameSettings;
import com.almasb.fxgl.core.math.FXGLMath;
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.physics.CollisionHandler;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.util.Duration;

import java.util.List;
import java.util.Map;

/**
 * @ClassName
 * @Description
 * @Author dyf
 * @Date 2022/6/30
 * @Version 1.0
 */
public class KnowGAApp extends GameApplication {

    static final String GOLD_KEY = "gold";
    static final String FPS_KEY = "fps";

    private ImageView background;
    private int fps;
    private Entity player;

    enum GameObj {
        PLAYER, GOLD;
    }

    @Override
    protected void initSettings(GameSettings gameSettings) {
        gameSettings.setTitle("KnowGAApp");
        gameSettings.setVersion("1.0");
    }

    @Override
    protected void initInput() {
        //绑定按键,控制角色行动
        FXGL.onKey(KeyCode.UP, () -> player.translateY(-5));
        FXGL.onKey(KeyCode.DOWN, () -> player.translateY(5));
        FXGL.onKey(KeyCode.LEFT, () -> player.translateX(-5));
        FXGL.onKey(KeyCode.RIGHT, () -> player.translateX(5));
    }

    @Override
    protected void onPreInit() {
        //预先加载背景图片
        Image image = FXGL.image("background.png");
        background = new ImageView(image);
        background.setFitHeight(FXGL.getAppHeight() - 22);
        background.setFitWidth(FXGL.getAppWidth());
    }

    @Override
    protected void initGameVars(Map<String, Object> vars) {
        //初始化金币变量并赋值
        vars.put(GOLD_KEY, 0);
        vars.put(FPS_KEY, 0);
    }

    @Override
    protected void initGame() {

        //添加背景
        FXGL.entityBuilder().view(background).at(0, 22).buildAndAttach();
        //创建玩家
        player = FXGL.entityBuilder()
                .viewWithBBox(new Rectangle(40, 40, Color.BLUE))    //创建一个20*20的正方形,添加到视图场景并且设置其物理场景下大小也为20*20
                .at(FXGL.getAppCenter())    //玩家创建后初始化的位置
                .type(GameObj.PLAYER)       //设置类型:不设置物理引擎无法识别
                .collidable()               //设置可碰撞:不设置物理引擎无法判断
                .buildAndAttach();          //创建并且添加到游戏世界中

        //间隔1S,定时生成金币,刷新FPS
        Rectangle2D rectangle2D = new Rectangle2D(100, 100, FXGL.getAppWidth() - 200, FXGL.getAppHeight() - 200);
        FXGL.getGameTimer().runAtInterval(() -> {
            //刷新FPS
            FXGL.set(FPS_KEY, fps);
            fps = 0;

            //查找现有金币数量
            List<Entity> golds = FXGL.getGameWorld().getEntitiesByType(GameObj.GOLD);
            //游戏世界里最多生成10枚金币
            if (golds.size() < 10) {
                //随机生成的金币不要和现有的金币产生位置冲突
                Point2D point2D = FXGLMath.randomPoint(rectangle2D);
                while (!FXGL.getGameWorld().getEntitiesInRange(new Rectangle2D(point2D.getX(), point2D.getY(), 10, 10)).isEmpty()) {
                    point2D = FXGLMath.randomPoint(rectangle2D);
                }
                //生成金币
                FXGL.entityBuilder()
                        .viewWithBBox(new Circle(10, Color.RED))    //创建一个半径10的圆形,添加到视图场景并且设置其物理场景下大小也为10
                        .at(point2D)                //创建后初始化的位置
                        .type(GameObj.GOLD)         //设置类型:不设置物理引擎无法识别
                        .collidable()               //设置可碰撞:不设置物理引擎无法判断
                        .buildAndAttach();          //创建并且添加到游戏世界中
            }
        }, Duration.seconds(1));

    }

    @Override
    protected void initPhysics() {
        FXGL.getPhysicsWorld().addCollisionHandler(new CollisionHandler(GameObj.PLAYER, GameObj.GOLD) {
            // 类型的顺序与传入构造函数的顺序相同
            @Override
            protected void onCollisionBegin(Entity player, Entity gold) {
                //删除金币
                gold.removeFromWorld();
                //增加分数
                FXGL.inc(GOLD_KEY, 1);
            }
        });
    }

    @Override
    protected void initUI() {
        //创建UI并且添加到游戏场景
        Text text = FXGL.getUIFactoryService().newText("", Color.BLACK, 22);
        text.textProperty().bind(FXGL.getWorldProperties().intProperty(GOLD_KEY).asString("金币: %s"));
        FXGL.addUINode(text, FXGL.getAppCenter().getX(), 22);
        Text fps = FXGL.getUIFactoryService().newText("", Color.BLACK, 22);
        fps.textProperty().bind(FXGL.getWorldProperties().intProperty(FPS_KEY).asString("FPS: %s"));
        FXGL.addUINode(fps, 0, 22);
    }

    @Override
    protected void onUpdate(double tpf) {
        fps++;
    }

    public static void main(String[] args) {
        launch(args);
    }
}

3.2 效果展示

1.gif