sulawu 2022-03-09 05:42 采纳率: 100%
浏览 308
已结题

用pagame写坦克大战报 AttributeError: 'NoneType' object has no attribute 'rect' 白兔了彦祖们

import pygame,time,random
_display = pygame.display
COLOR_BLACK = pygame.Color(0, 0, 0)
COLOR_RED = pygame.Color(255,0,0)
version = "v1.25"
class MainGame():
#游戏主窗口
window = None
SCREEN_HEIGHT = 650
SCREEN_WIDTH = 1000
#创建我方坦克
TANK_P1 = None
#存储所有敌方坦克
EnemyTank_list = []
#要创建的敌方坦克的数量
EnemTank_count = 5
#存储我方子弹的子弹的列表
Bullet_list = []
#存储敌方子弹的列表
Enemy_bullet_list = []
#增加爆炸效果列表
Explode_List = []
#墙壁列表
Wall_list = []
#开始游戏方法
def startGame(self):
_display.init()
#创建窗口加载窗口(借鉴官方文档)
MainGame.window = _display.set_mode([MainGame.SCREEN_WIDTH,MainGame.SCREEN_HEIGHT])
self.creatMyTank()
#?创建敌方坦克
self.creatEnemyTank()
self.cteatWalls()
#设置一下游戏标题
_display.set_caption("坦克大战"+version)
#让窗口持续刷新操作
while True:
#给窗口完成一个填充颜色
MainGame.window.fill(COLOR_BLACK)
#在循环中持续完成事件的获取
self.getEvent()
#将绘制文字得到的小画布,粘贴到窗口中
MainGame.window.blit(self.getTextSurface("剩余敌方坦克%d辆"%len(MainGame.EnemyTank_list),),(5,5))
#调用展示墙壁的方法
self.blitWalls()
if MainGame.TANK_P1 and MainGame.TANK_P1.live:
# 将我方坦克加入到窗口中
MainGame.TANK_P1.displayTank()
else:
del MainGame.TANK_P1
MainGame.TANK_P1 = None

        #循环展示敌方坦克
        self.blitEnemyTank()
        #根据坦克的开关状态调用坦克的移动方法
        if MainGame.TANK_P1 and not MainGame.TANK_P1.stop:
            MainGame.TANK_P1.move()
            #调用碰撞墙壁的方法
            MainGame.TANK_P1.hitWalls()
            MainGame.TANK_P1.hitEnemyTank()
        #调用渲染子弹列表的一个方法
        self.blitBullet()
        #调用渲染敌方子弹得到一个方法
        self.blitEnemyBullet()
        #调用展示爆炸效果的方法
        self.displayExplodes()

        time.sleep(0.02)
        #窗口的刷新
        _display.update()
#创建我方坦克
def creatMyTank(self):
    # 创建我方坦克
    MainGame.TANK_P1 = MyTank(300, 500)
    #创建音乐对象
    music = Music('img/start.wav')
    #调用播发音乐方法
    music.play()
#创建敌方坦克
def creatEnemyTank(self):
    top = 100
    for i in range(MainGame.EnemTank_count):
        speed = random.randint(3, 6)
        #每次都随机生成一个laft值
        left = random.randint(1, 9)
        eTank = EnemyTank(left*100,top,speed)
        MainGame.EnemyTank_list.append(eTank)
#创建墙壁的方法
def cteatWalls(self):
    for i in range(7):
        wall = Wall(140*i,325)
        MainGame.Wall_list.append(wall)
def blitWalls(self):
    for wall in MainGame.Wall_list:
        if wall.live:
            wall.displayWall()
        else:
            MainGame.Wall_list.remove(wall)
#将敌方坦克加入到窗口中
def blitEnemyTank(self):
    for eTank in MainGame.EnemyTank_list:
        if eTank.live:
            eTank.displayTank()
            # 坦克的移动方法
            eTank.randMove()
            #调用敌方坦克于墙壁的碰撞方法
            eTank.hitWalls()
            #敌方坦克是否撞到我方坦克
            eTank.hitMyTank()
            # 调用敌方坦克的射击
            eBullet = eTank.shot()
            # 将存储到敌方子弹列表
            # 如果子弹为None,不加如到列表
            if eBullet:
                #将子弹存储到敌方子弹列表
                MainGame.Enemy_bullet_list.append(eBullet)
        else:
            MainGame.EnemyTank_list.remove(eTank)
#将我方子弹加入到窗口中
def blitBullet(self):
    for bullet in MainGame.Bullet_list:
        #如果子弹还活着,绘制出来,否则,直接从列表中移除改子弹
        if bullet.live:
            bullet.displayBullet()
            # 让子弹移动
            bullet.bulletMove()
            #调用我方子弹于敌方坦克的碰撞方法
            bullet.hitEnemyTank()
            #调用判断我方子弹是否碰撞到墙壁的方法
            bullet.hitWalls()
        else:
            MainGame.Bullet_list.remove(bullet)
#将敌方子弹加入到窗口中
def blitEnemyBullet(self):
    for eBuller in MainGame.Enemy_bullet_list:
        #如果子弹还活着,绘制出来,否则,直接从列表中移除改子弹
        if eBuller.live:
            eBuller.displayBullet()
            # 让子弹移动
            eBuller.bulletMove()
            #调用是否碰撞到墙壁的一个方法
            eBuller.hitWalls()
            if MainGame.TANK_P1 and MainGame.TANK_P1.live:
                eBuller.hitMyTank()

        else:
            MainGame.Enemy_bullet_list.remove(eBuller)

#新增方法:展示爆炸效果列表
def displayExplodes(self):
    for explode in MainGame.Explode_List:
        if explode.live:
            explode.displayExplode()
        else:
            MainGame.Explode_List.remove(explode)

#获取程序期间所有事件(鼠标事件,键盘事件)
def getEvent(self):
    #1.获取所有事件
    eventLIst = pygame.event.get()
    #2.对事件进行判断处理(1.点击关闭按钮2.按下键盘上的某个按键)
    for event in eventLIst:
        #判断event.type是否QUIT,如果时退出的话,直接调用程序结束方法
        if event.type == pygame.QUIT:
            self.endGame()
        #判断事件类型是否为按键按下,如果是,继续判断按建时哪一个按键,来进行对应的处理
        if event.type == pygame.KEYDOWN:
            #点击ESC按键让我方坦克重生
            if event.key == pygame.K_ESCAPE and not MainGame.TANK_P1:
                #调用创建我方坦克的方法
                self.creatMyTank()

            if MainGame.TANK_P1 and MainGame.TANK_P1.live:
                # 具体是哪一个按键的处理
                if event.key == pygame.K_LEFT:
                    print("坦克向左调头,移动")
                    # 修改坦克方向
                    MainGame.TANK_P1.direction = 'L'
                    MainGame.TANK_P1.stop = False
                elif event.key == pygame.K_RIGHT:
                    print("坦克向右调头,移动")
                    # 修改坦克方向
                    MainGame.TANK_P1.direction = 'R'
                    MainGame.TANK_P1.stop = False
                elif event.key == pygame.K_UP:
                    print("坦克向上调头,移动")
                    # 修改坦克方向
                    MainGame.TANK_P1.direction = 'U'
                    MainGame.TANK_P1.stop = False
                elif event.key == pygame.K_DOWN:
                    print("坦克向下调头,移动")
                    # 修改坦克方向
                    MainGame.TANK_P1.direction = 'D'
                    MainGame.TANK_P1.stop = False
                elif event.key == pygame.K_SPACE:
                    print("发射子弹")
                    if len(MainGame.Bullet_list) < 3:
                        # 产生一颗子弹
                        m = Bullet(MainGame.TANK_P1)
                        # 将子弹加入到子弹列表
                        MainGame.Bullet_list.append(m)
                        music = Music('img/fire.wav')
                        music.play()
                    else:
                        print("子弹数量不足")
                    print("当前屏幕中子弹数量为:%d" % len(MainGame.Bullet_list))
        #结束游戏方法
        if event.type == pygame.KEYUP:
            #松开的如果是方向建,才更改移动状态
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or\
                    event.key == pygame.K_UP or event.key == pygame.K_DOWN:
                if MainGame.TANK_P1 and MainGame.TANK_P1.live:
                    # 修改坦克的移动状态
                    MainGame.TANK_P1.stop = True

#左上角文字绘制的功能
def getTextSurface(self,text):
    #初始化模块
    pygame.font.init()
    #查看系统支持的所有字体
    #fontList = pygame.font.get_fonts()
    #print(fontList)
    #选中一个合适的字体
    font = pygame.font.SysFont('kaiti',18)
    #使用对应的字体完成相关内容的绘制
    testSurface = font.render(text,True,COLOR_RED)
    return testSurface
#结束游戏方法
def endGame(self):
    print("谢谢使用")
    #结束python解释器
    exit()

class BaseItem(pygame.sprite.Sprite):
def init(self):
pygame.sprite.Sprite.init(self)
class Tank(BaseItem):
def init(self,left,top):
self.images = {
'U':pygame.image.load('img\P1_U.png'),
'D':pygame.image.load('img\P1_D.png'),
'L':pygame.image.load('img\P1_L.png'),
'R':pygame.image.load('img\P1_R.png')
}
self.direction = 'U'
self.image = self.images[self.direction]
#坦克所在的区域 Rect->
self.rect = self.image.get_rect()
#指定坦克初始化位置,分别距x,y轴的位置
self.rect.left = left
self.rect.top = top
#新增速度属性
self.speed = 5
#新增属性:坦克的移动开关
self.stop = True
#新增属性 live用来记录,坦克是否活着
self.live = True
#新增属性:用来记录坦克移动之前的坐标(用于坐标还原时使用)
self.oldLeft = self.rect.left
self.oldTop = self.rect.top

#坦克的移动方法
def move(self):
    #先记录移动之前的坐标
    self.oldLeft = self.rect.left
    self.oldTop = self.rect.top
    if self.direction == 'L':
        if self.rect.left > 0:
            self.rect.left -= self.speed
    elif self.direction == 'R':
        if self.rect.left + self.rect.height < MainGame.SCREEN_WIDTH:
            self.rect.left += self.speed
    elif self.direction == 'U':
        if self.rect.top >0:
            self.rect.top -= self.speed
    elif self.direction == 'D':
       if self.rect.top + self.rect.height < MainGame.SCREEN_HEIGHT:
           self.rect.top += self.speed
def stay(self):
    self.rect.left = self.oldLeft
    self.rect.top = self.oldTop
#新增碰撞墙壁的方法
def hitWalls(self):
    for wall in MainGame.Wall_list:
        if pygame.sprite.collide_rect(wall,self):
            self.stay()
#射击方法
def shot(self):
    return Bullet(self)
#展示坦克(将坦克这个surface绘制到窗口中  blit())
def displayTank(self):
    #1.重新设置坦克的图片
    self.image = self.images[self.direction]
    #2.将坦克加入到窗口中
    MainGame.window.blit(self.image,self.rect)

class MyTank(Tank): #我方坦克
def init(self,left,top):
super(MyTank, self).init(left,top)
#新增主动碰撞到敌方坦克的方法
def hitEnemyTank(self):
for eTank in MainGame.EnemyTank_list:
if pygame.sprite.collide_rect(eTank,self):
self.stay()

class EnemyTank(Tank): #敌方坦克
def init(self,left,top,speed):
super(EnemyTank,self).init(left,top)
#self.live = True
self.images = {
'U': pygame.image.load('img/enemy2U.gif'),
'D': pygame.image.load('img/enemy2R.gif'),
'L': pygame.image.load('img/enemy2L.gif'),
'R': pygame.image.load('img/enemy2D.gif')
}
self.direction = self.randDirection()
self.image = self.images[self.direction]
# 坦克所在的区域 Rect->
self.rect = self.image.get_rect()
# 指定坦克初始化位置,分别距x,y轴的位置
self.rect.left = left
self.rect.top = top
# 新增速度属性
self.speed = speed
self.stop = True
#新增步数属性,用来控制敌方坦克随机移动
self.step = 50

def randDirection(self):
    num = random.randint(1,4)
    if num == 1:
       return  'U'
    elif num == 2:
        return 'D'
    elif num == 3:
        return 'L'
    elif num == 4:
        return 'R'
#def displayEnemtTank(self):
    #super().displayTank()
#随机移动
def randMove(self):
    if self.step <= 0:
        self.direction = self.randDirection()
        self.step = 50
    else:
        self.move()
        self.step -= 1
def shot(self):
    num = random.randint(1,1000)
    if num <= 15:
        return Bullet(self)
def hitMyTank(self):
    if pygame.sprite.collide_rect(self,MainGame.TANK_P1):
        #让敌方坦克听下来 stay()
        self.stay()

class Bullet(BaseItem):
def init(self,tank,):
#图片
self.image = pygame.image.load('img/enemymissile.gif')
#方向(坦克方向)
self.direction = tank.direction
#位置
self.rect = self.image.get_rect()
if self.direction == 'U':
self.rect.left = tank.rect.left + tank.rect.width/2 - self.rect.width/2
self.rect.top = tank.rect.top - self.rect.height
elif self.direction == 'D':
self.rect.left = tank.rect.left + tank.rect.width / 2 - self.rect.width / 2
self.rect.top = tank.rect.top + tank.rect.height
elif self.direction == "L":
self.rect.left = tank.rect.left - self.rect.width / 2 - self.rect.width / 2
self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2
elif self.direction == 'R':
self.rect.left = tank.rect.left + tank.rect .width
self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2

    #速度
    self.speed = 7
    #用来记录子弹是否碰撞
    self.live = True
#子弹的移动方法
def bulletMove(self):
    if self.direction == 'U':
        if self.rect.top > 0:
            self.rect.top -= self.speed
        else:
            #修改状态值
            self.live = False
    elif self.direction == 'D':
        if self.rect.top < MainGame.SCREEN_HEIGHT - self.rect.height:
            self.rect.top += self.speed
        else:
            # 修改状态值
            self.live = False
    elif self.direction == 'L':
        if self.rect.left > 0:
            self.rect.left -= self.speed
        else:
            # 修改状态值
            self.live = False
    elif self.direction == 'R':
        if self.rect.left < MainGame.SCREEN_WIDTH - self.rect.width:
            self.rect.left += self.speed
        else:
            # 修改状态值
            self.live = False
#展示子弹的方法
def displayBullet(self):
    MainGame.window.blit(self.image,self.rect)
#新增我方子弹碰撞敌方坦克的方法
def hitEnemyTank(self):
    for eTank in MainGame.EnemyTank_list:
        if pygame.sprite.collide_rect(eTank,self):
            #产生一个爆炸效果
            explpde = Explode(eTank)
            #将爆炸效果加入到爆炸列表中
            MainGame.Explode_List.append(explpde)
            self.live = False
            eTank.live = False
#新增敌方子弹于我方坦克的碰撞方法
def hitMyTank(self):
    if pygame.sprite.collide_rect(self,MainGame.TANK_P1):
        #产生爆炸效果,并加入到爆炸效果列表中
        explode = Explode(MainGame.TANK_P1)
        MainGame.Explode_List.append(explode)
        #修改子弹状态
        self.live = False
        #修改我方坦克状态
        MainGame.TANK_P1.live = False
#新增子弹于墙壁的碰撞
def hitWalls(self):
    for wall in MainGame.Wall_list:
        if pygame.sprite.collide_rect(wall,self):
            #修改子弹的live属性
            self.live = False
            wall.hp -= 1
            if wall.hp <= 0:
                wall.live = False

class Explode():
def init(self,tank):
self.rect = tank.rect
self.step = 1
self.images = [
pygame.image.load('img/blast1.gif'),
pygame.image.load('img/blast2.gif'),
pygame.image.load('img/blast3.gif'),
pygame.image.load('img/blast4.gif'),
pygame.image.load('img/blast5.gif')
]
self.image = self.images[self.step]
self.live = True
#展示爆炸效果
def displayExplode(self):
if self.step < len(self.images):
MainGame.window.blit(self.image, self.rect)
self.image = self.images[self.step]
self.step += 1
else:
self.live = False
self.step = 0
class Wall():
def init(self,left,top):
self.image = pygame.image.load('img/steels.gif')
self.rect = self.image.get_rect()
self.rect.left = left
self.rect.top = top
#用来判断墙壁是否应该在窗口中展示
self.live = True
#用来记录墙壁的生命值
self.hp = 3
#展示墙壁的方法
def displayWall(self):
MainGame.window.blit(self.image,self.rect)
#我方坦克出生
class Music():
def init(self,fileName):
self.fileName = fileName
#先初始化混音器
pygame.mixer.init()
pygame.mixer.music.load(self.fileName)
#开始播放音乐
def play(self):
pygame.mixer.music.play()
MainGame().startGame()

这是源码

  • 写回答

2条回答 默认 最新

  • T_300 2022-03-12 13:42
    关注

    是不是我方坦克一爆炸就提示?因为那个判断相撞的语句是一直在判断的,我方坦克一旦爆炸他那个值就没有了,所以会报错,在判断相撞的前面加一个条If语句判断我方坦克是否存在就行了

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 6月18日
  • 已采纳回答 6月10日
  • 创建了问题 3月9日

悬赏问题

  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 正弦信号发生器串并联电路电阻无法保持同步怎么办
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 个人网站被恶意大量访问,怎么办
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)