当前位置: 首页 > news >正文

为什么游戏会出现“卡顿”:`clock.tick()` v.s. `clock.get_fps()`

running = True
while running:# 事件处理# 帧处理(如,更新、绘制和渲染画面).....# 控制目标帧率为60 FPSclock.tick(60)  

程序片断中,clock.tick(60) 设定的60 FPS,即设定帧停顿时间为(1/60秒),那么,问题来了:当“帧处理”时间大于(1/60秒)呢?

一、clock.tick(target_fps)

当上述问题出现时,当然要等“帧处理”完,此时,帧刷新的间隔就大于(1/60秒),即此时帧率小于60 FPS。

clock.tick(target_fps)设定的是目标帧率( clock.tick(60) 设定的目标帧率为60 FPS),它是**“最大目标帧率”,即程序尝试达到的理想上限,但实际帧率可能低于目标帧率**,而不会高于目标帧率。这是由 clock.tick() 的工作机制和游戏实际运行负载决定的。

“限制上限”,而非“保证达到”

clock.tick(60) 的本质是:让主循环每秒最多执行60次(即每帧至少间隔约16.67毫秒,1/60秒)。它的工作流程是:

  1. 记录上一帧的结束时间;
  2. 计算当前帧的处理时间(从帧开始到调用 tick() 前的耗时);
  3. 如果处理时间小于16.67毫秒:自动等待剩余时间(例如处理用了10毫秒,就等待6.67毫秒),确保每帧总耗时≥16.67毫秒,从而限制帧率不超过60 FPS;
  4. 如果处理时间大于16.67毫秒:不等待(因为已经超时),直接进入下一帧,此时实际帧率会低于60 FPS(例如处理用了33毫秒,实际帧率约30 FPS)。

实际帧率与目标帧率的关系

  • 实际帧率 ≤ 目标帧率

    • 当游戏逻辑简单、绘制压力小时(如静态画面、少量精灵),每帧处理时间<16.67毫秒,tick() 会通过等待补全时间,实际帧率等于目标帧率(60 FPS);
    • 当游戏逻辑复杂、绘制压力大时(如大量精灵、复杂特效),每帧处理时间>16.67毫秒,tick() 无法“压缩时间”,实际帧率低于目标帧率(例如30 FPS)。
  • 实际帧率不会大于目标帧率
    因为 tick() 会强制等待剩余时间(即使处理时间很短),确保每秒最多60帧,避免帧率过高导致的资源浪费(如显卡过度渲染)。

举例说明

假设目标帧率60 FPS(每帧理想耗时16.67毫秒):

  1. 简单场景:每帧处理(逻辑+绘制)仅用10毫秒 → tick() 等待6.67毫秒 → 总耗时16.67毫秒 → 实际帧率=60 FPS(等于目标);
  2. 复杂场景:每帧处理用了20毫秒(超过16.67毫秒) → tick() 不等待 → 总耗时20毫秒 → 实际帧率=50 FPS(低于目标);
  3. 极端复杂场景:每帧处理用了50毫秒 → 实际帧率=20 FPS(远低于目标)。

为什么游戏会出现“卡顿”

clock.tick(target_fps) 是**“上限锁”:保证帧率不会超过目标值,但无法保证达到目标值。实际帧率最终由每帧的处理成本**(逻辑复杂度、精灵数量、绘制压力等)决定:

  • 处理成本低 → 实际帧率=目标帧率;
  • 处理成本高 → 实际帧率<目标帧率(成本越高,帧率越低)。

这也是为什么游戏会出现“卡顿”——当实际帧率远低于目标帧率时,画面更新变慢,不能满足视觉对动画速度的要求,你就感觉到“卡顿”。
此时需要优化代码(如减少精灵、简化绘制)来降低每帧成本,让实际帧率接近目标值。

二、clock.get_fps()

既然,感觉到“卡顿”:“实际帧率<目标帧率”,那么,如何知道“卡顿”时的“实际帧率”是多少呢?

clock.get_fps() 是 Pygame 中 pygame.time.Clock 类的一个方法,用于获取游戏当前的平均帧率(FPS,Frames Per Second),即每秒实际运行的帧数。它是调试游戏性能、监控流畅度的重要工具。

基本用法与原理

  1. 前提:需先创建 Clock 对象(clock = pg.time.Clock()),并在主循环中通过 clock.tick(target_fps) 控制目标帧率(如 clock.tick(60) 表示目标60 FPS)。
  2. 作用get_fps() 会计算并返回最近一段时间内的平均帧率(非瞬时值,而是平滑后的结果),单位为“帧/秒”。
  3. 原理:基于 clock.tick() 的调用记录,通过计算相邻两帧的时间间隔,自动统计最近几帧的平均耗时,进而反推出帧率(帧率 = 1/平均每帧耗时)。

示例:显示当前帧率

import pygame as pg
pg.init()screen = pg.display.set_mode((800, 600))
pg.display.set_caption("帧率监控示例")
clock = pg.time.Clock()  # 创建Clock对象# 加载字体(用于显示帧率)
try:font = pg.font.SysFont("SimHei", 24)
except:font = pg.font.SysFont(None, 24)running = True
while running:# 事件处理for event in pg.event.get():if event.type == pg.QUIT:running = False# 控制目标帧率为60 FPS(实际帧率可能低于此值)clock.tick(60)  # 必须调用,否则get_fps()无法计算帧率# 获取当前平均帧率(浮点数)current_fps = clock.get_fps()# 绘制screen.fill((0, 0, 0))  # 黑色背景# 显示帧率文本(保留1位小数)fps_text = font.render(f"FPS: {current_fps:.1f}", True, (0, 255, 0))screen.blit(fps_text, (20, 20))  # 左上角显示pg.display.flip()pg.quit()

特点

  • 非瞬时值:返回的是“最近几帧”的平均值(而非当前这一秒的精确值),避免帧率波动导致的数值剧烈变化(例如,某一帧卡顿会被后续帧平滑)。
  • 依赖 tick():必须在主循环中调用 clock.tick(target_fps),否则 get_fps() 会返回 0(因为没有帧间隔数据)。
  • 性能参考:返回值反映游戏当前的实际流畅度——若远低于目标帧率(如目标60 FPS,实际仅30 FPS),说明存在性能瓶颈(如精灵过多、绘制逻辑复杂)。

用途

  1. 性能调试:通过观察帧率变化,定位性能问题(如打开某特效后帧率骤降,说明该特效消耗过多资源)。
  2. 动态优化:根据实际帧率调整游戏逻辑(如帧率过低时,临时降低精灵数量或简化绘制效果)。
  3. 玩家体验监控:在开发版中显示帧率,确保游戏在目标设备上能稳定运行(通常需保持30 FPS以上,60 FPS为理想状态)。
  • 帧率数值会受硬件性能、游戏逻辑复杂度影响(例如,同一段代码在高性能电脑上可能60 FPS,在低配设备上可能30 FPS)。

总之,clock.get_fps() 是游戏性能调优的“晴雨表”,通过它可以直观了解游戏的运行流畅度,是开发中不可或缺的工具。

http://www.lryc.cn/news/621879.html

相关文章:

  • 【Cuda 编程思想】LinearQaunt-分块量化矩阵乘法计算过程
  • 25. 移动端-uni-app
  • 【URP】[光栅阶段][光栅插值]Unity透视校正插值
  • 2025年最新政策下,劳务报酬的增值税应该如何计算?
  • MqSQL中的《快照读》和《当前读》
  • Prometheus 监控 Kubernetes Cluster 最新极简教程
  • [论文笔记] WiscKey: Separating Keys from Values in SSD-Conscious Storage
  • DeepSeek-V2:一种强大、经济且高效的混合专家语言模型
  • 在 macOS 上顺利安装 lapsolver
  • 从根本上解决MAC权限问题(关闭sip)
  • vue3 wangeditor5 编辑器,使用方法
  • demo 通讯录 + 城市选择器 (字母索引左右联动 ListItemGroup+AlphabetIndexer)笔记
  • 分布式锁:从理论到实战的深度指南
  • 【机器人-基础知识】ROS常见功能架构
  • 微软自曝Win 11严重漏洞:可导致全盘数据丢失
  • Kafka生产者原理深度解析
  • 从ChatGPT到智能助手:Agent智能体如何颠覆AI应用
  • Python爬虫反爬检测失效问题的代理池轮换与请求头伪装实战方案
  • 【121页PPT】智慧方案智慧综合体智能化设计方案(附下载方式)
  • java + html 图片点击文字验证码
  • 结构体(Struct)、枚举(Enum)的使用
  • 电源测试系统ATECLOUD-Power,让您告别电源模块测试痛点!
  • MLOps已死,AgenticOps当立:构建新一代AI智能体的全新工程范式
  • 【Redis】Redis典型应用——分布式锁
  • 【部署K8S集群】 1、安装前环境准备配置
  • k8s1.28.2集群部署istioctl的1.20.0版本(X86架构)
  • Mac(一)常用的快捷键整理
  • Mac Mysql 卸载
  • 18- 网络编程
  • Java ArrayList的介绍及用法