一步一步写自表达代码——消小球(3)

然后,我们实现点击小球的动作。

点击小球的时候,分为两步,第一步:选中;第二步,清除。

本章先研究选中。

首先,我们需要了解点击的小球的位置,但是,之前的设计并没有传入相关的参数。

所以我们先来重构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     @Override
21     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 Map<Integer, Boolean> marked = new HashMap<Integer, Boolean>();

选中处理结束的标志就是这个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         Set<Integer> set = marked.keySet();
 3         Iterator<Integer> 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(BorderFactory
3                             .createLineBorder(Color.CYAN));
4                 } else {
5                     this.balls[y][x].setBorder(null);
6                 }

这样就可以处理选中操作了,效果如下图所示。

posted @ 2012-11-27 15:38  史蒂芬.王  阅读(218)  评论(0编辑  收藏  举报