(此项目源码已上传至Github网站,网址为GitHub - Ran-a/Pac-man-yar)
游戏的角色分别是追赶者和吃豆人,玩家使用方向键来控制吃豆人的运动方向并吃食物,将食物吃完视为通关。吃豆人共有五次机会,若被追赶者追到,则失去一次机会,若五次机会全部用完,食物还没有被吃完,则视为游戏失败。若吃豆人吃到特殊食物,那么吃豆人将在5秒内对追赶者免疫,即碰到追赶者不会消耗机会,5秒后恢复原来的状态。游戏运行界面如下图所示。
2.1 判断人物改变方向之后是路还是墙
在玩家按了方向键之后,判断人物在该方向的下一步是路还是墙,若是路,则人物运动方向改变为玩家所按方向键所指示的方向,若是墙,则按照原来的方向继续前进。以下是关键代码。
public Boolean isPath(int x,int y){
if (x > rightBorder) {
x=leftBorder;
}else if (x < leftBorder) {
x=rightBorder;
}
return myMap[y][x]>=pathNum;
}
2.2 追赶者在地图路口处的可选择的上下左右方向中选择任意方向
在阅读了GitHub网站的一位作者(Github账号为RookieStupidCat)写的吃豆人小游戏关于该功能的代码(网址为 https://github.com/RookieStupidCat/Pac_Man/blob/master/src/pac_Man/Enemy.java)之后,使用该作者的代码实现了本项目的此功能,并将该代码再次默写到项目中。以下是关键代码。
public void randomChangeDirect(){//用于随机改变enemy的运动方向
if (GameFrame.old_myMap[this.y][this.x]==GameFrame.pointNum) {//判断是否为拐点
if (rcdstopStep) {//初始右向
if(GameFrame.old_myMap[this.y][this.x+everyStep]!=GameFrame.wallNum){//右边可通过
xStep=forwardStep-(int)(Math.random()*multiplyT)*multiplyT;//停止或继续走
}else xStep=stopStep;
}else if (xStepstopStep){//初始向下
if (GameFrame.old_myMap[this.y+everyStep][this.x]!=GameFrame.wallNum) {//下边可通过
yStep=forwardStep-(int)(Math.random()*multiplyT)*multiplyT;//停止或继续走
}else yStep=stopStep;
}else if (yStep
2.3 吃豆人与追赶者的碰撞判断
为方便读者理解,下文所提到的“坐标互换”的情况如下图所示。
在该游戏中,吃豆人和追赶者会出现坐标重合的情况,但也会出现吃豆人和追赶者坐标互换的情况。此时,虽然吃豆人和追赶者已经碰撞,但若碰撞检测条件仅仅是吃豆人和追赶者的坐标完全重合,那么会出现碰撞检测失灵的情况。在马洪博师兄的建议下,记录追赶者上一次运动的坐标,与这一次吃豆人的坐标进行对比,若两者发生互换,则符合碰撞检测的判断条件。以下是关键代码。
2.4 吃豆人吃特殊食物后一段时间内对追赶者免疫
吃豆人在吃掉特殊食物后,吃豆人在5秒内对追赶者免疫,即在该时间段内,追赶者追上吃豆人后,吃豆人不会死亡。吃豆人碰到一次追赶者之后,免疫失效,若两者没有相撞,5秒后自动失效。以下是关键代码。
//是否吃到特殊食物
boolean isEatSpe=false;
//当吃到特殊食物时,吃豆人对追赶者免疫,追赶者图片变为免疫模式enemy_0.png。
if (GameFrame.myMap[this.frame.eater.y][this.frame.eater.x] == GameFrame.speNum) {
img=Toolkit.getDefaultToolkit().getImage("image/enemy_immu.png");
isEatSpe=true;
//5秒后免疫失效,图片恢复之前的图片。
new Timer().schedule(new TimerTask() {
@Override
public void run() {
img=Toolkit.getDefaultToolkit().getImage("image/enemy.png");
isEatSpe=false;
}
},immuTime);}
move();
//当吃豆人进入免疫模式时,碰到追赶者不会死亡,在碰到一次追赶者后,被碰到的追赶者免疫模式失效,图片也恢复为原来的图片。
if (isEatSpe && frame.eater.x == frame.pursuer1.x && frame.eater.y == frame.pursuer1.y) {
System.out.println("playing");
this.frame.state="playing";
move();
img=Toolkit.getDefaultToolkit().getImage("image/enemy.png");
isEatSpe=false;
}
3.1 代码习惯
在项目编程中,应避免使用magic number;对已定义或即将定义的方法和变量应注释。
3.2 时间管理
学习和编码的时间应刻意分开,以便清楚地记录项目时间;做项目过程中,若某一功能用时较长,更应该记录所用时间。
WBS是工作分解结构(Work Breakdown Structure)的缩写。创建WBS是把项目工作按阶段可交付成果分解成较小的,更易于管理的组成部分的过程。在吃豆人游戏开始编程之前,首先创建吃豆人游戏的WBS表格,设想要实现的功能以及估算预计完成时间,每完成一个功能之后,填写实际完成时间,与预计完成时间对比,提高以后做项目估算时间的精确度。以下是吃豆人游戏的WBS表格。
一级功能 |
二级功能 |
三级功能 |
预计完成时间 |
实际完成时间 |
人的移动 |
移动轨迹 |
将地图导入游戏面板 |
30min |
23min |
判断人物改变方向之后是路还是墙。若是路,则成功改变方向,若是墙,则按照原来的方向继续前进。 |
30min |
139min |
||
按照地图路径移动 |
20min |
50min |
||
移动方向 |
键盘控制移动方向 |
30min |
76min |
|
追赶者移动 |
移动轨迹 |
判断追赶者改变方向之后是路还是墙。若是路,则成功改变方向,若是墙,则按照原来的方向继续前进。 |
10min |
15min |
按照地图路径移动 |
10min |
10min |
||
移动方向 |
在地图路口处的可选择的上下左右方向中选择任意方向 |
30min |
因花费时间太长,未记录 |
|
追赶者捉人 |
人与追赶者的碰撞判断 |
30min |
25min |
|
触发事件 |
游戏失败 |
30min |
30min |
|
食物生成 |
生成时间 |
游戏开始时生成 |
20min |
38min |
生成周期 |
只在游戏开始时生成一次,被吃后不会再次生成 |
20min |
||
生成位置 |
普通食物-按照一定的距离在地图的“路”部分生成食物。 |
30min |
||
特殊食物-游戏面板四个拐角处各一个 |
20min |
12min |
||
人吃食物 |
人与食物的碰撞判断 |
20min |
33min |
|
人吃特殊食物后一段时间内对追赶者免疫 |
30min |
54min |
||
分数统计 |
每吃一个普通食物加一分 |
20min |
19min |
|
每吃一个特殊食物加十分 |
20min |
3min |
||
通关判断 |
人将所有食物全部吃完则游戏胜利 |
30min |
46min |
|
生命消耗 |
吃豆人共五条性命,每失败一次就消耗一条性命。在五条性命都消耗完之前豆子吃完,则游戏成功。否则,游戏失败 |
显示剩余生命 |
15min |
18min |
生命消耗判定 |
15min |
27min |
||
新的生命开始后,吃豆人在上一条生命中所吃的豆不会再生。 |
20min |
|||
游戏失败判定 |
15min |
19min |
PSP是个人软件流程(Personal Software Process)的缩写。PSP是一个可用于控制、管理和改进个人工作方法的自我持续改进过程。在吃豆人游戏编程过程中,在开始某一个任务之前,记录开始时间以及对该任务的描述,若编程过程被其他事情打断,那么记录中断时间。完成该功能之后,记录结束时间。以下是作者在完成吃豆人游戏时的PSP表格。
分类 | 开始时间 | 结束时间 | 中断时间/min(s) | Δ/min(s) | 任务内容/描述 |
Preparing | 2022.11.23 10:48 | 2022.11.23 11:25 | 5 | 32 | 功能分解 |
Preparing | 2022.11.23 17:19 | 2022.11.23 17:39 | 1 | 19 | 分析技术难点以及确定开发先后次序 |
Preparing | 2022.11.23 17:43 | 2022.11.23 18:41 | 5 | 53 | 画WBS图以及WBS表格 |
Coding | 2022.11.25 20:16 | 2022.11.25 20:40 | 1 | 23 | 将地图导入游戏面板 |
Coding | 2022.11.25 20:42 | 2022.11.25 21:58 | 4 | 76 | 人移动以及键盘控制移动方向 |
Coding | 2022.11.27 17:05 | 2022.11.27 19:29 | 5 | 139 | 判断人物改变方向之后是路还是墙。 若是路,则成功改变方向,若是墙,则按照原来的方向继续前进。 |
Coding | 2022.11.27 19:31 | 2022.11.27 20:23 | 2 | 50 | 按照地图路径移动 |
Coding | 2022.11.28 10:16 | 2022.11.28 10:30 | 0 | 14 | 将用代码二进制作为元素的数组化成地图 |
Coding | 2022.11.29 20:41 | 2022.11.29 10:51 | 0 | 10 | 追赶者按照地图路径移动 |
Coding | 2022.11.29 20:52 | 2022.11.29 21:07 | 0 | 15 | 先用键盘触发事件控制追赶者, 判断追赶者改变方向后是路还是墙。 若是路,则成功改变方向,若是墙, 则按照原来的方向继续前进。 |
Coding | 2022.11.29 21:26 | 2022.11.29 21:53 | 2 | 25 | 在地图路口处的可选择的上下左右方 向中选择任意方向(未完成) |
Coding | 2022.11.30 21:06 | 2022.11.30 22:17 | 5 | 66 | 在地图路口处的可选择的上下左右方 向中选择任意方向(未完成) |
Coding | 2022.12.6 21:25 | 2022.12.6 22:16 | 5 | 46 | 在地图路口处的可选择的上下左右方 向中选择任意方向(有缺陷) |
Coding | 2023.2.23 19:43 | 2023.2.23 20:06 | 3 | 25 | 吃豆人与追赶者的碰撞判断 |
Coding | 2023.2.23 20:08 | 2023.2.23 20:40 | 2 | 30 | 游戏失败 |
Coding | 2023.2.24 14:37 | 2023.2.24 15:20 | 5 | 38 | 普通食物按照一定的距离在地图的“路”部分生成 |
Coding | 2023.2.24 15:24 | 2023.2.24 17:02 | 5 | 33 | 人与食物的碰撞判断 |
Coding | 2023.2.25 10:25 | 2023.2.25 11:15 | 4 | 46 | 通关判断 |
Coding | 2023.2.25 12:56 | 2023.2.25 13:17 | 2 | 19 | 分数统计 |
Coding | 2023.2.26 15:30 | 2023.2.26 16:01 | 3 | 28 | 多个追赶者同时运动 |
Coding | 2023.2.26 20:09 | 2023.2.26 20:24 | 0 | 15 | 特殊食物生成 |
Coding | 2023.2.27 19:39 | 2023.2.27 20:02 | 2 | 21 | 游戏暂停,游戏继续 |
Coding | 2023.2.27 20:06 | 2023.2.27 21:05 | 3 | 56 | 游戏重新开始 |
Coding | 2023.3.01 20:16 | 2023.3.01 21:13 | 3 | 54 | 人吃特殊食物后在一段时间内对追赶者免疫 |
Coding | 2023.3.02 18:55 | 2023.3.02 19:13 | 0 | 18 | 显示剩余生命 |
Coding | 2023.3.02 19:14 | 2023.3.02 19:41 | 5 | 27 | 生命消耗判定;新的生命开始后,吃豆人在上一条生命中所吃的豆不会再生。游戏失败判定 |
Coding | 2023.3.02 19:52 | 2023.3.02 20:16 | 5 | 19 | 游戏失败判定 |
非常感谢我的导师杨贵福老师,教会我们写项目之前的准备工作,帮助我形成了写项目PSP的好习惯,及时更正我的代码坏习惯。也很感谢实验室的韩亚光师兄、马洪博师兄以及田洪轩师兄帮助我调试代码,修改bug,提供思路;同时,感谢为我写吃豆人游戏提供思路的GitHub上的作者( Github账号为RookieStupidCat ),以上已经给出他的游戏项目地址。