欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

代码重构-以贪吃蛇为示例(一)-重构之前

程序员文章站 2022-05-21 14:06:01
...

题外话:

今天中午做到电脑前没事干,就写个贪吃蛇游戏,写着写着就发现变量太多了,函数调用太乱了,逻辑越来越混乱,于是就想重构一下。但是有想一想,干脆把重构的过程记录下来,大家也分享分享,还能提高一下知名度,何乐而不为呢?

所以……所以……我硬着头皮在不重构的情况下写完了一个简单的贪吃蛇(WTF!)

 

 

/*--------------------------------------------无耻的分隔栏----------------------------------------------------- */

 

介绍下功能:

Swing组件完成的贪吃蛇游戏,通过键盘的方向键改变方向,吃到虫子增长长度,每吃掉一个虫子,移动速度会增长,撞到四周或者自己提示游戏结束。记录分数(但是没显示,因为不重构写不下去了),没有重新游戏(留到重构以后再写)。

 

界面:

代码重构-以贪吃蛇为示例(一)-重构之前
            
    
    博客分类: 重构 重构Java贪吃蛇 

 

(恐怖的)代码:

 

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.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class Game extends JPanel implements KeyListener {

	/**
	 * 贪吃蛇行走的方向
	 */
	enum Direction {
		UP {
			@Override
			public Point getNextPoint(Point p) {
				return new Point(p.x, p.y - 1);
			}

			@Override
			public Point getPreviousPoint(Point p) {
				return new Point(p.x, p.y + 1);
			}

			@Override
			public boolean isAvailable(Direction d) {
				if (d == Direction.UP || d == Direction.DOWM) {
					return false;
				}
				return true;
			}
		},
		DOWM {
			@Override
			public Point getNextPoint(Point p) {
				return new Point(p.x, p.y + 1);
			}

			@Override
			public Point getPreviousPoint(Point p) {
				return new Point(p.x, p.y - 1);
			}

			@Override
			public boolean isAvailable(Direction d) {
				if (d == Direction.UP || d == Direction.DOWM) {
					return false;
				}
				return true;
			}
		},
		LEFT {
			@Override
			public Point getNextPoint(Point p) {
				return new Point(p.x - 1, p.y);
			}

			@Override
			public Point getPreviousPoint(Point p) {
				return new Point(p.x + 1, p.y);
			}

			@Override
			public boolean isAvailable(Direction d) {
				if (d == LEFT || d == RIGHT) {
					return false;
				}
				return true;
			}
		},
		RIGHT {
			@Override
			public Point getNextPoint(Point p) {
				return new Point(p.x + 1, p.y);
			}

			@Override
			public Point getPreviousPoint(Point p) {
				return new Point(p.x - 1, p.y);
			}

			@Override
			public boolean isAvailable(Direction d) {
				if (d == LEFT || d == RIGHT) {
					return false;
				}
				return true;
			}
		};
		/**
		 * 沿此方向的下一个点
		 * @param p
		 * @return
		 */
		public abstract Point getNextPoint(Point p);

		/**
		 * 沿此方向的上一个点
		 * @param p
		 * @return
		 */
		public abstract Point getPreviousPoint(Point p);

		/**
		 * 可以转动的方向
		 * @param d
		 * @return
		 */
		public abstract boolean isAvailable(Direction d);
	}

	private static final long serialVersionUID = -7269846451378790762L;
	private static final Random random = new Random();

	public static void main(String[] args) {
		JFrame j = new JFrame("贪吃蛇");
		Game contentPane = new Game();
		j.setContentPane(contentPane);
		j.addKeyListener(contentPane);
		j.setBounds(20, 20, 700, 500);
		j.setVisible(true);
		j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	/**
	 * 分数
	 */
	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 = da[random.nextInt(4)];

	/**
	 * 虫子的位置
	 */
	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 Game() {

		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);
		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);
		}

		/**
		 * 游戏主循环线程
		 */
		new Thread() {

			@Override
			public void run() {
				while (true) {
					if (System.currentTimeMillis() - crrTime > 500 / speed) {
						synchronized (Game.class) {

							moveSnake();
							if (!checkSnack()) {
								JOptionPane.showMessageDialog(null,
										"Game Over!");
								return;
							}
						}
						repaint();
						crrTime = System.currentTimeMillis();
					}

				}
			};
		}.start();
	}

	/**
	 * 判断贪吃蛇是否撞墙或撞到自己
	 * @return
	 */
	protected boolean checkSnack() {
		Point p = snake.getFirst();
		int x = p.x, y = p.y;
		if (x < 0 || x >= tableWidth || y < 0 || y >= tableHeight) {
			return false;
		}
		Iterator<Point> it = snake.iterator();
		it.next();
		while (it.hasNext()) {
			Point pBody = it.next();
			if (p.equals(pBody)) {
				return false;
			}
		}
		return true;

	}

	@Override
	public void keyPressed(KeyEvent e) {
	}

	@Override
	public void keyReleased(KeyEvent e) {
		Direction newd = keyMap.get(e.getKeyCode());
		if (newd != null && direction.isAvailable(newd)) {
			direction = newd;
			synchronized (Game.class) {
				moveSnake();
				if (!checkSnack()) {
					JOptionPane.showMessageDialog(null, "Game Over!");
					return;
				}
			}
			repaint();
			crrTime = System.currentTimeMillis();
		}
	}

	@Override
	public 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();
		}
	}

	/**
	 * 绘制图形
	 */
	@Override
	protected void paintComponent(Graphics g) {
		g.setColor(new Color(0x555555));
		g.clearRect(0, 0, tableWidth * sellSize, tableHeight * sellSize);
		for (int i = 0; i < tableWidth; i++) {
			for (int j = 0; j < tableHeight; ++j) {
				g.drawRect(i * sellSize, j * sellSize, sellSize, sellSize);
			}
		}
		g.setColor(new Color(0x3399cc));
		for (Point p : snake) {
			g.fillRect(p.x * sellSize, p.y * sellSize, sellSize, sellSize);
		}
		g.setColor(new Color(0x115599));
		Point p = snake.peek();
		g.fillRect(p.x * sellSize, p.y * sellSize, sellSize, sellSize);
		g.setColor(new Color(0xdd7744));
		g.fillRect(target.x * sellSize, target.y * sellSize, sellSize, sellSize);

	}

}
 

下节预告:拆分文件