相信很多人都玩过太空大战,版本不一样,原理相同。没玩过的看下图了解一下: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