相信很多人都玩過太空大戰,版本不一樣,原理相同。沒玩過的看下圖瞭解一下:html
首先先分解一下游戲的構成:java
- 大批敵軍
- 子彈
- 保衛機
這三個角色之間基本的互動請看流程圖git
以上是基本的操做流程圖,具體實現的源碼將在文章最後的小結
部分給你們github
我把我認爲可能須要考慮的問題歸類以下:算法
如何實現併發?api
Runnable
和Thread
,可是咱們今天不調用Thread,只用runnable,並且不是繼承。除此以外,今天用的package不是你們常知的java.awt.*
而是javafx.scene.*
。三個角色運動狀態不一樣,如何初始化用同一個類調用?數組
public class Shape { //在這以前你須要要個最基礎的圖形構造類,除非你不想創造複雜的圖形或者直接想調用圖像 //這邊的長方形能夠理解位積木 private Rectangle[] p = new Rectangle[50]; private int number = 0; private double xPosition = 0.0; private double yPosition = 0.0; //給圖形聲明初始的位置,須要考慮一下本來圖像的尺寸,位置過高或過低都會看不到完整的圖形 public Shape(double x, double y) { this.xPosition = x; this.yPosition = y; } //把新的積木拼到原有的積木上,也能夠使用arraylist實現 public void addRectangle(Rectangle r) { if (number < p.length) { p[number] = p; number++; } } //以上都是靜態的並且不會在畫面上顯示 //addShapeTo方法幫助咱們把積木們放到屏幕裏 public void addShapeTo(GameArena a) { for (int i = 0 ; i < number; i++) { p[i].setXPosition(p[i].getXPosition() + xPosition); p[i].setYPosition(p[i].getYPosition() + yPosition); a.addRectangle(p[i]); } } //移動積木堆們,根據咱們給定的速度。積木堆們以總體的形式運動 public void move(double x, double y) { xPosition += x; yPosition += y; for (int i=0; i<numberParts; i++) { p[i].setXPosition(p[i].getXPosition() + x);//注意,在屏幕裏表示向右 p[i].setYPosition(p[i].getYPosition() + y);//注意,在屏幕裏表示向下 } } //如名字所寫,帶有目的性,表示直接移動到指定的位置 //在這邊的做用是子彈打出去後最後又回到原來的位置,由於速度很快,因此屏幕上看不到回來的效果 //感受子彈好辛苦,可是不想給子彈單獨建個數組了,麻煩子彈了... public void moveTo(double x, double y) { move(x-xPosition, y-yPosition); xPosition = x; yPosition = y; } //獲取第i個積木 public Rectangle getP(int i) { return p[i]; } //判斷兩個積木快是否相撞 boolean collides (Shape c) { for (int i=0; i<number; i++) { for (int j=0; j<c.number; j++) { if (p[i].collides(c.getP(j)))//這個調用的是Rectangle裏的方法,不是這個類裏的 return true; } } return false; } public double getXPosition() { return xPosition; } public double getYPosition() { return yPosition; } public void removeShapeFrom(GameArena a) { for (int i=0; i<number; i++) { a.removeRectangle(p[i]); } } }
小編以前說了,若是你想引用現有的圖像作你的角色....
多線程
原理和上面的代碼差很少,不拼積木確定比拼積木輕鬆的,因此咱們只要創造圖像類。
如下是小編的源碼併發
/** * @author Hephaest */ //沒錯!什麼類都沒import! public class ImageView { private double xPosition; private double yPosition; private double width; private double height; private String url; private ImageView[] part = new ImageView[100]; private int numberPart = 0; public double getXPosition() { return xPosition; } public double getYPosition() { return yPosition; } public void setXPosition(double x) { this.xPosition = x; } public void setYPosition(double y) { this.yPosition = y; } public double getWidth() { return width; } public double getHeight() { return height; } public String getUrl() { return url; } //定義圖像的時候須要位置,尺寸,還有哪裏來的圖 public ImageView(double x, double y, double w, double h, String url) { xPosition = x; yPosition = y; width = w; height = h; this.url = url; } //碰撞的算法小編沒優化 public boolean collides(ImageView i) { return (xPosition < i.xPosition + i.width && xPosition + width > i.xPosition && yPosition < i.yPosition + i.height && yPosition + height > i.yPosition); } //運動的方法和以前的一致 public void move(double x, double y) { xPosition += x; yPosition += y; for (int i=0; i<numberPart; i++) { part[i].setXPosition(part[i].getXPosition() + x); part[i].setYPosition(part[i].getYPosition() + y); } } public void moveTo(double x, double y) { move(x-xPosition, y-yPosition); xPosition = x; yPosition = y; } public void removeShapeFrom(GameArena a) { for (int i=0; i<numberPart; i++) { a.removeImage(part[i]); } } }
最後至於圖形界面框那部分,之前鼠標操控的辦法,請參考原做者的javafx
使用辦法。小編爲了利用javafx實現圖像移動絞盡腦汁。不過最終仍是找到辦法了:oracle
/** *@author Joe Finney *override by hephaest */ //用hashmap 創造ImageView的數組對象,由於ImageView是節點 private Map<ImageView, javafx.scene.image.ImageView> images = new HashMap<>(); @override private void frameUpdate () { if (!this.exiting) { // Remove any deleted objects from the scene. synchronized (this) { for (Object o: removeList) { if (o instanceof Rectangle) { Rectangle r = (Rectangle) o; javafx.scene.shape.Rectangle rectangle = rectangles.get(r); root.getChildren().remove(rectangle); rectangles.remove(r); } //我本身添加的 if (o instanceof ImageView) { ImageView i = (ImageView) o; javafx.scene.image.ImageView image = images.get(i); root.getChildren().remove(image); images.remove(i); } } removeList.clear(); // Add any new objects to the scene. for (Object o: addList) { if (o instanceof Rectangle) { Rectangle r = (Rectangle) o; javafx.scene.shape.Rectangle rectangle = new javafx.scene.shape.Rectangle(0, 0, r.getWidth(), r.getHeight()); root.getChildren().add(rectangle); rectangles.put(r, rectangle); } //我本身添加的 if (o instanceof ImageView) { ImageView i = (ImageView) o; javafx.scene.image.ImageView image = new javafx.scene.image.ImageView(i.getUrl()); root.getChildren().add(image); images.put(i, image); } } addList.clear(); } for(Map.Entry<Rectangle, javafx.scene.shape.Rectangle> entry : rectangles.entrySet()) { Rectangle r = entry.getKey(); javafx.scene.shape.Rectangle rectangle = entry.getValue(); rectangle.setTranslateX(r.getXPosition() - r.getWidth()/2); rectangle.setTranslateY(r.getYPosition() - r.getHeight()/2); rectangle.setFill(getColourFromString(r.getColour())); } //我本身添加的 for(Map.Entry<ImageView, javafx.scene.image.ImageView> entry : images.entrySet()) { ImageView i = entry.getKey(); javafx.scene.image.ImageView image = entry.getValue(); image.setTranslateX(i.getXPosition() - i.getWidth()/2); image.setTranslateY(i.getYPosition()- i.getHeight()/2); image.setImage(new Image(i.getUrl())); } } }
除此以外,addImage和removeaddImage只要改個變量名字就行了。
這幾天摸索的經驗總結:
github完整源碼連接:Thanks to finneyj
Oracle-avafx.scene.image Javadoc:javafx.scene.image