一步一步写自表达代码——消小球(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 }
这样就可以处理选中操作了,效果如下图所示。
-----------------------------------------------------------------
现为独立咨询师。为软件企业或者其他企业的软件采购部门提供咨询,帮助改进软件开发流程,员工技术能力提升,以帮助企业在质量成本交货期三方面得到改善。