20212102侯玥实验四pygame之坦克大战

PART1:坦克大战代码分析

  1. 游戏元素共分bullets,tanks,walls,booms,bird,enemies六种。
  2. 对于tanks类:由于各游戏元素的导入为图像形式,因此要实现元素的动态效果需要不断刷新屏幕。动态效果涉及一组两张图片加载,通过mf%2来选择状态。

对于游戏中的操作,调用pygame.KEYUP,pygame.KEYDOWN实现,并对输入的字母对应相应的方向,进行相应图片的加载。

小细节:如果按键时长不足以让坦克走完一格(以向下为例处理):

由于图片像素为46像素,所以除数为23,半格半格地走。

event.key == K_s and playerpos[0] % 23 == 0 and playerpos[1] % 23 == 0
  1. 对于bullets,也就是炮弹类(因为英文有点长在程序里就写的pao):

考虑炮弹的方向,来源,坐标。考虑来源是因为敌方炮弹可以击中我方,但敌方炮弹无法摧毁敌方自己的坦克。炮弹在场上不止有一个,所以列表来储存。

下面是paodan模块:

class Pao(object):
    def __init__(self,paopos,Direction,source):
        self.paopos = paopos
        self.Direction =Direction
        self.source=source

  

  1. 对于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。

  1. 对于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

  

 

  1. 对于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

  

(这里插一句,游戏中涉及到敌我坦克不可穿模问题,所以将所有坦克按特殊墙体处理)

  1. 各元素坐标初始化:
playerpos = [23 * 8, 23 * 24] #坦克坐标初始化
wallplace = []
paolist = []
boomlist = []
enemylist = []

  

  1. 调用
pygame.image.load('').convert_alpha()

  

实现图像加载。

  1. 调用
pygame.time.delay(1)

  

实现移动速度的控制。

  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

  

  1. 无墙正常行走时(以向左为例):
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++中将如何实现。

posted @ 2022-05-31 23:22  FayFloride  阅读(150)  评论(0编辑  收藏  举报