You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pygame开发Flappy Bird:Colliderect碰撞检测误触发问题求助

Flappy Bird Pygame 碰撞检测异常问题解决

问题根源

你的碰撞检测异常是因为pipes列表没有被正确维护:每次调用Pipe.draw()时,都会往列表里追加新的管道Rect,但从未清空旧的。随着游戏运行,列表里会堆积大量已经移出屏幕的历史管道Rect,小鸟会和这些不存在的“幽灵管道”发生错误碰撞。

另外,代码里直接硬编码操作pipe和pipe2对象,后续扩展多管道时会更难维护。

修复方案

  1. 每帧清空管道Rect列表:在绘制管道前清空pipes,只保留当前帧的有效管道Rect。
  2. 批量控制管道滚动:不要单独操作pipe和pipe2,改用列表管理所有管道实例,统一设置滚动速度。
  3. 优化管道生成逻辑:确保管道重置时的Y轴范围合理,避免管道位置异常。

修改后的完整代码

import pygame, sys
from pygame.locals import QUIT
import random

WHITE = (255, 255, 255)
YELLOW = (255, 255, 0)
GREY = (100, 100, 100)
CLOCK = pygame.time.Clock()

class Bird:
    def __init__(self):
        self.__x = 20
        self.__y = screen_y / 2
        self.__vel = 16
        self.death = False
        self.rect = None  # 提前初始化rect
    
    def flap(self):
        if not self.death:
            self.__vel = 16

    def gravity(self):
        if not self.death:
            self.__y -= self.__vel
            self.__vel -= 2
            if self.__vel > 15:
                self.__vel = 15
            # 限制小鸟不超出屏幕底部,碰到直接死亡
            if self.__y > (screen_y - 50):
                self.__y = screen_y - 50
                self.death = True

    def draw(self):
        self.rect = pygame.draw.rect(DISPLAYWINDOW, YELLOW, (self.__x, self.__y, 50, 50))

    def collide(self, pipes_rects, pipe_objects):
        for pipe_rect in pipes_rects:
            if self.rect.colliderect(pipe_rect):
                # 停止所有管道滚动
                for pipe in pipe_objects:
                    pipe.set_scroll(0)
                print("damn you collision")
                self.death = True


class Pipe:
    def __init__(self, x):
        self.__x = x
        self.__y = random.randint(275, 450)  # 初始化就随机Y轴位置
        self.__w = 70
        self.__h = 700
        self.__scroll = 7.5       # world scroll

    def get_w(self):
        return self.__w

    def set_scroll(self, x):
        self.__scroll = x

    def move(self):
        if self.__scroll > 0:
            self.__x -= self.__scroll

    def draw(self):
        # 返回当前管道的Rect,而非直接追加到全局列表
        bottom_rect = pygame.draw.rect(DISPLAYWINDOW, WHITE, (self.__x, self.__y, self.__w, self.__h))
        # 如果需要顶部管道,取消注释下面一行
        # top_rect = pygame.draw.rect(DISPLAYWINDOW, WHITE, (self.__x, (self.__y - self.__h) - 250, self.__w, self.__h))
        # return [bottom_rect, top_rect]
        return [bottom_rect]

    def generation(self):
        if self.__x < 0 - self.__w:
            self.__y = random.randint(275, 450)
            self.__x = screen_x + self.__w


pygame.init()
screen_x = 500
screen_y = 700
DISPLAYWINDOW = pygame.display.set_mode((screen_x, screen_y))

# 用列表管理所有管道实例,替代硬编码的pipe和pipe2
pipe_objects = []
pipe_objects.append(Pipe(screen_x))
pipe_objects.append(Pipe((screen_x * 1.5) + pipe_objects[0].get_w()))

bird = Bird()

while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            bird.flap()
        
    DISPLAYWINDOW.fill(GREY)
    
    bird.draw()
    bird.gravity()
    
    # 每帧清空管道Rect列表,重新收集当前帧的有效管道Rect
    pipes_rects = []
    for pipe in pipe_objects:
        pipes_rects.extend(pipe.draw())
        pipe.move()
        pipe.generation()
    
    # 传入管道Rect列表和实例列表进行碰撞检测
    bird.collide(pipes_rects, pipe_objects)
    
    pygame.display.update()
    CLOCK.tick(30)

关键修改点

  • 新增pipe_objects列表管理所有管道实例,避免硬编码操作单个管道
  • pipes_rects每帧清空后重新收集当前管道的Rect,彻底解决历史Rect堆积问题
  • 碰撞检测时批量控制所有管道停止滚动,扩展性更强
  • 增加小鸟碰地面直接死亡的逻辑,符合游戏规则
  • 管道初始化时直接随机Y轴位置,逻辑更简洁

内容的提问来源于stack exchange,提问作者Apple_Retainer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 03:35:20