代码写完时没有报错,但运行时闪退且报错
报错内容:
错误的意思是,Bullet这个对象没有 bulletMove这个属性,仔细检查一下是否拼写错误
这个有可能是内存问题,你看一下你代码里面有哪些地方分配了内存,当内存出现问题的时候,他就会终止程序,在C语言里面也有过,一运行就弹出一个框终止了程序
你这不就是报错了吗。。。。。。
Bullet模块没有bulletMove()函数
import pygame, time, random
COLOR_BLACK = pygame.Color(0, 0, 0) # 顺序:红,绿,蓝
COLOR_RED = pygame.Color(255, 0, 0)
class MainGame():
window = None # 游戏主窗口
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 500
TANK_P1 = None # 创建我方坦克
EnemyTank_list = [] # 存储敌方所有坦克
EnemyTank_count = 5 # 要创建的敌方坦克的数量
Bullet_list = [] # 存储我方子弹的列表
Enemy_bullet_list = [] # 储存敌方坦克的列表
Explode_list = [] # 爆炸效果列表
Wall_list = []
def startGame(self): # 开始游戏方法
pygame.display.init()
MainGame.window = pygame.display.set_mode([MainGame.SCREEN_WIDTH, MainGame.SCREEN_HEIGHT]) # 创建窗口加载窗口(借鉴官方文档)
# MainGame.TANK_P1 = Tank(400, 300) # 创建我方坦克
self.createMyTank()
self.createEnemyTank()
self.createWalls()
pygame.display.set_caption("坦克大战") # 设置游戏标题
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:
if MainGame.TANK_P1.stop == True: # 调用坦克的移动方法
MainGame.TANK_P1.move()
MainGame.TANK_P1.hitWalls() # 调用碰撞墙壁的方法
MainGame.TANK_P1.hitEnemyTank()
self.blitBullet() # 调用渲染子弹列表的方法
self.blitEnemyBullet() # 调用渲染敌方子弹列表的方法
self.displayExplodes() # 调用展示爆炸效果的方法
time.sleep(0.005)
pygame.display.update() # 窗口的刷新
def createMyTank(self): # 创建我方坦克的方法
MainGame.TANK_P1 = MyTank(400, 300) # 创建我方坦克
# music = Music() # 创建音乐对象
# music.play() # 调用播放方法
def createEnemyTank(self): # 创建敌方坦克
top = 100
for i in range(MainGame.EnemyTank_count):
speed = random.randint(3, 6)
left = random.randint(1, 7) # 每次都随机生成一个left值
eTank = EnemyTank(left * 100, top, speed)
MainGame.EnemyTank_list.append(eTank)
def createWalls(self): # 创建墙壁的方法
for i in range(1, 7):
wall = Wall(120 * i, 240)
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() # 调用敌方坦克的射击
if eBullet: # 如果子弹为None,不加入到列表
MainGame.Enemy_bullet_list.append(eBullet) # 将子弹存储到敌方子弹列表
else:
MainGame.EnemyTank_list.remove(eTank)
def blitBullet(self): # 将我方子弹加入到窗口中
for bullet in MainGame.Bullet_list:
if bullet.live == True:
bullet.displayBullet()
bullet.bulletMove() # 让子弹移动
bullet.hitEnemyTank() # 调用我方子弹与敌方坦克的碰撞方法
bullet.hitWalls() # 调用判断我方坦克是否碰撞到墙壁的方法
else:
MainGame.Bullet_list.remove(bullet)
def blitEnemyBullet(self): # 将敌方子弹加入到窗口中
for eBullet in MainGame.Enemy_bullet_list:
if eBullet.live:
eBullet.displayBullet()
eBullet.bulletMove() # 让子弹移动
eBullet.hitWalls() # 调用是否碰撞到墙壁的方法
if MainGame.TANK_P1 and MainGame.TANK_P1.live:
eBullet.hitMyTank()
else:
MainGame.Enemy_bullet_list.remove(eBullet)
# 新增方法:展示爆炸效果列表
def displayExplodes(self):
for explode in MainGame.Explode_list:
if explode.live:
explode.displayExplode()
else:
MainGame.Explode_list.remove(explode)
def getEvent(self): # 获取程序期间所有事件(鼠标事件,键盘事件)
eventList = pygame.event.get() # 1.获取所有事件
for event in eventList: # 2.对事件进行判断处理(1,点击关闭按钮 2.按下键盘上的某个按建)
if event.type == pygame.QUIT: # 判断event.type是否QUIT,如果是退出,直接调用程序结束方法
self.endGame()
if event.type == pygame.KEYDOWN: # 判断事件类型是否为按键按下,如果是的话,继续判断按键是哪个按键进行对应处理
if event.key == pygame.K_ESCAPE and not MainGame.TANK_P1: # 点击esc按键让我方坦克重生
self.createMyTank() # 调用创见我方坦克的方法
if MainGame.TANK_P1 and MainGame.TANK_P1.live:
if event.key == pygame.K_LEFT:
# print("坦克向左调头.移动")
MainGame.TANK_P1.direction = 'L' # 修改坦克方向
MainGame.TANK_P1.move()
MainGame.TANK_P1.stop = True
elif event.key == pygame.K_RIGHT:
# print("坦克向右调头,移动")
MainGame.TANK_P1.direction = 'R' # 修改坦克方向
MainGame.TANK_P1.move()
MainGame.TANK_P1.stop = True
elif event.key == pygame.K_UP:
# print("坦克向上调头,移动")
MainGame.TANK_P1.direction = 'U' # 修改坦克方向
MainGame.TANK_P1.move()
MainGame.TANK_P1.stop = True
elif event.key == pygame.K_DOWN:
# print("坦克向下调头,移动")
MainGame.TANK_P1.direction = 'D' # 修改坦克方向
MainGame.TANK_P1.move()
MainGame.TANK_P1.stop = True
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()
# 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 = False # 修改坦克的移动状态
def getTextSurface(self, text): # 左上角文字绘制的功能
pygame.font.init() # 初始化字体模块
# fontList = pygame.font.get_fonts()
# print(fontList)
font = pygame.font.SysFont('kaiti', 18) # 选中一个合适的字体
textSurface = font.render(text, True, COLOR_RED) # 使用对应的字符完成相关内容的绘制
return textSurface
def endGame(self): # 结束游戏方法
print('谢谢使用')
exit() # 结束python解释器
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('F:\坦克大战图片\Pictures\p1tankU.gif'),
'D': pygame.image.load('F:\坦克大战图片\Pictures\p1tankD.gif'),
'L': pygame.image.load('F:\坦克大战图片\Pictures\p1tankL.gif'),
'R': pygame.image.load('F:\坦克大战图片\Pictures\p1tankR.gif')
}
self.direction = "U"
self.image = self.images[self.direction]
self.rect = self.image.get_rect() # 坦克所在的区域
self.rect.left = left # 指定坦克位置,分别距x,y轴距离
self.rect.top = top
self.speed = 5 # 新增速度属性
self.step = 20
self.stop = False # 新增属性:坦克的移动开关
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.width < MainGame.SCREEN_WIDTH:
self.rect.left += self.speed
elif self.direction == 'U':
if self.rect.top > 0:
self.rect.top -= self.speed
else:
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)
def displayTank(self): # 展示坦克(将坦克绘制到窗口中)
self.image = self.images[self.direction] # 重新设置坦克图片
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('F:\坦克大战图片\Pictures\enemy1U.gif'),
'D': pygame.image.load('F:\坦克大战图片\Pictures\enemy1D.gif'),
'L': pygame.image.load('F:\坦克大战图片\Pictures\enemy1L.gif'),
'R': pygame.image.load('F:\坦克大战图片\Pictures\enemy1R.gif')
}
self.direction = self.randDirection()
self.image = self.images[self.direction]
self.rect = self.image.get_rect() # 坦克所在的区域
self.rect.left = left # 指定坦克位置,分别距x,y轴距离
self.rect.top = top
self.speed = speed # 新增速度属性
self.stop = False # 新增属性:坦克的移动开关
self.step = 10
self.live = True
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 = 20
else:
self.move()
self.step -= 1
def shot(self):
num = random.randint(1, 1000)
if num <= 20:
return Bullet(self)
def hitMyTank(self):
if MainGame.TANK_P1 and MainGame.TANK_P1.live:
if pygame.sprite.collide_rect(self, MainGame.TANK_P1):
self.stay()# 让敌方坦克停下来 stay()
class Bullet(BaseItem):
def __init__(self, tank):
self.speed = 5
self.live = True
self.image = pygame.image.load('F:\坦克大战图片\Pictures\爆炸效果.1.gif') # 图片
self.direction = tank.direction # 方向
self.rect = self.image.get_rect() # 位置0
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 bulltMove(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):
explode = Explode(eTank) # 产生一个爆炸效果
MainGame.Explode_list.append(explode) # 将爆炸效果加入到爆炸列表
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):
self.live = False # 修改子弹的live属性
wall.hp -= 1
if wall.hp <= 0:
wall.live = False
class Explode():
def __init__(self, tank):
self.rect = tank.rect
self.step = 0
self.images = [
pygame.image.load('F:\坦克大战图片\Pictures\爆炸效果.1.gif'),
pygame.image.load('F:\坦克大战图片\Pictures\爆炸效果.1.gif'),
pygame.image.load('F:\坦克大战图片\Pictures\爆炸效果.1.gif'),
pygame.image.load('F:\坦克大战图片\Pictures\爆炸效果.1.gif'),
pygame.image.load('F:\坦克大战图片\Pictures\爆炸效果.1.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('F:\坦克大战图片\Pictures\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.load(self.fileName)
MainGame().startGame()