- 浏览: 266840 次
- 性别:
- 来自: 济南
文章分类
最新评论
JavaFX游戏开发--第二课 基础游戏框架
之前有一个第一课,讲精灵动画的。那个时候JavaFX 2.2还没出来,所以那一课中根本就没有用到Canvas。
但是既然在JavaFX 2.2出来后,新增加了Canvas,那么就大不一样了。
这一章教程中,我们将在JavaFX中创建一个简单的游戏框架。
首先大家看一看结构,主要的几个类。
这一课,我们只讲基础游戏框架,所以我们只看WApplication,WSystem,WObject 和 WScreen这四个类。
由这四个类组成一个简单的游戏框架。
首先是所有的游戏Object的基类WObject:
package org.wing.jfx.game.core.component; import javafx.beans.property.BooleanProperty; import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.scene.canvas.GraphicsContext; /** * @author wing * @date 2012/8/25 */ public abstract class WObject{ protected DoubleProperty widthProperty = new SimpleDoubleProperty(0); protected DoubleProperty heightProperty = new SimpleDoubleProperty(0); protected DoubleProperty xProperty = new SimpleDoubleProperty(0); protected DoubleProperty yProperty = new SimpleDoubleProperty(0); protected BooleanProperty visibleProperty = new SimpleBooleanProperty(true); protected BooleanProperty updateProperty = new SimpleBooleanProperty(true); public WObject(double x, double y, double width, double height){ this.xProperty = new SimpleDoubleProperty(x); this.yProperty = new SimpleDoubleProperty(y); this.widthProperty = new SimpleDoubleProperty(width); this.heightProperty = new SimpleDoubleProperty(height); } public WObject(){ this.xProperty = new SimpleDoubleProperty(0); this.yProperty = new SimpleDoubleProperty(0); this.widthProperty = new SimpleDoubleProperty(0); this.heightProperty = new SimpleDoubleProperty(0); } public abstract void draw(GraphicsContext gc); public abstract void update(); public DoubleProperty widthProperty() { return widthProperty; } public double getWidth(){ return widthProperty.get(); } public void setWidth(double width){ this.widthProperty.set(width); } public DoubleProperty heightProperty() { return heightProperty; } public double getHeight(){ return heightProperty.get(); } public void setHeight(double height){ this.heightProperty.set(height); } public DoubleProperty xProperty() { return xProperty; } public double getX(){ return xProperty.get(); } public void setX(double x){ this.xProperty.set(x); } public DoubleProperty yProperty() { return yProperty; } public double getY(){ return yProperty.get(); } public void setY(double y){ this.yProperty.set(y); } public BooleanProperty visibleProperty(){ return visibleProperty; } public void setVisible(boolean isVisible){ this.visibleProperty.set(isVisible); } public boolean isVisible(){ return visibleProperty.get(); } public BooleanProperty updateProperty(){ return updateProperty; } public void setUpdate(boolean isUpdate){ this.updateProperty.set(isUpdate); } public boolean isUpdate(){ return updateProperty.get(); } public void moveX(double x){ this.xProperty.set(getX() + x); } public void moveY(double y){ this.yProperty.set(getY() + y); } public boolean isCollisionWith(WObject baseObject){ if(getX() + getWidth() > baseObject.getX() && getX() < baseObject.getX() + baseObject.getWidth() && getY() + getHeight() > baseObject.getY() && getY() < baseObject.getY() + baseObject.getHeight()){ return true; } return false; } }
这个类很简单,主要是x,y,width,height,visible,update几个属性,使用了JavaFX中可进行绑定的Property。
另外是几个简单的移动碰撞的方法。
可能以后会增加一些别的东西,但是目前这个类就是这样的。
接下来是WScreen类,这个类是继承于Canvas的,意味着这是一个容器,可以绘制的容器。由于我们的WObject并
未继承任何JavaFX的系统类,那么所有的WObject都需要在WScreen中渲染。而且还需要WScreen提供一个刷新界
面的方法。
package org.wing.jfx.game.core.screen; import java.util.ArrayList; import java.util.List; import org.wing.jfx.game.core.component.WObject; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.input.KeyEvent; import javafx.util.Duration; /** * Screen * @author wing * 2012/8/25 */ public abstract class WScreen extends Canvas { protected enum GameState {GAME_MENU, GAME_START, GAME_CONTINUE, GAME_HELP, GAME_SET,GAME_EXIT,GAME_PAUSE}; private List<WObject> mObjects = new ArrayList<WObject>(); private Timeline timeline; private KeyFrame keyFrame; private int duration = 10; protected GameState mGameState = GameState.GAME_MENU; public WScreen(double width, double height) { super(width, height); initTimeLine(); } public void initEvents(){ getParent().getScene().setOnKeyPressed(new EventHandler<KeyEvent>() { @Override public void handle(KeyEvent event) { onKeyPressed(event); } }); getParent().getScene().setOnKeyReleased(new EventHandler<KeyEvent>() { @Override public void handle(KeyEvent event) { onKeyReleased(event); } }); } protected abstract void onKeyPressed(KeyEvent event); protected abstract void onKeyReleased(KeyEvent event); /** * add the object * @param baseObject the object to be add */ public void addObject(WObject baseObject){ this.mObjects.add(baseObject); } /** * remove the object * @param baseObject the object to be remove */ public void removeObject(WObject baseObject){ this.mObjects.remove(baseObject); } /** * remove the object with the index * @param index the index of the object */ public void removeObjectAtIndex(int index){ this.mObjects.remove(index); } /** * draw the objects * @param gc */ public void draw(GraphicsContext gc){ gc.clearRect(0, 0, getWidth(), getHeight()); for (int i = 0; i < mObjects.size(); i++) { WObject wObject = mObjects.get(i); if (wObject.isVisible()) { wObject.draw(gc); } } } /** * update all the objects */ public void update(){ for (int i = 0; i < mObjects.size(); i++) { WObject wObject = mObjects.get(i); if (wObject.isUpdate()) { mObjects.get(i).update(); } } } /** * init the timeline */ private void initTimeLine() { timeline = new Timeline(); timeline.setCycleCount(Timeline.INDEFINITE); keyFrame = new KeyFrame(Duration.millis(duration), new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent arg0) { draw(getGraphicsContext2D()); update(); } }); timeline.getKeyFrames().add(keyFrame); } /** * start the update timeline */ public void start(){ timeline.play(); } /** * pause the update timeline */ public void pause(){ timeline.pause(); } /** * stop the update timeline */ public void stop(){ timeline.stop(); } }
由上面的代码可见,我们包含一个游戏状态的枚举(目前没有用到),一个WObject的列表。然后通过创建一个无
限循环的Timeline来进行所有的WObject的绘制和刷新(可能有更好的方法,但目前这个游戏框架中暂时这样做)。
同时可以进行timeline的控制。
同样的,这里也暂时只提供了KeyPressed和KeyReleased两个事件方法,不过鼠标的事件添加也是很简单的。
下面看看WSystem,这个类暂时很简单,只是记录窗口的大小的类。因为只是简单的框架,其他的东西可能在后续
添加进去。
一般来说使用公共静态变量之类的并不符合Java规范,不过要纠结于此的话,可以将它更改为单例模式,并赋予一
些set get方法。
public class WSystem { public static int WIDTH = 800, HEIGHT = 600; public static void init(int width, int height){ WIDTH = width; HEIGHT = height; } }
再下面看看WApplication,这个是继承与JavaFX中的Application类,作为应用程序的启动类,JavaFX的这个游戏框
架中,任何示例的主类都需要继承WApplication。
package org.wing.jfx.game.core; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.stage.Stage; public abstract class WApplication extends Application { private Group mGroup; private Scene mScene; @Override public void start(Stage primaryStage) throws Exception { loadBefore(); mGroup= new Group(); mScene = new Scene(mGroup, WSystem.WIDTH, WSystem.HEIGHT); loadEnd(); showStage(primaryStage); } protected abstract void loadBefore(); protected abstract void loadEnd(); protected void showStage(Stage stage){ stage.setScene(mScene); stage.show(); } protected Scene getScene(){ return mScene; } protected Group getRoot(){ return mGroup; } public void setWindowSize(int width, int height){ WSystem.init(width, height); } }
这里的方法也是很容易理解的。
那么,我们就来看看如何使用这个简单的框架来构造JavaFX程序吧。
首先我们创建一个Rect继承WObject,这样会出现两个需要实现的方法:draw 和 update。
我们这里就简单的画一个矩形,然后在update方法进行移动。
package org.wing.jfx.game.test; import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; import org.wing.jfx.game.core.component.WObject; public class Rect extends WObject { public Rect(double x, double y, double width, double height){ super(x, y, width, height); } @Override public void draw(GraphicsContext gc) { gc.setFill(Color.CHOCOLATE); gc.fillRect(getX(), getY(), getWidth(), getHeight()); } @Override public void update() { moveX(1); } }
这就是这个框架中自己实现的一个简单的Object。
然后创建一个自己的Screen。命名为TestScreen,然后继承WScreen。
当然,只出现了两个Key事件的方法,我们可以在TestScreen中创建上面的Rect,然后添加到TestScreen中,再通
过Key事件来进行控制。
package org.wing.jfx.game.test; import javafx.scene.input.KeyEvent; import org.wing.jfx.game.core.WSystem; import org.wing.jfx.game.core.screen.WScreen; public class TestScreen extends WScreen { private Rect player; public TestScreen(double width, double height) { super(width, height); player = new Rect(50, 50, 100, 100); addObject(player); } @Override protected void onKeyPressed(KeyEvent event) { switch (event.getCode()) { case UP: player.moveY(-1); break; case DOWN: player.moveY(1); break; case ENTER: addObject(new Rect(Math.random() * WSystem.WIDTH, Math.random() * WSystem.HEIGHT, 100, 100)); break; default: break; } } @Override protected void onKeyReleased(KeyEvent event) { } }
如上面的代码所示,我们在构造函数中创建了一个坐标50,50 宽 100 高 100 的Rect。然后在事件处理中,上下控
制Rect的移动,通过Enter键,在屏幕上随机增加一个Rect。
由于我们在Rect的Update方法中增加了Move的操作,所以所有的Rect将一直往右移动。
下面创建我们的主类MainClass继承WApplication:
package org.wing.jfx.game.test; import javafx.scene.paint.Color; import javafx.stage.Stage; import org.wing.jfx.game.core.WApplication; import org.wing.jfx.game.core.WSystem; public class MainClass extends WApplication { @Override protected void loadBefore() { setWindowSize(800, 600); } @Override protected void loadEnd() { TestScreen testScreen = new TestScreen(WSystem.WIDTH, WSystem.HEIGHT); getRoot().getChildren().add(testScreen); testScreen.start(); testScreen.initEvents(); getScene().setFill(Color.BLACK); } @Override protected void showStage(Stage stage){ super.showStage(stage); stage.setTitle("JavaFX游戏开发 第二课 基础游戏框架"); } public static void main(String[] args) { launch(args); } }
这个就是我们的主类了,我们在loadBefore中设定了窗口的大小,在loadEnd中创建了TestScreen,启动了
TestScreen的循环Timeline,载入了TestScreen的事件,并设定场景背景为黑色,然后重写了父类的showStage方法
修改了程序的标题。
后面的就是用这个简单的游戏框架创建的简单的程序了,只要整个框架搭建好,后面每次进行游戏开发的时候,就
可以节省很多的代码量了。
运行结果倒是不怎样,不过我们在这一章中,主要是构建了游戏框架。
在下一章中,我们会增加动画精灵以及地图的绘制。
转载请注明出处:http://blog.csdn.net/ml3947
相关推荐
javafx-sdk-17.0.2-lts-windows-x64
Java11以后的版本不再集成Javafx,需要单独下载
linux系统下,可用如下两命令运 行 javafx 的 jar包 export JAVAFX=/home/这里是linux的用户名文件夹/javafx-sdk-18/lib java --module-path $JAVAFX --add-modules javafx.fxml,javafx.controls -jar demo.jar 或都...
javaFX-jps-plugin.jar
javaFx 学习--之布局菜单
javafx_sdk-2_2_21-windows-i586
JavaFX11,让你使用java快速开发桌面软件,版本为11.0.2,windows操作系统.我博客内有对应教程.
javaFx 学习--入门示例程序的源码
javaFx 学习--之Adding Dynamic Behavior(加动态特性源码)
luke-javafx-7.3.1-luke-release.zip,luke-javafx-7.3.1-luke-release.zip
javafx使用指南-目录版.pdf
javafx-commons-2.0.1
NULL 博文链接:https://angkor.iteye.com/blog/410382
javafx-rest-archetype.zip,javafx基本原型提供了一个maven原型,用于生成基本javafx rest客户机服务器启动程序
JavaFX的Maven原型Maven原型,用于创建不同类型的JavaFX应用程序。 该项目是一个多模块Maven项目。 每个模块都包含一个用于创建JavaFX应用程序的原型。 通过原型创建的所有项目都使用来编译和运行JavaFX应用程序。...
javaFx 学习--之组件篇1(边框与布局管理1Label)
javafx_sdk-2_2_7-windows-i586
javafx-sdk-13.0.2.JavaFX is a set of graphics and media packages that enables developers to design, create, test, debug, and deploy rich client applications that operate consistently across diverse ...
13. JavaFX Scene Builder- Getting Started with JavaFX Scene Builder.pdf
利用javafx绘制动画风扇图,提供pause、reverse、resume按钮