Pygame同组精灵碰撞差异化反应实现(两车道合流模拟)
问题根因
现有代码的碰撞逻辑存在三个直接导致全车道堵死的缺陷:
- 碰撞检测未区分前后车:
spritecollide会将当前车辆自身计入碰撞结果,且只要检测到碰撞就直接将当前车辆速度设为0,无论当前车处于前车还是后车位置,最终形成前车被后车“撞停”的连锁死锁 - 并道触发点逻辑混乱:
merge=random.randint(500,1000)写在update方法中,每帧都会随机重置,车辆并道行为完全不稳定 - 下行车道(Car_down)未实现碰撞逻辑,两车道合并时会与上行车直接刚性碰撞锁死
修复方案
核心调整四点逻辑:
- 仅检测车辆前方的局部区域:为每辆车生成车头前方的小范围碰撞检测区,只有该区域碰到其他车辆时,才判定当前车为后车,需要减速/停车
- 碰撞判定排除自身,仅当碰撞对象位于当前车前方时才触发减速
- 将并道触发点从帧更新逻辑移到车辆初始化阶段,每辆车生成时固定自身的并道位置,避免每帧随机跳变
- 为下行车道补充一致的跟车、碰撞处理逻辑
修复后完整代码
import pygame import random from pygame.locals import (QUIT, KEYDOWN, K_ESCAPE) # 常量定义 SCREEN_WIDTH = 1500 SCREEN_HEIGHT = 400 grey = [90, 90, 90] green = [125, 255, 50] spawnrate_up = 700 spawnrate_down = 800 car_size = [75, 35] # 跟车安全距离 SAFE_DISTANCE = 10 class Car_up(pygame.sprite.Sprite): def __init__(self, color, size): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface(size) self.image.fill(color) self.rect = self.image.get_rect() self.rect.x = random.randint(-100, -20) self.rect.y = 150 self.speedx = 10 self.speedy = 0 # 每辆车初始化时固定并道位置,禁止每帧随机 self.merge_point = random.randint(500, 1000) def update(self): # 驶出屏幕自动销毁 if self.rect.left > SCREEN_WIDTH: self.kill() # 初始化默认行驶速度 self.speedx = 10 self.speedy = 0 # 生成车头前方碰撞检测区:仅检测车头前安全距离范围,不检测全车 front_detect_rect = pygame.Rect( self.rect.right, self.rect.top, SAFE_DISTANCE, self.rect.height ) # 检测与同车道前车、下行车道车辆的碰撞 collide_same_lane = pygame.sprite.spritecollideany( self, car_up, collided=lambda curr, other: curr != other and front_detect_rect.colliderect(other.rect) ) collide_other_lane = pygame.sprite.spritecollideany( self, car_down, collided=lambda curr, other: front_detect_rect.colliderect(other.rect) ) # 仅前方有障碍物时停车 if collide_same_lane or collide_other_lane: self.speedx = 0 self.speedy = 0 # 驶过并道点后开始向下并入单车道 elif self.rect.centery <= 263 and self.rect.centerx > self.merge_point: self.speedy = 3 # 更新车辆位置 self.rect.move_ip(self.speedx, self.speedy) class Car_down(pygame.sprite.Sprite): def __init__(self, color, size): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface(size) self.image.fill(color) self.rect = self.image.get_rect() self.rect.x = random.randint(-100, -20) self.rect.y = 250 self.speedx = 10 self.speedy = 0 # 下行车同样固定并道点 self.merge_point = random.randint(500, 1000) def update(self): # 驶出屏幕自动销毁 if self.rect.left > SCREEN_WIDTH: self.kill() self.speedx = 10 self.speedy = 0 # 同步生成前方碰撞检测区 front_detect_rect = pygame.Rect( self.rect.right, self.rect.top, SAFE_DISTANCE, self.rect.height ) # 检测与同车道前车、上行车道车辆的碰撞 collide_same_lane = pygame.sprite.spritecollideany( self, car_down, collided=lambda curr, other: curr != other and front_detect_rect.colliderect(other.rect) ) collide_other_lane = pygame.sprite.spritecollideany( self, car_up, collided=lambda curr, other: front_detect_rect.colliderect(other.rect) ) if collide_same_lane or collide_other_lane: self.speedx = 0 self.rect.move_ip(self.speedx, self.speedy) pygame.init() screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) clock = pygame.time.Clock() # 自定义车辆生成事件 ADDCAR_down = pygame.USEREVENT + 1 ADDCAR_up = pygame.USEREVENT + 2 pygame.time.set_timer(ADDCAR_up, spawnrate_up) pygame.time.set_timer(ADDCAR_down, spawnrate_down) # 初始化车辆精灵组 car_up = pygame.sprite.Group() car_down = pygame.sprite.Group() car_down.add(Car_down(green, car_size)) car_up.add(Car_up(green, car_size)) run = True while run: for event in pygame.event.get(): if event.type == KEYDOWN: if event.key == K_ESCAPE: run = False elif event.type == QUIT: run = False elif event.type == ADDCAR_down: new_car = Car_down(green, car_size) car_down.add(new_car) elif event.type == ADDCAR_up: new_car = Car_up(green, car_size) car_up.add(new_car) screen.fill(grey) car_up.draw(screen) car_up.update() car_down.draw(screen) car_down.update() pygame.display.flip() clock.tick(25) pygame.quit()
可调参数说明
- 修改
SAFE_DISTANCE数值可调整跟车间距,数值越大跟车距离越远 - 若要实现降速跟车而非完全停车,将碰撞触发分支的
self.speedx = 0改为低数值(如3)即可 - 若要模拟拉链式交替通行效果,可为车辆增加等待计时器属性,停车累计到固定时长后自动小幅前进,避免永久锁死
内容的提问来源于stack exchange,提问作者Jrmnp
相关产品推荐
相关产品推荐

