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

Pygame按下按键控制对象变速时窗口冻结问题求助

Pygame窗口冻结问题修复(按键触发变速功能)

你的程序按下J键后窗口冻结,根源是GameObject.a()方法里的while speedfactor > 0循环——这个循环会阻塞游戏主循环,导致Pygame无法处理窗口事件(比如关闭、刷新),直接卡死。Pygame的所有逻辑都必须在主循环的每一帧里增量执行,不能用这种阻塞式的循环。

解决方案

把变速逻辑拆到游戏主循环的每一帧中,用状态变量跟踪变速过程,逐步更新对象位置和速度,直到完成指定的变速时长。

修改后的完整代码

import pygame

class GameObject(pygame.sprite.Sprite):
    all_objects = pygame.sprite.Group()
    def __init__(self, x, y, obj_type):
        super().__init__()
        self.image = pygame.Surface((20, 20))
        self.image.fill((255, 0, 0))
        self.rect = self.image.get_rect()
        self.rect.center = [x, y]
        self.obj_type = obj_type  
        self.speedfactor = None
        # 新增变速状态变量
        self.is_changing_speed = False
        self.current_speed = 0.0
        self.move_direction = ''
        self.speed_step = 0.2  # 每帧速度变化量
        self.target_frames = 0  # 变速持续的总帧数
        self.elapsed_frames = 0  # 已运行帧数
        self.is_speeding_up = False  # True加速,False减速
        GameObject.all_objects.add(self)

    def move(self):
        if self.obj_type == "P":
            keys = pygame.key.get_pressed()
            if keys[pygame.K_w]:
                self.rect.y -= 1
            if keys[pygame.K_a]:
                self.rect.x -= 1
            if keys[pygame.K_s]:
                self.rect.y += 1
            if keys[pygame.K_d]:
                self.rect.x += 1

    def getKicked(self):
        if self.obj_type == "O":
            print("kick")

    # 初始化变速状态,不再执行阻塞循环
    def start_speed_change(self, direction, initial_speed, time_seconds, sp=False):
        if self.is_changing_speed:
            return  # 避免重复触发
        self.is_changing_speed = True
        self.current_speed = float(initial_speed)
        self.move_direction = direction
        self.is_speeding_up = sp
        # 计算总帧数:time_seconds * 帧率(主循环是30帧/秒)
        self.target_frames = int(time_seconds * 30)
        self.elapsed_frames = 0

    def update(self):
        # 处理变速逻辑
        if self.is_changing_speed:
            # 更新位置
            if self.move_direction == 'r':
                self.rect.x = max(0, min(self.rect.x + self.current_speed, 800 - self.rect.width))
            elif self.move_direction == 'u':
                self.rect.y = max(0, min(self.rect.y - self.current_speed, 600 - self.rect.height))
            elif self.move_direction == 'l':
                self.rect.x = max(0, min(self.rect.x - self.current_speed, 800 - self.rect.width))
            elif self.move_direction == 'd':
                self.rect.y = max(0, min(self.rect.y + self.current_speed, 600 - self.rect.height))
            
            # 更新速度
            if self.is_speeding_up:
                self.current_speed += self.speed_step
            else:
                self.current_speed -= self.speed_step
                # 减速到0后停止
                if self.current_speed <= 0:
                    self.current_speed = 0
                    self.is_changing_speed = False
            
            # 更新帧数,达到目标时长后停止
            self.elapsed_frames += 1
            if self.elapsed_frames >= self.target_frames:
                self.is_changing_speed = False

        # 原有碰撞检测逻辑
        collisions = pygame.sprite.spritecollide(self, GameObject.all_objects, False)
        for obj in collisions:
            if obj != self and self.obj_type != obj.obj_type:
                print(f"Collision detected with {obj.obj_type} object")
            if self.obj_type == "O" and obj.obj_type == "P":
                self.getKicked()

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("COLLISION TEST")
screenrect = screen.get_rect()

obj4 = GameObject(200,100, "J")

clock = pygame.time.Clock()
FPS = 30

running = True
while running:
    clock.tick(FPS)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        # 用事件触发变速,避免按住J键重复触发
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_j and obj4.obj_type == "J":
                # 参数:方向、初始速度、持续时间(秒)、是否加速
                obj4.start_speed_change('r', 2, 1, False)

    for obj in GameObject.all_objects:
        obj.move()
        obj.update()

    screen.fill((0, 0, 0))
    for obj in GameObject.all_objects:
        screen.blit(obj.image, obj.rect)
    pygame.display.flip()

pygame.quit()

关键修改说明

  • 移除了原a()方法中的阻塞循环,改用start_speed_change()初始化变速状态
  • 添加状态变量跟踪变速进度、当前速度、移动方向等核心参数
  • 在update()方法中,每一帧增量更新对象位置和速度,直到完成指定时长或速度降为0
  • 改用KEYDOWN事件触发变速,避免按住J键时重复启动变速过程
  • 保留了原有的碰撞检测逻辑,同时限制对象移动范围防止超出窗口边界

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 19:05:02