突然发现,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.youkuaiyun.com/ml3947
------------------------------------------------------------------------------------------------------------------------
最近在捣鼓着自己的个人博客。申请了一个域名和一个空间。目前博客是专注于JavaFX技术的,而且正在进行WJFXGameEngine的开发工作,申请了个GoogleCode开源项目。进度还是不错的,就是JavaFX目前的Canvas上面的效率不敢恭维。
不过我相信以后会有很大的改进的,毕竟Canvas也是在最近版本才出来的,而且在JDK 8上也有JavaFX 3D。
等我个人开发的WJFXGameEngine的游戏示例和JavaFX的软件增多后,再在文章置顶网站链接,到时候大家可以去看看。
------------------------------------------------------------