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

Pygame精灵碰撞检测实现:双可控精灵碰撞穿模及卡死崩溃问题求解

问题原因

  • 执行顺序倒置:现有代码先做碰撞检测,后执行精灵移动,碰撞检测完全针对上一帧的位置,逻辑完全不生效
  • 死循环触发逻辑:当精灵已经处于碰撞状态时,while循环会不断把位置回退到碰撞前的坐标,碰撞状态始终不解除,程序直接卡死在循环里
  • 回滚逻辑不合理:同时回滚两个精灵的位置,会出现双方同时按移动键时完全没法靠近、或者单方向移动也会被拽回的问题

修复方案

调整主循环的执行顺序为:「获取按键 → 保存两个精灵的上一帧坐标 → 执行两个精灵的移动逻辑 → 碰撞检测 → 碰撞时回滚位置 → 绘制画面」,同时把while循环改成单次if判断即可,一帧只需要做一次碰撞检测,回滚到上一帧位置就可以解除碰撞。
如果要更好的交互体验,也可以只回滚主动移动导致碰撞的精灵,最简单的通用实现是两个精灵各自回滚自己的上一帧位置,谁触发碰撞谁退回去。

修正后代码

import pygame
from pygame.locals import *

displayWidth = 500
displayHeight = 500
display = pygame.display.set_mode((displayWidth,displayHeight))
clock = pygame.time.Clock()

class Player(pygame.sprite.Sprite):
    def __init__(self,image,x,y):
        super().__init__()
        self.image = image
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
    def move(self, keyPress,kup,kdown,kleft,kright):
        if keyPress[kup]:
            self.rect.move_ip(0,-5)
        if keyPress[kdown]:
            self.rect.move_ip(0,5)
        if keyPress[kleft]:
            self.rect.move_ip(-5,0)
        if keyPress[kright]:
            self.rect.move_ip(5,0)
        if self.rect.left < 0:
            self.rect.left = 0
        if self.rect.right > displayWidth:
            self.rect.right = displayWidth
        if self.rect.top < 0:
            self.rect.top = 0
        if self.rect.bottom > displayHeight:
            self.rect.bottom = displayHeight

pygame.init()
pygame.display.set_caption("Collision Detection")

# 替换为自己的本地图片路径即可
sprite1 = Player(pygame.image.load("Images/down.png"),0,0)
enemy1 = Player(pygame.image.load("Images/up.png"),100,100)
player_list = pygame.sprite.Group()
enemy_list = pygame.sprite.Group()
player_list.add(sprite1)
enemy_list.add(enemy1)

gameRunning = True
while gameRunning == True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gameRunning = False
    display.fill([0,0,0])
    keyPress = pygame.key.get_pressed()
    # 先保存移动前的坐标
    p_prev_x = sprite1.rect.x
    p_prev_y = sprite1.rect.y
    e_prev_x = enemy1.rect.x
    e_prev_y = enemy1.rect.y
    # 执行移动逻辑
    sprite1.move(keyPress,K_UP,K_DOWN,K_LEFT,K_RIGHT)
    enemy1.move(keyPress,K_w,K_s,K_a,K_d)
    # 碰撞后回滚坐标
    if pygame.sprite.collide_rect(sprite1,enemy1):
        sprite1.rect.x = p_prev_x
        sprite1.rect.y = p_prev_y
        enemy1.rect.x = e_prev_x
        enemy1.rect.y = e_prev_y
    # 最后绘制画面
    player_list.draw(display)
    enemy_list.draw(display)
    pygame.display.flip()
    clock.tick(60)
pygame.quit()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 12:54:04