代码重构-以贪吃蛇为示例(四)-继续封装
程序员文章站
2022-05-21 14:00:30
...
题外话:
本人第一次写技术文章,希望寻求鼓励啊,发了四篇了一个评论还都没有,真心凉
/* -------------------------------------------------正文分隔条--------------------------------------------- */
上一节我们已经将Snake从原来的类中抽离出来,现在我们继续研究庞大的GamePanel类,继续封装其他的内容。
现在有这样一个需求:我需要提供不同大小,不同样式的地图,可能还有一些阻挡物,然后根据需要选择地图。
单单只靠GamePanel是做不到的,我们需要单独的地图类,也就是GameMap。
按照上一节的思路,下面是GameMap接口和一个简单的实现类SimpleGameMap类。
package snakes; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; /** * 贪吃蛇地图 * * @author Chris * */ public interface GameMap { /** * 绘制地图 * * @param g * 画布 */ public void draw(Graphics g); /** * 获得地图高度 * * @return */ public int getHeight(); /** * 获取一个点在地图上的位置,用作制作无边界地图 * * @param p * @return 返回一个点在地图上的位置,如果没有对应地址则返回 null */ public Point getPointOnMap(Point p); /** * 获得地图尺寸 * * @return */ public Dimension getSize(); /** * 获得地图宽度 * * @return */ public int getWidth(); /** * 判断输入点是否会装到地图墙壁 * * @param p * @return */ public boolean isAgainstWall(Point p); /** * 从地图上获取一个可行(不撞墙)的点,而且要保证此点沿着<code> direction </code>方向连续 * <code> needLength </code>个(算上本身)点也不撞墙 * * @param direction * @param needLength * @return */ public Point getAvailablePoint(Direction direction, int needLength); /** * 从地图上获取一个可行(不撞墙)的点 * * @return */ public Point getAvailablePoint(); }
package snakes; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; import java.util.Random; public class SimpleGameMap implements GameMap { private static final Random random = new Random(); private GamePanel panel; /** * 地图横向包含的单元格数 */ private int width; /** * 地图纵向包含的单元格数 */ private int height; public SimpleGameMap (GamePanel panel, int width, int height) { this.panel = panel; this.width = width; this.height = height; } @Override public void draw(Graphics g) { int sellSize = panel.getSellSize(); g.setColor(new Color(0x555555)); for (int i = 0; i < width; i++) { for (int j = 0; j < height; ++j) { g.drawRect(i * sellSize, j * sellSize, sellSize, sellSize); } } } @Override public int getHeight() { return height; } @Override public Point getPointOnMap(Point p) { if (!isAgainstWall(p)) return new Point(p); return null; } @Override public Dimension getSize() { return new Dimension(width, height); } @Override public int getWidth() { return width; } @Override public boolean isAgainstWall(Point p) { return !(p.x >= 0 && p.x < width && p.y >= 0 && p.y < height); } @Override public Point getAvailablePoint(Direction direction, int needLength) { int x = 0, y = 0; switch (direction) { case UP: x = random.nextInt(width); y = random.nextInt(height - needLength) + needLength; break; case DOWN: x = random.nextInt(width); y = random.nextInt(height - needLength); break; case LEFT: x = random.nextInt(width - needLength) + needLength; y = random.nextInt(height); break; case RIGHT: x = random.nextInt(width - needLength); y = random.nextInt(height); break; } return new Point(x, y); } @Override public Point getAvailablePoint() { return new Point(random.nextInt(width), random.nextInt(height)); } }
另外根据需要,为Direction添加了获取反方向的方法,还修改了Snake的部分逻辑。Direction比较简单,有兴趣的可以查看附件。以下是Snake修改的部分。
/** * 贪吃蛇长度 */ private volatile int length = 3; public Snake (GamePanel panel, int length) { this.length = length; this.panel = panel; initDirection(); initList(); } /** * 初始化蛇链表 */ private void initList() { snakeList = new LinkedList<Point>(); Point p = panel.getGameMap().getAvailablePoint(direction.getOpposite(), length); snakeList.add(p); for (int i = 0; i < length - 1; ++i) { p = getDirection().getPreviousPoint(p); snakeList.add(p); } } /** * 移动贪吃蛇,包括吃虫 */ public void move() { snakeList.addFirst(getDirection().getNextPoint(snakeList.getFirst())); if (isAgainstTarget()) { ++length; panel.resetTarget(); panel.increaseScore(); panel.increaseSpeed(); } else { snakeList.removeLast(); } }
下节预告:分数管理ScoreManager和速度管理SpeedManager