Pygame精灵按空格发射子弹触发AttributeError报错如何修复
报错原因
- 核心触发点:
car.py中shoot方法错误调用对象。你在car.py里将加载的子弹图片Surface对象命名为bullets,却尝试调用bullets.Bullet()创建子弹实例,bullets是图片对象而非模块,不存在Bullet属性,直接触发AttributeError。 - 同时存在多个隐藏问题会导致后续报错:
- 循环导入:
bullet.py导入autopilot.py的变量,autopilot.py又导入car.py,如果car.py导入Bullet类会触发循环导入异常。 - 各模块重复初始化Pygame窗口、重复定义screen变量,会引发未知渲染异常。
car.py和autopilot.py中定义的bullet_group是独立分组,子弹加入car.py的分组后不会被主循环渲染更新。
- 循环导入:
修复方案
1. 修改car.py
删除顶部重复的屏幕初始化、screen定义、子弹图片加载、bullet_group定义代码,调整类方法如下:
import pygame from bullet import Bullet class Player(pygame.sprite.Sprite): def __init__(self, scale, speed, bullet_group): pygame.sprite.Sprite.__init__(self) self.bullet_group = bullet_group self.speed = speed self.moving = True self.frame = 0 self.flip = False self.direction = 0 # 加载车辆图片逻辑不变 self.images = [] img = pygame.image.load('car/car.png').convert_alpha() img = pygame.transform.scale(img, (int(img.get_width()) * scale, (int(img.get_height()) * scale))) self.images.append(img) self.image = self.images[0] self.rect = self.image.get_rect() self.update_time = pygame.time.get_ticks() self.movingLeft = False self.movingRight = False self.rect.x = 465 self.rect.y = 325 def draw(self, screen): screen.blit(self.image, (self.rect.centerx, self.rect.centery)) def move(self): dx = 0 dy = 0 if self.movingLeft and self.rect.x > 33: dx -= self.speed self.flip = True self.direction = -1 if self.movingRight and self.rect.x < 900: dx += self.speed self.flip = False self.direction = 1 self.rect.x += dx self.rect.y += dy def shoot(self): bullet = Bullet(self.rect.centerx + 18, self.rect.y + 30, self.direction) self.bullet_group.add(bullet)
2. 修改bullet.py
删除顶部重复的屏幕初始化代码、screen定义、循环导入语句,调整碰撞检测逻辑:
import pygame bullet_img = pygame.image.load('car/bullet.png').convert_alpha() class Bullet(pygame.sprite.Sprite): def __init__(self, x, y, direction): pygame.sprite.Sprite.__init__(self) self.speed = 5 self.image = bullet_img self.rect = self.image.get_rect() self.rect.center = (x,y) self.direction = direction def update(self, debris): self.rect.centery -= self.speed # 子弹出屏销毁 if self.rect.top < 1: self.kill() # 碰撞检测 if pygame.sprite.collide_rect(self, debris) and debris.alive: debris.health -= 25 self.kill()
3. 修改debris.py
删除顶部重复的屏幕初始化代码,调整draw方法:
import pygame class Debris(pygame.sprite.Sprite): def __init__(self, scale, speed): pygame.sprite.Sprite.__init__(self) self.x = 400 self.y = 0 self.speed = speed self.vy = 0 self.on_ground = True self.move = True self.health = 100 self.max_health = self.health self.alive = True # 加载障碍物图片逻辑不变 self.images = [] img = pygame.image.load('debris/cement.png').convert_alpha() img = pygame.transform.scale(img, (int(img.get_width()) * scale, (int(img.get_height()) * scale))) self.images.append(img) self.image = self.images[0] self.rect = self.image.get_rect() self.rect.x = self.x self.rect.y = self.y def draw(self, screen): screen.blit(self.image,(self.x,self.y))
4. 修改autopilot.py
调整类实例初始化逻辑,传入必要参数,删除重复的帧更新代码:
import pygame import car import debris pygame.init() # 屏幕设置 WIDTH = 1000 HEIGHT = 400 screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("AutoPilot") screen.fill((255, 255, 255)) # 帧率设置 FPS = 120 clock = pygame.time.Clock() # 加载背景图 bg = pygame.image.load('background/street.png').convert_alpha() # 精灵分组 bullet_group = pygame.sprite.Group() debris_group = pygame.sprite.Group() # 实例化游戏对象 debris = debris.Debris(1, 5) player = car.Player(1, 5, bullet_group) debris_group.add(debris) # 主循环 run = True while run: screen.blit(bg, [0, 0]) # 更新并渲染子弹 bullet_group.update(debris) bullet_group.draw(screen) # 渲染其他对象 debris.draw(screen) player.draw(screen) player.move() # 事件监听 for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: run = False if event.key == pygame.K_a: player.movingLeft = True if event.key == pygame.K_d: player.movingRight = True if event.key == pygame.K_SPACE: player.shoot() if event.type == pygame.KEYUP: if event.key == pygame.K_a: player.movingLeft = False if event.key == pygame.K_d: player.movingRight = False pygame.display.update() clock.tick(FPS) pygame.quit()
内容的提问来源于stack exchange,提问作者J.R. BEATS
相关产品推荐
相关产品推荐

