泡泡堂游戏开发 (Python Project)
源码链接
–> 泡泡堂游戏GitHub地址,记得随手给个star~
概述
在本次python的项目中,我们小组顺利的完成了游戏泡泡堂的基本功能,总代码量接近5k行,并在游戏泡泡堂的基本功能上实现了创新和拓展。选择泡泡堂作为python课程的项目题目是因为泡泡堂这一游戏,本身被多数玩家青睐,自2003年泡泡堂创建至今,泡泡堂就一直流行于中国甚至世界。因此,在学习了python基础之后,我们小组选择实现泡泡堂这个游戏,在实现过程中能帮助我们更好地掌握python,了解python相关的工具和环境,理解python的特性。在实现方面,泡泡堂有很大的扩展空间,在各个功能模块上面也容易区分开来,整个项目能够由简到繁,使得小组内的每个成员能够很好的完成自己的工作。
功能
游戏截图
AI设计
这篇博客将与大家分享BNB项目过程中的AI设计,AI模块设计代码量394行。所分享的内容仅为此次BNB项目AI设计的重点部分,要想设计出一个较为完整的AI还需要许多的功能和长时间的Debug。下面将依次介绍设计过程中的重点部分,非常欢迎各位博友一起讨论。
a) 设计思路
b) 计算安全区域
c) 判断当前位置放泡泡是否安全
d) 寻找路径
e) 按照路径移动
AI设计流程图
设计思路
我们希望游戏中的AI能够存活足够长的时间,并且能够在此基础上开辟通到玩家的路径,离玩家越来越近,当与玩家足够接近时尝试放泡泡将玩家炸死。游戏中的AI能够首先根据周围的地形、整体的局势来决定下一步该怎么做。AI将会根据环境来计算出一个合适的路径,接着根据路径移动,在每一步移动中都会刷新路径,达到AI实时反应的效果。
为达到这个目标,AI在每一步行动中会采取如下策略。
a) 计算安全区域和危险区域。
b) 计算玩家位置。
c) 寻找AI到达玩家的路径,同时判定AI与玩家是否连通。
d) 判断AI当前的位置是否安全。
e) 若AI当前位置危险,规避泡泡,计算路径。
否则若AI与玩家不连通,炸箱子,计算路径。
否则若AI与玩家连通,攻击玩家,计算路径。
f) 判断AI是否需要推箱子。若AI需要推箱子,则推箱子,计算路径。
g) 根据路径移动
def control(self):
"""运行AI"""
self.compute_safe_region()
self.compute_player_pos()
self.find_path("JudgeReachable")
self.judge_evade()
if self.evade:
self.find_path("EvadeBubble")
elif not self.attack:
self.find_path("FindBox")
else:
self.find_path("FindPlayer")
self.judge_push()
if self.push:
self.find_path("PushBox")
self.move()
self.kill()
计算安全区域
AI运行的第一步就是计算安全区域。先说明在此函数中定义的数据结构,record是一个二维列表,表示当前的地图情况,列表中存储布尔类型,True为可走,False为不可走。那么哪些地方是可走的、哪些地方是不可走的呢?在我们的地图中,如果某个格子有障碍物或超出了边界,那么这个格子当然是不可走的,为False。还有一种情况的格子也是不可走的,就是有水柱的格子和即将出现水柱的格子。除此之外其它格子为安全格子。
def compute_safe_region(self):
"""计算安全区域与危险区域,存储在record中"""
delay = 10
for i in range(1, self.screen_x + 1):
for j in range(1, self.screen_y + 1):
if self.plat.f1[i][j] == None or isinstance(self.plat.f1[i][j], Prop):
if self.record_count[i][j] >= delay:
self.record[i][j] = True
self.record_count[i][j] = 0
else:
self.record_count[i][j] += 1
else:
self.record[i][j] = False
self.record_count[i][j] = 0
for i in range(1, self.screen_x + 1):
for j in range(1, self.screen_y + 1):
if type(self.plat.f1[i][j]) == Bubble or type(self.plat.f1[i][j]) == TimingBubble:
# 对泡泡四个方向的水柱区域
for k in range(0, self.plat.f1[i][j].field + 1):
if j - k >= 1:
self.record[i][j - k] = False
self.record_count[i][j - k] = 0
if j + k <= self.screen_y:
self.record[i][j + k] = False
self.record_count[i][j + k] = 0
if i - k >= 1:
self.record[i - k][j] = False
self.record_count[i - k][j] = 0
if i + k <= self.screen_x:
self.record[i + k][j] = False
self.record_count[i + k][j] = 0
判断当前位置放泡泡是否安全
这个函数是为了让AI不炸死自己而设计的。函数的功能为判断当前位置放泡泡是否安全。在该函数中,我定义了两种数据,一个是若放泡泡,泡泡波及的范围,另一个是若放泡泡,AI的逃脱范围。在逃脱范围的十字中,若存在一个拐角,那么AI是能够逃脱的。此外,若在泡泡波及范围之外有安全的区域,则AI也是能够逃脱的。其它情况都是不能逃脱的。
def try_bubble(self, x, y):
"""
判断当前位置放泡泡是否安全
spout_range 表示若放泡泡,该泡泡波及的范围
escape_range 表示若放泡泡,逃脱的范围
"""
# 左右上下
spout_range = [0