图3-4 通过事件监听建立联系
3.5 系统数据结构设计
3.5.1 蛇、石头、食物的表示
用一个大的表格来表示显示区域,里面的格子就是组成蛇的基本单位,一个格子可以代表一个食物,也可以代表一个石头,几块连在一起的石头就可以代表一条蛇。使用坐标来区分这些格子。
图3-5 蛇、石头、食物的表示
这里用一个集合来存储这些坐标,并且要求能够区分出蛇头和蛇尾。
3.5.2 蛇的移动
蛇向前移动一步,可以看作是蛇头前面增加了一个节点,蛇的尾巴上少了一个节点(即去尾,加头)
7
图3-6 蛇的移动
3.5.3 存储蛇身的数据结构
由于要区分蛇头和蛇尾,因此这个数据结构必须是有序的。另一方面,我们需要经常的访问第一个和最后一个节点,所以LinkedList最合适。因为它有getFirst(),getLast(),和removeLast()方法。
图3-7 根据原蛇头和方向计算新蛇头的坐标
3.5.4 蛇的移动方向
蛇下一步移动到哪里,是由方向来控制的。根据原蛇头的坐标和方向来确定新蛇头的坐标,因此在这里用int型常量来表示蛇的移动方向。在原坐标的基础上,根据蛇头的运动方向来确定新蛇头的坐标,比如向上移动就是y-1。
在Snake中增加蛇的方向向量:
public static final int UP = 1;上 public static final int DOWN = -1;下 public static final int LEFT = 2;左 public static final int RIGHT = -2;右
8
3.5.5 如何显示蛇身
显示蛇身,其实就是填充,用颜色填充格子。
需要4个参数,像素坐标x,像素坐标y,格子宽度,格子高度。 像素坐标就是矩形左上角的坐标
图3-8 格子坐标和像素坐标
3.5.6 蛇身的移动方向 (1)相反方向
和上一次移动的方向相反的方向称为相反方向,这种输入应该忽略。这样可以防止蛇从自己的身体中穿过。 (2)无效方向
在蛇的这一次移动之后和下一次移动之前这个时间间隔内输入了多个非相反方向,只有最后一个是有效方向,其他的都是无效方向。
蛇的最终运动方向以有效方向为准。
(3)Snake中增加监听器,并另外启动一个线程来不断调用蛇的move(),在Snake中提供一个启动线程的方法。 3.5.7 吃到食物判定
通过判定坐标是否重合来判断,只需要判断蛇头是否和食物重合就可以了,因为蛇的身体都是走蛇头走过的地方,蛇吃掉食物后身体就会变长。在Controller的snakeMoved中添加如下代码:
/* 判断是否吃到食物 */
if (food != null && food.isSnakeEatFood(snake)) {
/* 吃到食物后, 蛇增加身体, 再重新丢一个食物 */
9
snake.eatFood();
food.setLocation(ground == null ? food.getNew() : ground
.getFreePoint());
}/* 如果吃到食物, 就肯定不会吃到石头 */
else if (ground != null && ground.isSnakeEatRock(snake)) { }
/* 如果吃到的是石头, 或吃到自己的身体, 就让蛇死掉 */ stopGame();
if (snake.isEatBody())
stopGame();
4 系统详细设计
4.1 程序设计
4.1.1 主类MainFrame
(1)主类为此程序的入口,定义了MainFrame的对象frame,开始运行此程序。
(2)源代码见文件MainFrame.Java 4.1.2 类MainFrame (1)成员变量见表4-1
表4-1 主要成员变量
成员变量描述 选项面板 游戏面板 蛇类对象 石头对象 食物对象 控制对象 速度标签 (2)方法见表4-2
变量类型 private GameOptionPanel private GamePanel private Snake private Ground private Food private Controller private JLabel 名称 optionPanel gamePanel snake ground food controller infoLabel 10
表4-2 主要方法
方法名 gameOver() gameStart() gameContinue() gamePause() 功能 游戏结束 游戏开始 游戏继续 游戏暂停 4.1.3 类Snake
(1)成员变量见表4-3
表4-3 主要成员变量
成员变量描述 上下左右(方向) 蛇体 蛇头坐标 蛇尾坐标 是否活着 是否暂停 速度 监听 (2)方法见表4-4
表4-4 主要方法
方法名 eatFood() setHeadColor() setBodyColor() changeDirection(int) move() begin() 功能 判断食物是否被蛇吃掉,如果食物在蛇运行方向的正前方,并且与蛇头接触,则被吃掉 设置蛇头的颜色 设置蛇身的颜色 改变运行方向 蛇在运行中所采取的措施 开启一个新的线程驱动蛇定时移动 变量类型 int LinkedList
(1)成员变量见表4-5
11