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
相关产品推荐
相关产品推荐

