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

Pygame动画卡顿不流畅,如何优化解决?

Pygame圆周动画卡顿问题排查与解决

问题描述

使用基础Python/Pygame实现沿圆周路径运动的旋转圆形动画时,白色圆形运动卡顿、不流畅,移动时呈现跳跃/弹跳效果:

  • 设备配置:Pygame 2.4.0(SDL 2.26.4)、Python 3.9.7、Windows系统、8GB内存、1.6GHz四核Corei5-8265U
  • 设备运行其他简单图形/动画无异常,当前动画已设置较低帧率和步长,卡顿问题仍存在

代码示例

import pygame
from pygame.locals import *
import math
pygame.init()
screen = pygame.display.set_mode((1080, 720))
ORIGIN_X, ORIGIN_Y = 540, 360
RADIUS = 100
clock = pygame.time.Clock()
FRAME_RATE = 60
WHITE = (255, 255, 255)
BLACK = (  0,   0,   0)
PATH_RADIUS = 200
THETA_STEP = -3
def draw_objects(surface):
    pygame.draw.circle(surface, WHITE, centre_rotated_surface, RADIUS)
    pygame.draw.line(surface, BLACK, (0, surface_height // 2), (surface_width, surface_height // 2), 1)
    return
def rotate_objects(surface, angle):
    rect_surface = surface.get_rect()
    surface_rotated = pygame.transform.rotate(surface, angle)
    rect_rotated_surface = surface_rotated.get_rect()
    centre_rotated_surface = rect_rotated_surface.center
    return surface_rotated, centre_rotated_surface
surface_width, surface_height = 2 * RADIUS, 2 * RADIUS
surface = pygame.Surface((surface_width, surface_height), SRCALPHA)
centre_rotated_surface = (RADIUS, RADIUS)
draw_objects(surface)
THETA = 0
running = True
while running:
    clock.tick(FRAME_RATE)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    circle_centre_x = round(ORIGIN_X + PATH_RADIUS * math.cos(math.pi * THETA / 180)) 
    circle_centre_y = round(ORIGIN_Y + PATH_RADIUS * math.sin(math.pi * THETA / 180))
    surface_rotated, centre_rotated_surface = rotate_objects(surface, THETA)
    screen.fill(BLACK)
    screen.blit(surface_rotated, (circle_centre_x - surface_width // 2, circle_centre_y - surface_height // 2))
    pygame.display.update()
    THETA = (THETA + THETA_STEP) % 360
pygame.quit()

已尝试无效方案

  • 替换pygame.display.update()为pygame.display.flip()
  • 启用双缓冲

后续补充(2023年6月2日)

已修正数学逻辑,但卡顿问题仍存在,动画呈现明显跳跃感。


解决方法

1. 取消坐标取整,避免像素跳跃

代码中对circle_centre_x和circle_centre_y使用round()强制转为整数坐标,导致物体移动时出现像素级跳跃。直接保留浮点坐标即可,Pygame支持浮点值的blit位置参数:

# 移除round()函数
circle_centre_x = ORIGIN_X + PATH_RADIUS * math.cos(math.pi * THETA / 180) 
circle_centre_y = ORIGIN_Y + PATH_RADIUS * math.sin(math.pi * THETA / 180)

2. 优化旋转操作,减少性能开销

当前每帧调用pygame.transform.rotate()生成新表面是性能瓶颈之一,可直接在屏幕上绘制旋转后的图形,避免重复创建表面:

# 删除原draw_objects和rotate_objects函数
# 主循环内修改绘制逻辑:
screen.fill(BLACK)
# 计算圆形当前位置
circle_pos = pygame.math.Vector2(circle_centre_x, circle_centre_y)
# 计算旋转后的线段端点
line_start = circle_pos + pygame.math.Vector2(-RADIUS, 0).rotate(-THETA)
line_end = circle_pos + pygame.math.Vector2(RADIUS, 0).rotate(-THETA)
# 绘制圆形和线段
pygame.draw.circle(screen, WHITE, circle_pos, RADIUS)
pygame.draw.line(screen, BLACK, line_start, line_end, 1)
pygame.display.update()

3. 启用硬件加速与双缓冲

初始化窗口时添加硬件加速和双缓冲标志,提升渲染效率:

screen = pygame.display.set_mode((1080, 720), pygame.HWSURFACE | pygame.DOUBLEBUF)

4. 简化重复运算

将弧度转换的常量提前定义,减少每帧重复计算:

DEG_TO_RAD = math.pi / 180
# 主循环内使用常量计算
circle_centre_x = ORIGIN_X + PATH_RADIUS * math.cos(THETA * DEG_TO_RAD) 
circle_centre_y = ORIGIN_Y + PATH_RADIUS * math.sin(THETA * DEG_TO_RAD)

5. 排查实际帧率

通过clock.get_fps()获取实际运行帧率,如果实际帧率远低于设定的60,说明存在性能瓶颈,可适当降低帧率或简化绘制逻辑:

# 主循环内添加打印
print(f"实际帧率:{clock.get_fps():.1f}")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 16:23:30