Pygame开发Flappy Bird生成180度旋转上管道时报rect赋值错误
问题原因
报错直接诱因是Pygame的Rect.get_rect()参数传值不符合规范:
get_rect()的所有锚点参数(bottom/midtop/center等)都只接收格式为(x坐标, y坐标)的二元整数组,你在设置上管道rect时,给bottom传入了(player_x+AWAY_FROM_BIRD, obstacle_height2),其中obstacle_height2本身已经是提前拼接好的(x,y)元组,最终传入的是嵌套结构(整数, (x,y)),Pygame无法解析该参数所以抛出赋值错误。- 现有障碍物逻辑还有设计缺陷:你把上下两根管道的image、rect属性都绑定在同一个Sprite实例上,后赋值的上管道属性会直接覆盖下管道的属性,最终只能渲染出一根管道;且初始只创建了1个Obstacles实例,后续定时触发逻辑只会反复修改这一个实例的属性,根本无法生成多组连续滚动的管道。
修复方案
- 废弃原有在单个Sprite实例内生成两根管道的逻辑,单个Sprite实例只对应一根管道,初始化时通过参数区分是上管道还是下管道,分别设置旋转状态和锚点定位。
- 修正rect传参逻辑:上下管道共用同一个x坐标,下管道用
midtop锚点定位,上管道的midbottom锚点y值直接设为「下管道top y值 - 管道预留间距」,不需要复杂的列表拼接转换。 - 给管道类添加左移逻辑、离屏自动销毁逻辑,避免无意义的内存占用。
- 调整主循环逻辑:触发管道生成定时器事件时,一次性生成上下配对的两个管道实例加入精灵组,精灵组统一执行更新、绘制操作,不要在Sprite类的方法内直接调用draw。
修复后核心代码
首先提前加载管道资源,避免每次生成都重复读取文件:
# 全局资源加载部分,放在游戏初始化后即可 PIPE_IMG = pygame.image.load("assets/images/obstacles/pipe-green.png").convert_alpha()
替换原有Obstacles类:
class Obstacles(pygame.sprite.Sprite): def __init__(self, x, y, is_top=False): super().__init__() self.image = PIPE_IMG if is_top: # 上管道旋转180度,用midbottom锚点定位 self.image = pygame.transform.rotate(self.image, 180) self.rect = self.image.get_rect(midbottom=(x, y)) else: # 下管道直接用midtop锚点定位 self.rect = self.image.get_rect(midtop=(x, y)) def update(self): # 管道持续左移,速度可根据游戏手感调整 self.rect.x -= 2 # 管道完全移出屏幕左边界后自动销毁 if self.rect.right < 0: self.kill()
修改主循环内的事件处理和渲染逻辑:
while True: event_list = pygame.event.get() for event in event_list: if event.type == pygame.QUIT: pygame.quit() exit() # 把管道生成逻辑移到事件遍历内部 if event.type == OBSTACLESPAWN and GAME_ACTIVE == 1: # 随机生成下管道的顶部y坐标,避开上下边界 pipe_y = random.randint(int(HEIGHT/2 - 100), HEIGHT - 112 - 50) # 生成下管道 bottom_pipe = Obstacles(WIDTH + AWAY_FROM_BIRD, pipe_y, is_top=False) # 生成上管道,和下管道间距固定为OBSTACLE_SPACE top_pipe = Obstacles(WIDTH + AWAY_FROM_BIRD, pipe_y - OBSTACLE_SPACE, is_top=True) obstacle.add(bottom_pipe, top_pipe) if GAME_ACTIVE == 1: SCREEN.blit(background_surf, background_rect) # 先绘制管道,再绘制玩家和地面,保证层级正确 obstacle.draw(SCREEN) obstacle.update() player.draw(SCREEN) player.update() SCREEN.blit(ground_surf, ground_rect) pygame.display.update() clock.tick(FPS)
后续扩展说明
- 修复后代码不会再出现rect赋值报错,会按设定间隔自动生成成对管道,管道自动向左滚动,离屏后自动销毁。
- 后续添加碰撞检测时,直接调用
pygame.sprite.spritecollide(player.sprite, obstacle, False)即可判断小鸟是否撞到管道,不需要手动遍历所有管道做碰撞计算。
内容的提问来源于stack exchange,提问作者Snabba_Snigeln
相关产品推荐
相关产品推荐

