Pygame摆锤模拟程序失焦(切出窗口)时崩溃无响应
摆锤模拟窗口失焦崩溃问题修复方案
问题根源
你的代码核心问题出在主循环被长时间阻塞:
simulatePendulum方法内部包含一个长达100万次的循环(tMax=10000、dt=0.01,计算下来循环次数近百万),每次主循环调用这个方法时,程序会死死卡在这个循环里,完全无法处理Pygame的系统事件(包括窗口失焦、最小化、关闭等)。- 系统检测到窗口长时间没有响应事件,就会判定窗口崩溃;而控制台因为数学计算在后台持续运行,所以能正常输出。
- 同时存在重复渲染:
simulatePendulum里每步调用draw,主循环又再次调用draw,造成冗余的资源消耗。
修复后的完整代码
import pygame import numpy as np pygame.init() WIDTH = 800 HEIGHT = 500 res = (WIDTH, HEIGHT) screen = pygame.display.set_mode(res) clock = pygame.time.Clock() WHITE = [255, 255, 255] RED = [255,0,0] BLACK = [0, 0, 0] BLUE = [0, 0, 155] class Pendulum: def __init__(self, theta0, L, dt, pivot, bobMass): self.g = 9.81 self.theta = theta0 self.L = L self.dt = dt self.pivot = pivot self.bobMass = bobMass # 初始化角速度和当前位置 self.omega = 0.0 self.x = self.L * np.sin(self.theta) self.y = self.L * np.cos(self.theta) def update(self): # 逐帧更新摆锤状态(每次只计算一步) self.omega += self.dt * (-self.g / self.L * np.sin(self.theta)) self.theta += self.dt * self.omega self.x = self.L * np.sin(self.theta) self.y = self.L * np.cos(self.theta) def draw(self): bobPos = (self.x + 400, self.y + 300) pivotPos = (self.pivot[0] + 400, self.pivot[1] + 300) screen.fill(WHITE) pygame.draw.line(screen, RED, pivotPos, bobPos, 2) pygame.draw.circle(screen, BLUE, pivotPos, 5) pygame.draw.circle(screen, BLACK, bobPos, 10) pygame.display.update() def main(): theta0 = np.pi/4 L = 100 dt = 0.01 pivot =(0,0) bobMass=1 p = Pendulum(theta0, L, dt, pivot, bobMass) done = False while not done: # 优先处理所有事件,确保窗口能响应系统操作 for event in pygame.event.get(): if event.type == pygame.QUIT: done = True # 可选:检测窗口焦点状态,可扩展暂停/继续功能 elif event.type == pygame.ACTIVEEVENT: if event.gain == 0: print("窗口失焦") else: print("窗口恢复焦点") # 逐帧更新摆锤状态并渲染 p.update() p.draw() clock.tick(60) pygame.quit() if __name__ == "__main__": main()
关键修复说明
拆分模拟逻辑:
- 移除了一次性跑完所有模拟步骤的
simulatePendulum方法,换成逐帧更新的update方法,每次主循环只计算一步摆锤状态,彻底避免阻塞事件处理流程。 - 让类内部保存摆锤的当前状态(角度、角速度、位置),不再预计算所有时间点的数据。
- 移除了一次性跑完所有模拟步骤的
统一渲染流程:
- 把
draw调用移到主循环中统一执行,移除模拟过程中的重复渲染,减少资源浪费。
- 把
强化事件处理:
- 确保事件循环在主循环中优先执行,让程序能及时响应窗口失焦、最小化等系统事件,避免被判定为无响应。
- 可选添加了
ACTIVEEVENT事件监听,方便扩展窗口失焦时暂停模拟的功能。
精简冗余代码:
- 移除了
tMax、scale、pivotRadius等未实际使用的参数,简化代码结构。
- 移除了
内容的提问来源于stack exchange,提问作者Archie
相关产品推荐
相关产品推荐

