- 浏览: 6361 次
- 性别:
- 来自: 北京
最新评论
-
yanhuadesan:
写的相当不错,正好今天我也在写这个来着,学习了
代码重构-以贪吃蛇为示例(五)-封装Scoring和SpeedManager
面对这么乱的代码,第一步就是把想关性不太大的部分抽离出去。具体操作:
- Direction类可以从原来文件中取出,放到同一个包下;
- 将main函数提出,放到GameLauncher.java中;
- 将原来的Game类改为GamePanel,作为游戏的面板;
那么现在我们有三个文件:GameLauncher(启动程序),GamePanel(程序面板),Direction(方向类,作为工具)。
接下来我们要抽离函数。
首先构造函数:
public GamePanel () { 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 (GamePanel.class) { moveSnake(); if (!checkSnack()) { JOptionPane.showMessageDialog(null, "Game Over!"); return; } } repaint(); crrTime = System.currentTimeMillis(); } } }; }.start(); }
这里做了三个事情:初始化按键和方向的映射,初始化蛇的链表,开启游戏线程。其实还有一件事应该放在这里,就是初始化蛇的方向,我们作为第四件事。按照这个方式我们抽取4个函数:initKeyMap,initSnake,initGameLoop,getRandomDirection。
现在代码是这样:
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() { @Override public 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); }
接下来是checkSnake
/** * 判断贪吃蛇是否撞墙或撞到自己 * * @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; }
这个函数做了两件事:检查是否碰到墙壁,检查是否和自己相撞。可以抽取两个函数 isAgainstWall和isAgainstSelf:
/** * 判断贪吃蛇是否撞墙或撞到自己 * * @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; }
最后看一下paintComponent这复杂的大函数:
/** * 绘制图形 */ @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); }
首先清空一下画布,然后画了整个的表格(可以说是地图),花蛇身和蛇头,最后画目标点(也就是虫子)。
/** * 绘制图形 */ @Override protected 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); } } }
总体代码预览:
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() { @Override public 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; } @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 (GamePanel.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.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类
发表评论
-
代码重构-以贪吃蛇为示例(五)-封装Scoring和SpeedManager
2012-10-21 22:50 987继续题外话: 上一篇忘记发布到博客频道了,都没有人看到,这次 ... -
代码重构-以贪吃蛇为示例(四)-继续封装
2012-10-19 10:55 730题外话:本人第一次写技术文章,希望寻求鼓励啊,发了四篇了一个评 ... -
代码重构-以贪吃蛇为示例(三)-封装Snake
2012-10-17 15:44 1584通过上一节的分离我们可以使程序的流程更清楚,但是这些功能还是冗 ... -
代码重构-以贪吃蛇为示例(一)-重构之前
2012-10-16 15:56 976题外话: 今天中午做到电脑前没事干,就写个贪吃蛇游戏,写着写 ... -
代码重构-以贪吃蛇为示例(序)
2012-10-16 15:22 909在正文之前,先说点题外话。 首先,作为一名学习了2年Ja ...
相关推荐
NULL 博文链接:https://chrisbing.iteye.com/blog/1700581
NULL 博文链接:https://chrisbing.iteye.com/blog/1700345
NULL 博文链接:https://chrisbing.iteye.com/blog/1702680
13--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码13--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码13--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码13...
2--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码2--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码2--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码2--...
41--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码41--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码41--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码41...
54--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码54--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码54--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码54...
1--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码1--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码1--[贪吃蛇].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码1--...
8--[贪吃蛇大作战].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码8--[贪吃蛇大作战].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码8--[贪吃蛇大作战].zip源码scratch2.0 3.0编程项目源文件源码...
本文为51单片机项目实战---贪吃蛇,附有原理图和程序代码,希望对你的学习有所帮助。
Android示例程序Snake贪吃蛇代码 http://blog.csdn.net/manp1212/article/details/7692020
贪吃蛇是一款经典的游戏,本资源中包含实现这个游戏的VC++源代码!
本资源包含完整的C语言版的小游戏“贪吃蛇”的源代码。读者可以自行下载,推荐使用Dev-C++来进行演示。希望可以满足读者的需要。代码之路,无穷无尽。加油!!!!!!!!!!!
javaweb毕业设计-JAVA贪吃蛇游戏毕业设计(源代码+lw)(可做课程设计).rarjavaweb毕业设计-JAVA贪吃蛇游戏毕业设计(源代码+lw)(可做课程设计).rarjavaweb毕业设计-JAVA贪吃蛇游戏毕业设计(源代码+lw)(可做课程设计)....
cocos creator 项目源码--类贪吃蛇,贪吃蛇大作战这种,源码仅供参考
C语言--贪吃蛇相关PPT
cocos2dx实现的简单贪吃蛇游戏,包含代码和资源
C语言作业-C语言贪吃蛇小游戏C语言作业-C语言贪吃蛇小游戏C语言作业-C语言贪吃蛇小游戏C语言作业-C语言贪吃蛇小游戏C语言作业-C语言贪吃蛇小游戏C语言作业-C语言贪吃蛇小游戏C语言作业-C语言贪吃蛇小游戏C语言作业-...
cocos2d-x 贪吃蛇源代码!
这是一个用cocos2d-x3.14和vs2013编译的简单贪吃蛇代码。