然后,我们实现点击小球的动作。
点击小球的时候,分为两步,第一步:选中;第二步,清除。
本章先研究选中。
首先,我们需要了解点击的小球的位置,但是,之前的设计并没有传入相关的参数。
所以我们先来重构BallActionListener
1 package org.stephen.bubblebreaker.listener; 2 3 import java.awt.event.ActionEvent; 4 import java.awt.event.ActionListener; 5 6 import org.stephen.bubblebreaker.control.EventDispatcher; 7 import org.stephen.bubblebreaker.model.Event; 8 import org.stephen.bubblebreaker.model.Game; 9 10 public class BallActionListener implements ActionListener {11 12 int x;13 int y;14 15 public BallActionListener(int x, int y) {16 this.x = x;17 this.y = y;18 }19 20 @Override21 public void actionPerformed(ActionEvent e) {22 Game.getInstance().startSelect(x, y);23 EventDispatcher.send(Event.UPDATE_BALLS);24 }25 }
这样,通过x,y就可以知道选中的位置,并且通过选中的位置,选中临近的同色小球(Game.getInstance().startSelect(int, int))。然后更新显示。
选中的处理,由于我们需要从选中点开始向四周扩散不断的寻找相邻的同色小球。所以,我们建立一个Map用来存放那些同色的小球,并用一个boolean型表示该小球是否被遍历过。
1 Mapmarked = new HashMap ();
选中处理结束的标志就是这个Map里所有的数据值都是true。
那么选中的算法就可以描述为:
1 public void startSelect(int x, int y) {2 clearMarkState();3 marked.put(y * 12 + x, false);4 Integer key = y * 12 + x;5 while (key != null) {6 markHomoNeighbor(key % 12, key / 12);7 key = getNextUnselectedKey();8 }9 }
然后实现上述需要的3个方法:
clearMarkState
1 public void clearMarkState() {2 marked.clear();3 for (Ball[] row : grid.balls) {4 for (Ball ball : row) {5 ball.marked = false;6 ball.selected = false;7 }8 }9 }
markHomoNeighbor
1 public void markHomoNeighbor(int x, int y) { 2 Ball[][] balls = grid.balls; 3 balls[y][x].marked = true; 4 balls[y][x].selected = true; 5 marked.put(y * 12 + x, true); 6 if (x > 0 && balls[y][x - 1].color.equals(balls[y][x].color)) { 7 balls[y][x - 1].marked = true; 8 if (!marked.containsKey(y * 12 + x - 1)) { 9 marked.put(y * 12 + x - 1, false);10 }11 }12 if (x < 11 && balls[y][x + 1].color.equals(balls[y][x].color)) {13 balls[y][x + 1].marked = true;14 if (!marked.containsKey(y * 12 + x + 1)) {15 marked.put(y * 12 + x + 1, false);16 }17 }18 if (y > 0 && balls[y - 1][x].color.equals(balls[y][x].color)) {19 balls[y - 1][x].marked = true;20 if (!marked.containsKey((y - 1) * 12 + x)) {21 marked.put((y - 1) * 12 + x, false);22 }23 }24 if (y < 11 && balls[y + 1][x].color.equals(balls[y][x].color)) {25 balls[y + 1][x].marked = true;26 if (!marked.containsKey((y + 1) * 12 + x)) {27 marked.put((y + 1) * 12 + x, false);28 }29 }30 }
getNextUnselectedKey
1 private Integer getNextUnselectedKey() { 2 Setset = marked.keySet(); 3 Iterator iterator = set.iterator(); 4 while (iterator.hasNext()) { 5 Integer key = iterator.next(); 6 if (marked.get(key) == false) { 7 return key; 8 } 9 }10 return null;11 }
上述代码书写过程中会产生marked,selected变量。
注:上述代码还可以采用递归调用来实现,代码更加简练。
然后就是显示处理,在原有的MainFrame.render处理中增加下列处理。
1 if (balls[y][x].selected) {2 this.balls[y][x].setBorder(BorderFactory3 .createLineBorder(Color.CYAN));4 } else {5 this.balls[y][x].setBorder(null);6 }
这样就可以处理选中操作了,效果如下图所示。