IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> JavaFX游戏制作思路 -> 正文阅读

[移动开发]JavaFX游戏制作思路

最近在学习JavaFX游戏制作,这篇文章将自己的思考所得记录下来。

JavaFX游戏制作主要是在Canvas内绘画。每一帧都先检查所有的动作,然后将相应的组件绘制上去。

由此可见,最重要的类就是组件,其中组件包括,位置,长宽,图片以及图层等信息,并且每个组件可能还会有动作(比如游戏中的敌人,会自己找到你,并且攻击你)。

我定义了一个基础的Component类记录组件的基础功能

@Data
public class Component{

    // 对应图片的url
    private String image_url;
    private Image image;
    // 位置信息(从左上角开始)
    private Integer pos_x;
    private Integer pos_y;
    // 宽度和高度
    private Integer width;
    private Integer height;
    // 图层数,代表什么时候被渲染,数越大,表示越在表层
    private Integer layout;
    // 用于进行碰撞检测
    private Rect rect;


    class Rect{
        // 方形中心坐标
        public Integer x;
        public Integer y;
        public Integer width;
        public Integer height;
        public Rect(Integer x, Integer y, Integer width, Integer height){
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }
    }

    public Component(Image image, Integer width, Integer height, Integer layout){
        this.image = image;
        this.width = width;
        this.height = height;
        this.layout = layout;
        this.pos_x = 0;
        this.pos_y = 0;
        Rect rect = new Rect(pos_x+(width/2), pos_y+(height/2), width, height);
    }

    public Component(String image, Integer width, Integer height, Integer layout){
        this.image = new Image(image, width, height, true, true);
        this.width = width;
        this.height = height;
        this.layout = layout;
        this.pos_x = 0;
        this.pos_y = 0;
        Rect rect = new Rect(pos_x+(width/2), pos_y+(height/2), width, height);
    }

    public Component(String image, Integer width, Integer height, Integer x, Integer y, Integer layout){
        this.image = new Image(image, width, height, true, true);
        this.width = width;
        this.height = height;
        this.layout = layout;
        this.pos_x = x;
        this.pos_y = y;
        Rect rect = new Rect(pos_x+(width/2), pos_y+(height/2), width, height);
    }

    // 移动
    public void gotoxy(Integer x, Integer y){
        this.pos_x = x;
        this.pos_y = y;
    }

    // 碰撞检测
    // 返回true表示碰撞了,返回false表示没有碰撞
    public boolean checkimpact(Rect rect){
        // 从两个方向上进行检测
        // 两个轴上的距离
        int distance_x = Math.abs(rect.x-this.rect.x);
        int distance_y = Math.abs(rect.y-this.rect.y);
        // 两个轴上的最大距离
        int max_distance_x = Math.min(rect.width, this.rect.width);
        int max_distance_y = Math.min(rect.height, this.rect.height);
        if(distance_x<=max_distance_x || distance_y<=max_distance_y){
            return true;
        }
        return false;
    }
}

这只是定义了基础的功能,但是不包括人物的动作,为了让每个类都能有自己的动作,我们需要一个接口

@FunctionalInterface
public interface FrameDoing {

    // 每一帧的动作
    public void doing(Component component);

}

并且定义一个类,继承Component以及实现FrameDoing接口

public class Role extends Component implements FrameDoing{

    // 每一帧的动作
    private FrameDoing frameDoing;

    public Role(String image, Integer width, Integer height, Integer x, Integer y,Integer layout, FrameDoing frameDoing) {
        super(image, width, height, x, y,layout);
        this.frameDoing = frameDoing;
    }


    @Override
    public void doing(Component component) {
        if(this.frameDoing != null){
            frameDoing.doing(component);
        }
    }

}

有了组件的基础信息,我们就需要一个管理组件的类,因此定义了Painter类,这个类负责检查每个组件的动作,并且将图片绘制到画布上。

@Data
public class Painter {

    // 传入一个canves的绘画对象
    private Canvas canvas;
    private GraphicsContext gc;
    // 记录所有组件的List
    private List<Component> componentList;


    public Painter(Canvas canvas){
        this.canvas = canvas;
        this.gc = canvas.getGraphicsContext2D();
        this.componentList = new ArrayList<Component>();
    }

    public Painter(Canvas canvas, GraphicsContext gc){
        this.canvas = canvas;
        this.gc = gc;
        this.componentList = new ArrayList<Component>();
    }

    // 开启每一帧的动作
    public void start(int frame){
        new Thread(() -> {
            while(true) {
                checkframe();
                try {
                    Thread.sleep(1000/frame);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(() -> {
            while (true){
                paint();
                try {
                    Thread.sleep(1000/frame);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    // 检查每个角色每一帧的动作
    public void checkframe(){
        for(int i=0; i<componentList.size(); i++){
            if(componentList.get(i) instanceof Role){
                ((Role) componentList.get(i)).doing(componentList.get(i));
            }
        }
    }

    // 清空画布
    public void flush(){
        gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
    }

    // 提供一个绘制方法,可以在画布上绘图
    public void paint(){
        System.out.println("开始绘图");
        flush();
        // 根据layout等级,从小到大绘制
        int num = 0;
        // 从1开始
        int currentLayout = 1;
        while(num < componentList.size()){
            for(int i=0; i<componentList.size(); i++){
                if(componentList.get(i).getLayout() == currentLayout){
                    // 绘图
                    gc.drawImage(componentList.get(i).getImage(),
                            componentList.get(i).getPos_x(),
                            componentList.get(i).getPos_y(),
                            componentList.get(i).getWidth(),
                            componentList.get(i).getHeight());
                    num++;
                }
            }
            currentLayout++;
        }
    }

    // 往画家的组件库中添加组件
    // 返回插入列表的索引
    public Integer addComponent(Component component){
        componentList.add(component);
        return componentList.size()-1;
    }

    // 从组件库中取组件
    public Component getComponent(Integer index){
        if(this.componentList.size() == 0){
            return null;
        }
        if(index < 0){
            return componentList.get(0);
        }
        if(index >= componentList.size()){
            return componentList.get(componentList.size()-1);
        }
        return componentList.get(index);
    }
}

有了上面的信息,就需要一个主类来执行程序

public class Direct extends Application {

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        Canvas canvas = new Canvas(500,500);
        GraphicsContext gc = canvas.getGraphicsContext2D();
        Painter painter = new Painter(canvas, gc);

        // 创建组件
        Component component1 = new Role("/image/aaa.jpg", 250, 300, 0,0,1, new FrameDoing(){

            @Override
            public void doing(Component component) {
                System.out.println("第一个角色的动作");
                component.setPos_x(component.getPos_x()+5);


            }
        });
        Component component2 = new Role("/image/刻晴111.png", 100, 100, 0, 0, 2, new FrameDoing() {
            @Override
            public void doing(Component component) {
                System.out.println("第二个角色的动作");
                component.setPos_x(component.getPos_x()+10);
            }
        });

        painter.addComponent(component1);
        painter.addComponent(component2);



        Pane pane = new Pane();
        pane.getChildren().add(painter.getCanvas());
        Scene scene = new Scene(pane, 500, 500);
        primaryStage.setScene(scene);
        painter.start(20);

        primaryStage.setHeight(600);
        primaryStage.setWidth(800);
        primaryStage.show();

    }
}

如此一来,便可以运行啦。

我们创建一个角色的时候,需要传入FrameDoing的实现类,其中的参数在执行动作的时候传入的就是自己本身,这样就可以在doing(Component?component)方法中对自己的各种信息作出改变。

因此,定义一个组件就变得简单了,只需要在实例化的时候给定基本信息,然后给定重写的doing(Component?component)方法即可。

这样一来,添加组件的操作就变得简单规范啦,当然,如果要写一个比较完整的游戏还是有很多东西要做的,这只是游戏制作的很小一部分,同时也是一种代码实现思路,希望对你有所帮助。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 12:22:54  更:2022-04-04 12:23:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 20:46:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码