JavaFX遊戲開發–第二課 基礎遊戲架構

來源:互聯網
上載者:User

  之前有一個第一課,講精靈動畫的。那個時候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>() {@Overridepublic void handle(KeyEvent event) {onKeyPressed(event);}});getParent().getScene().setOnKeyReleased(new EventHandler<KeyEvent>() {@Overridepublic 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>() {@Overridepublic 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;@Overridepublic 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);    }    @Overridepublic void draw(GraphicsContext gc) {         gc.setFill(Color.CHOCOLATE);         gc.fillRect(getX(), getY(), getWidth(), getHeight());}@Overridepublic 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);}@Overrideprotected 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;}}@Overrideprotected 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 {@Overrideprotected void loadBefore() {setWindowSize(800, 600);}@Overrideprotected void loadEnd() {TestScreen testScreen = new TestScreen(WSystem.WIDTH, WSystem.HEIGHT);getRoot().getChildren().add(testScreen);testScreen.start();testScreen.initEvents();getScene().setFill(Color.BLACK);}@Overrideprotected 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


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.