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

代码重构-以贪吃蛇为示例(四)-继续封装

程序员文章站 2022-05-21 14:00:30
...

题外话:

本人第一次写技术文章,希望寻求鼓励啊,发了四篇了一个评论还都没有,真心凉代码重构-以贪吃蛇为示例(四)-继续封装
            
    
    博客分类: 重构 重构Java贪吃蛇 


/* -------------------------------------------------正文分隔条--------------------------------------------- */


上一节我们已经将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