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

如何在Pygame中实现时间与弧长按比例联动的圆形环形倒计时

圆形倒计时效果示例

Pygame 带弧长联动的圆形倒计时实现

其实这个效果的核心难点根本不是手动计算弧长,很多人一开始把问题想复杂了——觉得要先算圆环总周长、再逐帧计算要缩短多少长度,完全没必要。Pygame本身的绘制API已经把这块逻辑封装好了,你只需要把时间占比对应到绘制的角度范围,天然就能保证弧长和剩余时间严格等比例。

核心实现步骤

  • 先固定几个全局参数:总倒计时时长、圆环的圆心坐标、圆环的内外半径、弧的颜色、背景色。这里要对齐Pygame的时间单位,统一用毫秒计算,避免单位不统一导致的比例计算错误。
  • 搞懂Pygame的draw.arc()的角度规则:函数接受的角度是弧度值,0弧度对应的位置是屏幕的3点钟方向,角度沿着逆时针方向递增;因为屏幕坐标系Y轴是向下的,实际绘制出来的视觉旋转方向是顺时针。如果要做常见的“从12点钟方向开始顺时针逐步缩短”的圆环,只要把绘制的起始角度偏移-π/2弧度(也就是90度),就能把起点转到正上方。
  • 保证弧长和时间的同步逻辑:每帧计算当前剩余时间,除以总时长得到当前的剩余占比,这个占比直接乘以整圆的总弧度2π,就是当前需要绘制的弧的总跨度。因为整个圆的周长和弧度是完全线性对应的,所以画出来的弧长永远和剩余时间占比完全一致,不会出现视觉和进度脱节的问题。
  • 性能优化细节:
    • 不要靠draw.arc()的width参数画很粗的线条,边缘会有明显的锯齿。更顺滑的效果是先画一个大的实心圆当圆环的底色,再叠一个小一圈的和背景同色的实心圆,把中间挖空成环形,再在上面画对应进度的弧。
    • 中心的时间数字不要每帧都重新生成字体渲染对象,可以提前初始化字体对象,每次只更新文字内容,把文字块的位置用get_rect(center=圆心坐标)锚定居中,减少不必要的性能消耗。如果需要更精细的倒计时显示(比如精确到0.1秒),只要调整文字的渲染格式就行,因为弧的计算是基于实时剩余毫秒值的,不管数字显示的是整数秒还是小数秒,视觉进度都会和时间严格同步,不需要额外修改绘制逻辑。

最小可运行示例代码

import pygame
import math

pygame.init()
screen = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
# 倒计时基础配置
TOTAL_DURATION = 10 * 1000  # 总时长10秒,单位毫秒
start_timestamp = pygame.time.get_ticks()
CENTER_POS = (250, 250)
OUTER_RADIUS = 150
INNER_RADIUS = 130
PROGRESS_COLOR = (0, 200, 255)
BASE_RING_COLOR = (60, 60, 60)
BG_COLOR = (30, 30, 30)

running = True
while running:
    screen.fill(BG_COLOR)
    # 计算实时剩余时间
    elapsed = pygame.time.get_ticks() - start_timestamp
    remaining = max(0, TOTAL_DURATION - elapsed)
    progress_ratio = remaining / TOTAL_DURATION

    # 绘制底层完整环形
    pygame.draw.circle(screen, BASE_RING_COLOR, CENTER_POS, OUTER_RADIUS)
    pygame.draw.circle(screen, BG_COLOR, CENTER_POS, INNER_RADIUS)

    # 绘制对应进度的弧
    if remaining > 0:
        start_angle = -math.pi / 2  # 起始点对齐12点钟方向
        end_angle = start_angle + progress_ratio * 2 * math.pi
        arc_rect = pygame.Rect(
            CENTER_POS[0] - OUTER_RADIUS,
            CENTER_POS[1] - OUTER_RADIUS,
            OUTER_RADIUS * 2,
            OUTER_RADIUS * 2
        )
        pygame.draw.arc(
            screen,
            PROGRESS_COLOR,
            arc_rect,
            start_angle,
            end_angle,
            width=OUTER_RADIUS - INNER_RADIUS
        )

    # 绘制中心时间数字
    font = pygame.font.SysFont(None, 60)
    time_surface = font.render(f"{int(remaining / 1000)}", True, (255, 255, 255))
    time_rect = time_surface.get_rect(center=CENTER_POS)
    screen.blit(time_surface, time_rect)

    # 事件处理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    pygame.display.flip()
    clock.tick(60)

pygame.quit()

常见踩坑点

  • 很多人第一次写的时候会把角度的方向搞反,最后画出来的弧是逆时针缩短的,只要记住把起始角度偏移-π/2,就符合常规的倒计时视觉习惯,不需要额外做坐标翻转。
  • 计算时间占比的时候一定要统一单位,比如全程用毫秒就不要中途换成秒,不然很容易出现进度比例算错,弧长和时间对不上的问题。
  • 倒计时结束的时候要把剩余时间的最小值卡到0,不然时间流逝超过总时长后,计算出来的占比会变成负数,导致绘制的弧角度异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.24 06:15:03