javafx做游戏之连连看(1)
连连看是一款非常经典的游戏。
在接下来的blog中将详细讲解javafx如何做连连看游戏。
连连看规则:任意两个Tile可以用小于等于3条线连起来,则满足消除规则。
一、功能概述:
1、支持背景音乐。
2、支持刷新、提示等高级功能。
3、支持Tiles消除动画。
二、效果图
三、在线运行地址
四、设计思路
本篇中将重点讲解Tile对象的设计:
从图中或运行效果中我们可以看出Tile包含以下属性:
1、位置(每个Tile在canvas上初始化位置不一样)
2、类型(相同类型才能连接)
3、显示图片(不同类型用不同图片显示)
4、选中特效
另外,Tile还包含以下功能:
1、选择第一个Tile时,显示选中标识,并在canvas中记录。
2、选择第二个Tile时,如果第二个Tile就是第一个Tile,则反选第一个Tile,并清空canvas中记录。
如果两个Tile不能消除,则先清除第一个Tile的相关记录,然后把第二个Tile当第一个Tile处理。
如果可以消除,则消除这两个Tile。
下面看javafx中代码实现:
public class Tile extends Parent { // 记录单元格位置 public ObjectProperty<Point> index = new SimpleObjectProperty<Point>(); // 单元格类型 public StringProperty type = new SimpleStringProperty(); // 所在画布对象 public War3Canvas canvas; // 是否可点击 public boolean clickable = true; // 用于点击后实现单元格特效 private DoubleProperty strokeAlpha = new SimpleDoubleProperty(0.0); public Timeline fade = new Timeline(); // 单元格图片 private ObjectProperty<Image> imageProperty = new SimpleObjectProperty<Image>(); // 单元格边框颜色 private ObjectProperty<Color> colorProperty = new SimpleObjectProperty<Color>(); // 用于变化两个单元格位置时临时存储Point public Point tempPoint; public Tile(final War3Canvas canvas, Point index, String type) { initArgs(); this.index.set(index); this.canvas = canvas; this.type.set(type); this.strokeAlpha.set(0); getChildren().add(create()); setOnMouseClicked(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { handleAction(); } }); } // 点击事件处理 private void handleAction() { // 不可点击,说明已经不存在了,直接返回 if (!clickable) { return; } // 第一次点击,用于选择开始连接点 if (canvas.tempStart == null) { canvas.tempStart = this; fade.setRate(10); fade.play(); return; }// 开始连接点已经选好 else { if (canvas.tempStart == this) { canvas.tempStart = null; fade.setRate(-10); fade.play(); return; } else { canvas.tempEnd = this; canvas.tempStart.fade.setRate(-10); canvas.tempStart.fade.play(); canvas.tempEnd.fade.setRate(10); canvas.tempEnd.fade.play(); // 如果类型相同,则查找连接路径 if (canvas.tempStart.getType().equals(canvas.tempEnd.getType())) { List<Point> path = canvas.findPath( canvas.tempStart.getPoint(), canvas.tempEnd.getPoint()); if (path != null) { canvas.tempStart.clickable = false; canvas.tempEnd.clickable = false; canvas.tempStart = null; canvas.tempEnd = null; canvas.drawLine(path); } else { canvas.tempStart = canvas.tempEnd; canvas.tempEnd = null; } } else { canvas.tempStart = canvas.tempEnd; canvas.tempEnd = null; } } } } private void initArgs() { index.addListener(new ChangeListener<Point>() { @Override public void changed(ObservableValue<? extends Point> observable, Point oldValue, Point newValue) { tempPoint = newValue; setTranslateX(newValue.col * (Utils.ELEMENTSIZE + 5) + 60); setTranslateY(newValue.row * (Utils.ELEMENTSIZE + 5) + 60); } }); type.addListener(new ChangeListener<String>() { @Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { Image image = new Image(Tile.class .getResourceAsStream(newValue), Utils.ELEMENTSIZE - 5, Utils.ELEMENTSIZE - 5, true, true); imageProperty.set(image); } }); strokeAlpha.addListener(new ChangeListener<Number>() { @Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { Color color = Color.color(0, 0.8, 0, newValue.doubleValue()); colorProperty.set(color); } }); KeyFrame frame1 = new KeyFrame(Duration.ZERO, new KeyValue(strokeAlpha, 0, Interpolator.LINEAR)); KeyFrame frame2 = new KeyFrame(Duration.millis(500), new KeyValue( strokeAlpha, 1, Interpolator.LINEAR)); fade.getKeyFrames().addAll(frame1, frame2); } // 生成单元格UI private Node create() { Group group = new Group(); Rectangle rec = new Rectangle(Utils.ELEMENTSIZE, Utils.ELEMENTSIZE, Color.WHITE); rec.strokeProperty().bind(colorProperty); rec.setStrokeWidth(3); rec.setArcWidth(10); rec.setArcHeight(10); ImageView view = new ImageView(); view.setTranslateX(3); view.setTranslateY(3); view.imageProperty().bind(imageProperty); group.getChildren().addAll(rec, view); return group; } public String getType() { return type.get(); } public Point getPoint() { return index.get(); } @Override public String toString() { return "[" + getPoint().row + "," + getPoint().col + "]"; } }