代码重构-以贪吃蛇为示例(二)-分离入口、内部类,抽离函数
?面对这么乱的代码,第一步就是把想关性不太大的部分抽离出去。具体操作:
?
?
那么现在我们有三个文件:GameLauncher(启动程序),GamePanel(程序面板),Direction(方向类,作为工具)。
?
?
接下来我们要抽离函数。
?
首先构造函数:
?
package snakes;import java.awt.Color;import java.awt.Graphics;import java.awt.Point;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedList;import java.util.Map;import java.util.Random;import javax.swing.JOptionPane;import javax.swing.JPanel;public class GamePanel extends JPanel implements KeyListener{private static final long serialVersionUID = -7269846451378790762L;private static final Random random = new Random();/** * 分数 */private int score = 0;/** * 每一个单元格的尺寸,像素 */private final int sellSize = 20;/** * 地图横向包含的单元格数 */private final int tableWidth = 30;/** * 地图纵向包含的单元格数 */private final int tableHeight = 20;/** * 贪吃蛇的点链表 */private final LinkedList<Point> snake = new LinkedList<Point>();private final Direction[] da ={ Direction.UP, Direction.DOWM, Direction.LEFT, Direction.RIGHT };private Direction direction;/** * 虫子的位置 */private Point target = new Point(random.nextInt(tableWidth), random.nextInt(tableHeight));/** * 贪吃蛇初始长度 */private final int initsnakeLenght = 3;private final Map<Integer, Direction> keyMap = new HashMap<Integer, Direction>();/** * 移动速度 */private volatile long speed = 1;private volatile long crrTime = System.currentTimeMillis();public GamePanel (){initSnakeDirection();initKeyMap();initSnake();initGameLoop();}/** * 初始化蛇运行方向 */private void initSnakeDirection(){direction = getRandomDirection();}/** * 随机生成方向 * * @return 方向 */private Direction getRandomDirection(){return da[random.nextInt(4)];}/** * 初始化游戏线程 */private void initGameLoop(){/** * 游戏主循环线程 */new Thread(){@Overridepublic void run(){while (true){if (System.currentTimeMillis() - crrTime > 500 / speed){synchronized (GamePanel.class){moveSnake();if (!checkSnack()){JOptionPane.showMessageDialog(null, "Game Over!");return;}}repaint();crrTime = System.currentTimeMillis();}}};}.start();}/** * 初始化蛇链表 */private void initSnake(){Point p = new Point(random.nextInt(tableWidth - initsnakeLenght >> 1) + initsnakeLenght,random.nextInt(tableHeight - initsnakeLenght >> 1) + initsnakeLenght);snake.add(p);for (int i = 0; i < initsnakeLenght - 1; ++i){p = direction.getPreviousPoint(p);snake.add(p);}}/** * 初始化按键和方向的映射 */private void initKeyMap(){keyMap.put(KeyEvent.VK_UP, Direction.UP);keyMap.put(KeyEvent.VK_DOWN, Direction.DOWM);keyMap.put(KeyEvent.VK_LEFT, Direction.LEFT);keyMap.put(KeyEvent.VK_RIGHT, Direction.RIGHT);}/** * 判断贪吃蛇是否撞墙或撞到自己 * * @return */protected boolean checkSnack(){return !isAgainstWall() && !isAgainstSelf();}/** * 判断蛇头是否撞到自己的身体,是则返回true,否返回false * * @return */private boolean isAgainstSelf(){Point p = snake.getFirst();Iterator<Point> it = snake.iterator();it.next();while (it.hasNext()){Point pBody = it.next();if (p.equals(pBody)){return true;}}return false;}/** * 判断蛇头是否撞到墙壁,是则返回true,否返回false * * @return */private boolean isAgainstWall(){Point p = snake.getFirst();int x = p.x, y = p.y;return x < 0 || x >= tableWidth || y < 0 || y >= tableHeight;}@Overridepublic void keyPressed(KeyEvent e){}@Overridepublic void keyReleased(KeyEvent e){Direction newd = keyMap.get(e.getKeyCode());if (newd != null && direction.isAvailable(newd)){direction = newd;synchronized (GamePanel.class){moveSnake();if (!checkSnack()){JOptionPane.showMessageDialog(null, "Game Over!");return;}}repaint();crrTime = System.currentTimeMillis();}}@Overridepublic void keyTyped(KeyEvent e){}/** * 移动贪吃蛇,包括吃虫 */private void moveSnake(){snake.addFirst(direction.getNextPoint(snake.getFirst()));if (snake.getFirst().equals(target)){target = new Point(random.nextInt(tableWidth), random.nextInt(tableHeight));++speed;++score;}else{snake.removeLast();}}/** * 绘制图形 */@Overrideprotected void paintComponent(Graphics g){g.clearRect(0, 0, tableWidth * sellSize, tableHeight * sellSize);drawMap(g);drawSnake(g);drawTarget(g);}/** * 绘制目标点(虫子) * * @param g * 画布 */private void drawTarget(Graphics g){g.setColor(new Color(0xdd7744));g.fillRect(target.x * sellSize, target.y * sellSize, sellSize, sellSize);}/** * 绘制蛇 * * @param g * 画布 */private void drawSnake(Graphics g){drawSnakeBody(g);drawSnakeHead(g);}/** * 绘制蛇头 * * @param g * 画布 */private void drawSnakeHead(Graphics g){g.setColor(new Color(0x115599));Point p = snake.peek();g.fillRect(p.x * sellSize, p.y * sellSize, sellSize, sellSize);}/** * 绘制蛇身 * * @param g * 画布 */private void drawSnakeBody(Graphics g){g.setColor(new Color(0x3399cc));for (Point p : snake){g.fillRect(p.x * sellSize, p.y * sellSize, sellSize, sellSize);}}/** * 绘制地图 * * @param g * 画布 */private void drawMap(Graphics g){g.setColor(new Color(0x555555));for (int i = 0; i < tableWidth; i++){for (int j = 0; j < tableHeight; ++j){g.drawRect(i * sellSize, j * sellSize, sellSize, sellSize);}}}}?
?
?
下节预告:抽离Snake类
?