20212102侯玥实验四pygame之坦克大战
PART1:坦克大战代码分析
- 游戏元素共分bullets,tanks,walls,booms,bird,enemies六种。
- 对于tanks类:由于各游戏元素的导入为图像形式,因此要实现元素的动态效果需要不断刷新屏幕。动态效果涉及一组两张图片加载,通过mf%2来选择状态。
对于游戏中的操作,调用pygame.KEYUP,pygame.KEYDOWN实现,并对输入的字母对应相应的方向,进行相应图片的加载。
小细节:如果按键时长不足以让坦克走完一格(以向下为例处理):
由于图片像素为46像素,所以除数为23,半格半格地走。
event.key == K_s and playerpos[0] % 23 == 0 and playerpos[1] % 23 == 0
- 对于bullets,也就是炮弹类(因为英文有点长在程序里就写的pao):
考虑炮弹的方向,来源,坐标。考虑来源是因为敌方炮弹可以击中我方,但敌方炮弹无法摧毁敌方自己的坦克。炮弹在场上不止有一个,所以列表来储存。
下面是paodan模块:
class Pao(object): def __init__(self,paopos,Direction,source): self.paopos = paopos self.Direction =Direction self.source=source
- 对于boom类:
场上可以不止有一个boom,用列表储存。
Pao元素遇到只剩一滴血的坦克元素才会发生boom。
for i in paolist: flag = False if i.source == 0: for j in enemylist: if -23 < i.paopos[0] - j.enemypos[0] <= 46 and -23 < i.paopos[1] - j.enemypos[1] <= 46: if (j.blood == 1): enemylist.remove(j) enemynum -= 1 else: j.blood -= 1 flag = True break
Pao元素遇到特殊墙体后也会发生boom(以向上走的炮弹为例)。
if i.Direction == 0: if [[i.paopos[0] // 23, math.ceil(i.paopos[1] / 23) - 1], 0] in wallplace: flag = True wallplace.remove([[i.paopos[0] // 23, math.ceil(i.paopos[1] / 23) - 1], 0]) if [[i.paopos[0] // 23 + 1, math.ceil(i.paopos[1] / 23) - 1], 0] in wallplace: flag = True wallplace.remove([[i.paopos[0] // 23 + 1, math.ceil(i.paopos[1] / 23) - 1], 0]) #0类墙体表示木质墙体,被炮弹攻击会消失半格 if [[i.paopos[0] // 23, math.ceil(i.paopos[1] / 23) - 1], 1] in wallplace or [ [i.paopos[0] // 23, math.ceil(i.paopos[1] / 23) - 1], 2] in wallplace: flag = True if [[i.paopos[0] // 23 + 1, math.ceil(i.paopos[1] / 23) - 1], 1] in wallplace or [ [i.paopos[0] // 23 + 1, math.ceil(i.paopos[1] / 23) - 1], 2] in wallplace: flag = True #1类或2类墙体表示特殊墙体,无法被摧毁 if flag: boomlist.append([[i.paopos[0] - 9, i.paopos[1] - 14], 5]) paolist.remove(i)
Pao遇到pao也会boom。
- 对于enemy类:
def __init__(self,enemypos,Direction,Type,blood,speed,frequency):
轻型坦克速度较快,重型坦克有三条生命值,frequency记录敌方炮弹发射频率。
以下是敌人的攻击代码:frequency用于控制敌方炮弹发射速度(太快玩家会死的),enemypos为敌方坦克位置。
def enemyattack(): for i in enemylist: if i.frequency != 0: i.frequency -= 1 if i.enemypos[0] % 23 == 0 and i.enemypos[1] % 23 == 0 and i.frequency == 0: if random.randint(0, 1) == 0: paolist.append(Paodan.Pao(setpao(i.Direction, i.enemypos), i.Direction, 1)) i.frequency = 150
实现敌人的随机行走(以向上为例):
其中调用的notwallup会在后面定义。
for i in enemylist: point = False flag = False if i.Direction == 0 and notwallup(i.enemypos, 0) and notwallup(i.enemypos, 1) and notwallup(i.enemypos, 2) and notwallup( i.enemypos, 4): for j in enemylist: if i.enemypos != j.enemypos and 0 < i.enemypos[1] - j.enemypos[1] <= 46 and abs( j.enemypos[0] - i.enemypos[0]) <= 46: point = True if point != True: i.enemypos[1] -= i.speed flag = True
- 对于wall类:
Pao遇到木质墙体会将墙体移除:
if [[i.paopos[0] // 23 + 1, math.ceil(i.paopos[1] / 23) - 1], 0] in wallplace: flag = True wallplace.remove([[i.paopos[0] // 23 + 1, math.ceil(i.paopos[1] / 23) - 1], 0])
坦克遇到特殊墙体会停止前进,于是编写notwall(以向上为例):
def notwallup(pos, Type): if [[pos[0] // 23, math.ceil(pos[1] / 23) - 1], Type] not in wallplace and [ [pos[0] // 23 + 1, math.ceil(pos[1] / 23) - 1], Type] not in wallplace: return True else: return False
(这里插一句,游戏中涉及到敌我坦克不可穿模问题,所以将所有坦克按特殊墙体处理)
- 各元素坐标初始化:
playerpos = [23 * 8, 23 * 24] #坦克坐标初始化 wallplace = [] paolist = [] boomlist = [] enemylist = []
- 调用
pygame.image.load('').convert_alpha()
实现图像加载。
- 调用
pygame.time.delay(1)
实现移动速度的控制。
- Enemy出生点设置:
if rspawnpoint == mspawnpoint == lspawnpoint == 0 and enemynum != 4: #敌人出生点设置,保证界面中有不少于4名敌人 enemynum += 1 if random.randint(0, 2) == 0: rspawnpoint = 600 elif random.randint(0, 1) == 0: mspawnpoint = 600 else: lspawnpoint = 600 #随机选择出生点 else: pass
- 无墙正常行走时(以向左为例):
def notwallleft(pos, Type): if [[math.ceil(pos[0] / 23) - 1, pos[1] // 23], Type] not in wallplace and [ [math.ceil(pos[0] / 23) - 1, pos[1] // 23 + 1], Type] not in wallplace: return True else: return False
PART2:结果如下
敌人自由行走和攻击,每次攻击会拆除半格墙体:
基地被炸,游戏结束:
PART3:感想
不得不说最后的大作业很有启发。一直都很喜欢打游戏,可以自己动手做游戏可以说是大部分游戏迷的梦想。
90tank这部游戏可以说有我童年的回忆在,我和我表哥小时候经常在一起打。听说可以做游戏于是立马选择了这个。但后来发现游戏程序的编写不是易事。
Python实现的是2D游戏,画面元素通过图片形式加载,所以想要做出游戏的动态效果是很麻烦的。每个坦克有两种状态,用于实现图片的动态效果,但代码也就会变得很长,于是我的图片加载代码差不多快100行了......
现在这个代码其实还有一点小小的bug,就是我方坦克生命值为0时,游戏依然能够运行,有时会玩着玩着不小心按到别的与游戏无关的按键,会闪退(这是我不知道打了多少遍试出来的)。
全课程下来吧,可以说学到了很多。
以前学习C++的时候,以为学代码就只能用来解决数学问题,但其实接触了python这门课之后,才发现其实现在就可以学着用代码做一些更为高深的东西。C++和python一样都属于面向对象编程语言,但是我在接触了python课之后才真正的明白面向对象与面向过程的区别。
通过python我了解了网络编程的相关知识,初识socket编程,还以为会是很难很难的东西,但发现其实一个聊天室的搭建通过python的socket编程用短短几行代码就实现了。
之前看一些学长学姐做的大创项目,“基于python爬虫的微博舆情监控”,那是我第一次听说爬虫这个功能,还挺好奇的。于是很巧地就在python课上学到了。爬虫真的是一个很有趣的功能,爬取网站上的内容十分方便。记得我第一次想爬取淘宝网站的内容,虽然后来被反爬了吧,但看到部分输出的字符中有“淘宝网”,“客服中心”之类的字样,有点小小的愉悦感。
感觉课程安排很合理,从基础的知识,到后来一些深入的网络编程,爬虫知识的入门,一点一点走近python,看到python功能的强大,也看到他和其他语言的区别。
最后大作业的安排在我眼里是很欢乐的一个作业,因为可以用自己感兴趣的python技术模块实现自己想要去做的事。可以说是自己一个学期python学习的成果,可以基于课程讲解的基础上更深入地学习socket或爬虫,也可以自己去探索pygame的世界,写出自己的童年回忆。这个作业我真的很喜欢。
后续的话,我可能会去探索一下C++里面网络编程的相关知识,挺好奇python里面的一些技术放到C++中将如何实现。