突然发现,JavaFX游戏开发的教程好久没有更新了...
不过没关系,以后更新的可能会频繁一点.
下面我们来进行JavaFX打砖块游戏开发第三课。
在上一课里面,我们创建了一个鼠标控制的挡板。和一个在屏幕上四处弹的小球。
这一课里面,我们将会增加一些砖块等等的。
事先声明,这里我们不会涉及到算法问题。也就是说,游戏中使用的都是最简单最基本的,而且肯定是会有很多的问题。大家可以自行修改,或者我在后面会专门开一篇文章讲解。
首先我们建立一个砖块类。
import javafx.geometry.Bounds; import javafx.scene.effect.BoxBlur; import javafx.scene.effect.Lighting; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; public class Brick extends BaseObject { private Rectangle mRectangle; private int hp; private BoxBlur mBlur; public Brick(Color color, int hp) { this.hp = hp; this.mRectangle = new Rectangle(); this.mRectangle.widthProperty().bindBidirectional(widthProperty()); this.mRectangle.heightProperty().bindBidirectional(heightProperty()); this.mRectangle.xProperty().bindBidirectional(xProperty()); this.mRectangle.yProperty().bindBidirectional(yProperty()); this.mRectangle.setFill(color); this.mBlur = new BoxBlur(); this.mBlur.setWidth(5); this.mBlur.setHeight(5); this.mRectangle.setEffect(new Lighting()); setWidth(100); setHeight(25); getChildren().add(this.mRectangle); } public Bounds getBounds() { return this.mRectangle.getLayoutBounds(); } public int getHp() { return this.hp; } public void setHp(int hp) { this.hp = hp; } }
很简单的,其实就是一个矩形,包含了一个Blur的效果,和一个HP的属性。我们将矩形的属性与object的属性进行绑定,这样,我们操作object就是操作矩形了。
接下来,创建一个关卡load的类。
import javafx.scene.paint.Color; public class LevelLoader { private static int[][] level1 = { { 0, 1, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 0 }, { 0, 1, 1, 1, 1, 1, 0 } }; public static void load(GameScene scene, int level) { int[][] datas = getLevel(level); for (int i = 0; i < datas.length; i++) for (int j = 0; j < datas[0].length; j++) if (datas[i][j] != 0) { Brick brick = new Brick(Color.RED, datas[i][j]); brick.setWidth(108.0D); brick.setX((760- 7 * brick.getWidth()) / 2.0D + j * (brick.getWidth())); brick.setY(i * (brick.getHeight()) + 100); scene.addChild(brick); scene.getBricks().add(brick); } } public static int[][] getLevel(int i) { if (i == 1) { return level1; } return (int[][])null; } }
这里,我们通过一个二维数组来摆放砖块的位置。GameScene是我们的游戏场景,当然也经过了很多的修改。这里砖块的HP值,根据二维数组里的值来确定。大家也可以将砖块的颜色与值绑定,同样能直接通过一个二维数据来确定砖块的种类和HP值。
接下来,我们来看看场景GameScene类:
import java.util.concurrent.CopyOnWriteArrayList; import javafx.animation.FadeTransition; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Parent; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.util.Duration; public class GameScene extends Parent { private int width; private int height; private Rectangle background; private MainBrick mainBrick = new MainBrick(); private Ball ball = new Ball(15, 15, 15); private Timeline timeline; private KeyFrame keyFrame; private CopyOnWriteArrayList<Brick> bricks = new CopyOnWriteArrayList<>(); public GameScene(int width, int height) { this.width = width; this.height = height; initGameObjects(); initTimeLine(); initLevel(); } private void initGameObjects() { this.background = new Rectangle(0.0D, 0.0D, this.width, this.height); this.background.setOnMouseMoved(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { mainBrick.onMouseMove(event); } }); this.background.setFill(Color.BLACK); this.mainBrick.setX(0.0D); this.mainBrick.setY(this.height - this.mainBrick.getHeight()); this.ball.setX((this.mainBrick.getWidth() - this.ball.getWidth()) / 2.0D); this.ball.setY(this.height - this.mainBrick.getHeight() - this.ball.getHeight()); getChildren().add(this.background); getChildren().add(this.mainBrick); getChildren().add(this.ball); } private void initTimeLine() { this.timeline = new Timeline(); this.timeline.setCycleCount(-1); this.keyFrame = new KeyFrame(Duration.millis(5.0D), new EventHandler<ActionEvent>() { public void handle(ActionEvent arg0) { ball.moveX(ball.getSpeedX()); ball.moveY(ball.getSpeedY()); if ((ball.getX() <= 0.0D) || (ball.getX() >= 800.0D - ball.getWidth())) { ball.setSpeedX(-ball.getSpeedX()); } if ((ball.getY() <= 0.0D) || (ball.getY() >= 600.0D - ball.getHeight())) { ball.setSpeedY(-ball.getSpeedY()); } if (ball.isCollisionWith(mainBrick)) { ball.setSpeedY(-ball.getSpeedY()); } for (Brick brick : bricks) { if (ball.isCollisionWith(brick)) { brick.setHp(brick.getHp() - 1); ball.setSpeedY(-ball.getSpeedY()); if (brick.getHp() <= 0) { destroyObject(brick); } break; } } } }, new KeyValue[0]); this.timeline.getKeyFrames().add(this.keyFrame); this.timeline.play(); } private void destroyObject(final BaseObject brick) { FadeTransition fade = new FadeTransition(Duration.millis(200.0D), brick); fade.setFromValue(1.0D); fade.setToValue(0.0D); fade.setOnFinished(new EventHandler<ActionEvent>() { public void handle(ActionEvent t) { getChildren().remove(brick); } }); this.bricks.remove((Brick) brick); fade.play(); } private void initLevel() { LevelLoader.load(this, 1); } public void addChild(Parent parent) { getChildren().add(parent); } public CopyOnWriteArrayList<Brick> getBricks() { return this.bricks; } }
GameScene里包含了一个brick砖块的集合。我们鼠标控制的挡板MainBrick和一个小球Ball。
我们通过创建一个时间轴,在帧中进行小球的移动,碰撞判断。
每次碰撞brick的hp就减一,当hp小于或等于0时,执行destroyobject方法。这个方法通过对brick执行一个FadeTransition,让它进行一个渐变的消失。然后从集合中移除。
大家可以看看效果:
当然,这里的碰撞会有问题。然后与挡板的碰撞,也没有进行角度等的判断。不过没关系,这些都可以在以后解决。
我们首先要完成的是整个游戏的流程。
下一课里,我们将会创建游戏菜单,然后进行关卡的完成得分等。
转载请注明出处: http://blog.csdn.net/ml3947
------------------------------------------------------------------------------------------------------------------------
最近在捣鼓着自己的个人博客。申请了一个域名和一个空间。目前博客是专注于JavaFX技术的,而且正在进行WJFXGameEngine的开发工作,申请了个GoogleCode开源项目。进度还是不错的,就是JavaFX目前的Canvas上面的效率不敢恭维。
不过我相信以后会有很大的改进的,毕竟Canvas也是在最近版本才出来的,而且在JDK 8上也有JavaFX 3D。
等我个人开发的WJFXGameEngine的游戏示例和JavaFX的软件增多后,再在文章置顶网站链接,到时候大家可以去看看。
------------------------------------------------------------