Pygame报错TypeError: Invalid rect assignment,子弹定位问题求助
解决Pygame中子弹对齐的TypeError问题
我想让子弹的topright与飞船的topright对齐,于是在Bullet类的__init__方法中写了:
self.rect = self.image.get_rect(topright = (pos))
通过以下代码传入飞船的topright位置:
self.shoot.add(Bullet(self.rect.topright))
其中self是Spaceship类的实例,shoot是pygame精灵组,但运行时出现TypeError: Invalid rect assignment错误,尝试移除pos的括号、设置x=pos等操作都没解决,完整代码如下:
import pygame # normal setup pygame.init() screen = pygame.display.set_mode((700, 700), pygame.RESIZABLE) pygame.display.set_caption('ZAP!') icon = pygame.image.load('download.jpg') pygame.display.set_icon(icon) clock = pygame.time.Clock() running = True # while loop running so after ending game i can still run # bg bg = pygame.image.load('ok_proper.jpg') bg_pic = pygame.transform.scale(bg, (700, 700)) class Bullet(pygame.sprite.Sprite): def __init__(self,pos): super().__init__() self.image = pygame.transform.rotate(pygame.transform.scale(pygame.image.load('Graphics/yes.png'),(100,100)),90) self.rect = self.image.get_rect(topright = (pos)) self.speed = 10 self.rect.y -= self.speed if self.rect.y < 0: self.rect = self.image.get_rect(topright= (pos)) class Spaceship(pygame.sprite.Sprite): def __init__(self): super().__init__() self.image = pygame.image.load('Graphics/spaceship.png') self.rect = self.image.get_rect(bottomleft=(250, 700)) self.speed = 5 self.laser_time = 0 self.laser_cooldown = 600 self.ready = True self.shoot = pygame.sprite.Group() def movement(self): keys = pygame.key.get_pressed() if (keys[pygame.K_RIGHT] or keys[pygame.K_d]) and self.rect.right + self.speed < 699: self.rect.x += self.speed elif (keys[pygame.K_LEFT] or keys[pygame.K_a]) and self.rect.x - self.speed > 0: self.rect.x -= self.speed elif keys[pygame.K_SPACE] and self.ready: self.shootlaser() self.ready = False self.laser_time = pygame.time.get_ticks() def shootlaser(self): if not self.ready: timeoflaser = pygame.time.get_ticks() if self.laser_time - timeoflaser == self.laser_cooldown: self.ready = True else: self.shoot.add(Bullet(self.rect.topright)) def update(self): self.movement() self.shootlaser() # spaceship spaceship = Spaceship() # spaceship = pygame.sprite.GroupSingle() # spaceship.add(Spaceship()) # bullet bullet = Bullet(spaceship) while running: clock.tick(60) screen.blit(bg_pic, (0, 0)) # background for event in pygame.event.get(): if event.type == pygame.QUIT: running = False screen.blit(spaceship.image,spaceship.rect) screen.blit(bullet.image,bullet.rect) spaceship.update() # spaceship.draw(screen) pygame.display.update()
错误原因分析
- 致命参数错误:代码中
bullet = Bullet(spaceship)这行传入的是Spaceship实例,不是坐标元组,而get_rect的topright参数需要(x,y)格式的元组,直接传对象导致了Invalid rect assignment。 - 逻辑位置错误:Bullet类的
__init__里直接修改位置、判断越界,这部分移动逻辑应该放在update方法中,初始化只负责创建实例。 - 冷却判断逻辑颠倒:
shootlaser里的self.laser_time - timeoflaser == self.laser_cooldown写反了,应该是当前时间减上次发射时间,而且用==容易因帧率问题错过触发,改用>=更稳妥。 - 精灵组未正确使用:创建了
shoot精灵组却没在主循环更新、绘制,反而单独绘制了错误的bullet实例。
修正后的完整代码
import pygame # 初始化设置 pygame.init() screen = pygame.display.set_mode((700, 700), pygame.RESIZABLE) pygame.display.set_caption('ZAP!') icon = pygame.image.load('download.jpg') pygame.display.set_icon(icon) clock = pygame.time.Clock() running = True # 背景设置 bg = pygame.image.load('ok_proper.jpg') bg_pic = pygame.transform.scale(bg, (700, 700)) class Bullet(pygame.sprite.Sprite): def __init__(self, pos): super().__init__() # 加载并处理子弹图片 self.image = pygame.transform.rotate(pygame.transform.scale(pygame.image.load('Graphics/yes.png'), (100, 100)), 90) # 直接用pos设置topright,self.rect.topright本身就是元组,无需额外加括号 self.rect = self.image.get_rect(topright=pos) self.speed = 10 def update(self): # 子弹向上移动 self.rect.y -= self.speed # 超出屏幕顶部就销毁子弹 if self.rect.bottom < 0: self.kill() class Spaceship(pygame.sprite.Sprite): def __init__(self): super().__init__() self.image = pygame.image.load('Graphics/spaceship.png') self.rect = self.image.get_rect(bottomleft=(250, 700)) self.speed = 5 self.laser_time = 0 self.laser_cooldown = 600 self.ready = True self.shoot = pygame.sprite.Group() def movement(self): keys = pygame.key.get_pressed() # 向右移动,边界判断改用屏幕宽度更灵活 if (keys[pygame.K_RIGHT] or keys[pygame.K_d]) and self.rect.right + self.speed < screen.get_width(): self.rect.x += self.speed # 向左移动 elif (keys[pygame.K_LEFT] or keys[pygame.K_a]) and self.rect.x - self.speed > 0: self.rect.x -= self.speed # 发射子弹 if keys[pygame.K_SPACE] and self.ready: self.shootlaser() self.ready = False self.laser_time = pygame.time.get_ticks() def shootlaser(self): # 冷却时间判断逻辑修正 if not self.ready: time_now = pygame.time.get_ticks() if time_now - self.laser_time >= self.laser_cooldown: self.ready = True else: # 传入飞船的topright坐标创建子弹 self.shoot.add(Bullet(self.rect.topright)) def update(self): self.movement() # 更新子弹组的所有子弹 self.shoot.update() # 创建飞船实例 spaceship = Spaceship() while running: clock.tick(60) screen.blit(bg_pic, (0, 0)) # 事件处理 for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # 更新飞船状态 spaceship.update() # 绘制飞船 screen.blit(spaceship.image, spaceship.rect) # 绘制所有子弹 spaceship.shoot.draw(screen) pygame.display.update()
关键修改点
- 删除了错误的
bullet = Bullet(spaceship)代码,不再创建无效的子弹实例。 - 将Bullet的移动、越界逻辑移到
update方法,初始化只做基础设置。 - 修正冷却时间判断逻辑,确保冷却结束后能正确恢复发射状态。
- 主循环中通过
spaceship.shoot.draw(screen)绘制所有子弹,利用精灵组统一管理。 - 简化了
get_rect的参数写法,直接使用传入的pos元组。
内容的提问来源于stack exchange,提问作者Madhav Koduvayur
相关产品推荐
相关产品推荐

