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

为什么游戏会出现“卡顿”:`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.xdnf.cn/news/18016.html

相关文章:

  • 【uni-app】根据角色/身份切换显示不同的 自定义 tabbar
  • 线性代数 · 直观理解矩阵 | 空间变换 / 特征值 / 特征向量
  • CERT/CC警告:新型HTTP/2漏洞“MadeYouReset“恐致全球服务器遭DDoS攻击瘫痪
  • 机械加工元件——工业精密制造的璀璨明珠
  • Day14: Flask太空站搭建指南:从零到超光速的Web开发之旅
  • git clone https://gh.llkk.cc/
  • C++从入门到实战(十九)C++ vector容器及其常用接口
  • 电子电路学习日记
  • qt项目中解决关闭弹窗后执行主界面的信号槽时闪退问题
  • MySql——聚簇索引(主键索引)和非聚簇索索引(非主键索引)引区别(即聚集索引和非聚集索引区别)
  • Java 学习笔记(基础篇2)
  • Docker build创建镜像命令入门教程
  • **超融合架构中的发散创新:探索现代编程语言的挑战与机遇**一、引言随着数字化时代的快速发展,超融合架构已成为IT领域的一种重要趋势
  • ts概念讲解
  • Vue 3 + TypeScript:package.json 示例 / 详细注释说明
  • 基于Java飞算AI的Spring Boot聊天室系统全流程实战
  • 快速部署一个鉴黄服务
  • 前端vue框架
  • 【机器人-开发工具】ROS 2 (4)Jetson Nano 系统Ubuntu22.04安装ROS 2 Humble版本
  • 【Java 后端】Spring Boot 集成 JPA 全攻略
  • Nginx学习笔记(九)—— Nginx Rewrite深度解析
  • 版本更新!FairGuard-Mac加固工具已上线!
  • win11右键菜单改回win10样式
  • Data Augmentation数据增强
  • EtherCAT概念介绍
  • EchoEar喵伴接入小聆AI,MCP服务轻松体验,智能升级!
  • 低配硬件运行智谱GLM-4.5V视觉语言模型推理服务的方法
  • 如何基于langchain基类LLM自定义大模型
  • 飞算JavaAI开发全流程解析:从自然语言到可运行工程的智能进化
  • 从零开始学Python之数据结构(字符串以及数字)