游戏设计模式阅读 - 游戏循环

news2025/2/24 10:22:33

游戏与普通程序最大的不同点在于:

        游戏不像其他大多数软件,游戏即使在没有玩家输入时也继续运行。 如果你站在那里看着屏幕,游戏也不会冻结。动画会持续播放。视觉效果继续闪烁。 如果运气不好的话,怪物会继续暴揍你的角色。

那么维持这一切的必要条件是什么,在代码层面又是如何维持你的游戏世界不陷入时停的呢?

这个概念就是:循环

循环的意图

        将游戏的进行和玩家的输入解耦,和处理器速度解耦。

事件循环

        游戏即使在没有玩家输入时也继续运行。

        这是真实游戏循环的第一个关键部分:它处理用户输入,但是不等待它

while (true) {
  processInput();
  update();
  render();
}

// processInput()处理上次调用到现在的任何输入。
// update()让游戏模拟一步。 运行AI和物理。
// render()绘制游戏,

什么是帧率

        我们用实际时间来测算游戏循环运行的速度,就得到了游戏的“帧率”(FPS)。如果游戏循环的更快,FPS就更高,游戏运行得更流畅、更快。

两个因素决定了帧率:

1、每帧要做多少工作

        复杂的物理,众多游戏对象,图形细节都让CPU和GPU繁忙,这决定了需要多久能完成一帧。

2、底层平台的速度

         更快的芯片可以在同样的时间里执行更多的代码。 多核,GPU组,独立声卡,以及系统的调度都影响了在一定时间内能够做多少东西。

每秒的帧数

        早期的游戏被仔细地编码,一帧只做一定的工作,开发者可以让游戏以想要的速率运行。

        但是如果你想要在快些或者慢些的机器上运行同一游戏,游戏本身就会加速或减速。

一个游戏循环在游戏运行过程中被不断执行。 每一次循环,它无阻塞地处理玩家输入更新游戏状态渲染游戏。 追踪时间的消耗并控制游戏的速度

优化上面的简易循环代码

        上面代码的问题是无法控制游戏运行得有多快

        假设游戏需要以60FPS运行,那么每帧约等于16ms。只要用少于这个时长处理游戏内的所有内容,就可以以稳定的帧率运行。所需要做的就是处理这一帧,然后等待,直到处理下一帧。

while (true) {
  double start = getCurrentTime();
  processInput();
  update();
  render();
  sleep(start + MS_PER_FRAME - getCurrentTime());
}

但如果每次循环消耗的时间超过16ms,那它永远也跟不上

需要解决的问题:

1、每次更新将游戏时间推动一个固定量。

2、消耗一定量的真实时间来处理它。

因此还可以基于上帧到现在有多少真实时间流逝来选择前进的时间。这一帧花费的时间越长,游戏的间隔越大。

double lastTime = getCurrentTime();
while (true){
  double current = getCurrentTime();
  double elapsed = current - lastTime;
  processInput();
  update(elapsed);
  render();
  lastTime = current;
}

每一帧,计算上次游戏更新到现在有多少真实时间过去了。在更新游戏状态时将其传入,然后游戏引擎内推进一定的时间量。

假设有一颗子弹跨过屏幕。 使用固定的时间间隔,在每一帧中根据它的速度移动它。 使用变化的时间间隔,根据过去的时间拉伸速度。 随着时间间隔增加,子弹在每帧间移动得更远。 无论是二十个快的小间隔还是四个慢的大间隔,子弹在真实时间里移动同样多的距离。

但这个方案也不合理:游戏不再是确定的了,也不再稳定。

游戏时间追逐真实时间

        计算上一次游戏循环过去了消耗了多少真实时间。 为游戏的“当前时间”模拟推进相同长度的时间,以追上玩家的时间。

double previous = getCurrentTime();
double lag = 0.0;
while (true) {
  double current = getCurrentTime();
  double elapsed = current - previous;
  previous = current;
  lag += elapsed;
  processInput();
  while (lag >= MS_PER_UPDATE){
    update();
    lag -= MS_PER_UPDATE;
  }
  render();
}
// 在每帧的开始,根据过去了多少真实的时间来更新lag。 这个变量表明了游戏世界时钟比真实世界落后了多少。
// 使用一个固定时间步长的内部循环进行追赶。 一旦追上真实时间,就执行渲染然后开始新一轮循环
// MS_PER_UPDATE只是更新游戏的间隔。 这个间隔越短,就需要越多的处理次数来追上真实时间。

// 可以通过限制内层循环的最大次数来保证游戏不会完全卡死

由于render()次数比update()次数更少,就有可能出现render()发生在两次update()之间。

因此,需要在lag不为零lagMS_PER_UPDATE更小时,跳出循环进行渲染。 lag的剩余量就是到下一帧的时间。

render(lag / MS_PER_UPDATE);

决策

使用平台的事件循环:

1、简单
        不必担心编写和优化自己的游戏核心循环。

2、平台友好
        你不必明确地给平台一段时间让它处理它自己的事件,不必缓存事件,不必管理任何平台输入模型和你的不匹配之处。

3、失去了对时间的控制。

使用游戏引擎的循环:

1、不必自己编写
        编写游戏循环非常需要技巧。 由于是每帧都要执行的核心代码,小小的漏洞或者性能问题就对游戏有巨大的影响。 稳固的游戏循环是使用现有引擎的原因之一。

2、无法自己编写
        代价就是如果引擎无法满足真正的需求,开发者也没法获得控制权。

自己写:    

1、完全可控
        可以做任何想做的事情。可以为游戏的需求订制开发。

2、需要与平台交互
        应用框架和操作系统通常需要时间片去处理自己的事件和其他工作。 如果拥有应用的核心循环,平台就没有这些时间片了。 开发者得显式定期检查,保证框架没有挂起或者混乱。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2304341.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(五)趣学设计模式 之 建造者模式!

目录 一、 啥是建造者模式?二、 为什么要用建造者模式?三、 建造者模式怎么实现?四、 建造者模式的应用场景五、 建造者模式的优点和缺点六、 总结 🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方…

github 怎么创建一个私有repository 并从另外一台电脑拉取下来更新

1.github上新建一个repository 设置为private tips删除在这 点setting 然后往下拖动 会有个这里是用来删项目的 2.另外 一台电脑拉取这个repository的时候 需要配置 一个ssh key 这个key的内容生成参考本地电脑的生成 然后在这配置 2.1 生成 SSH 密钥(如果还没有…

DeepSeek-R1本地化部署的硬件要求

DeepSeek-R1本地化部署的硬件要求全解析 引言 DeepSeek-R1作为一款高效的AI推理模型,凭借其卓越的推理性能和灵活的训练机制,成为了春节期间的热议话题。 然而,要在本地成功部署DeepSeek-R1,尤其是其满载的 671B 参数版本&#…

AGI觉醒假说的科学反驳:从数学根基到现实约束的深度解析

文章目录 引言:AGI觉醒论的核心迷思一、信息论视角:意识产生的熵约束1.1 香农熵的物理极限1.2 量子退相干的时间屏障二、数学根基:形式系统的自指困境2.1 哥德尔不完备定理的现代诠释三、概念解构:AGI觉醒假说的认知陷阱3.1 术语混淆的迷雾3.2 拟人化谬误的认知根源四、意识…

CSS—盒模型(3分钟结合示例精通盒模型)

个人博客:haichenyi.com。感谢关注 1. 目录 1–目录2–概念3–内容4–内边距5–边框6–外边距7–类型 概念 在HTML中,每一个元素都可以看作一个矩形的盒子。如图 如上图所示,一个一个的矩形都可以堪称一个元素。矩形有大有小,边有…

蓝桥杯 3.搜索

蓝桥杯 3.搜索 文章目录 蓝桥杯 3.搜索DFS回溯DFS剪枝记忆化搜索编程66-75 DFS回溯 回溯法简介 使用**DFS(深度优先搜索)**实现, DFS是一种遍历或搜索图, 树或者图像等数据结构的算法, 当然这个图, 树未必要存储下来(隐式处理就是回溯法)搜索树一般是排列型搜索树 (总节点个数…

STM32的“Unique device ID“能否修改?

STM32F1系列的"Unique device ID"寄存器的地址为0x1FFFF7E8。 这个寄存器是只读的。 "Unique device ID"寄存器位于“System memory”中。“System memory”地址范围为“0x1FFF F000- 0x1FFF F7FF”。 所有STM32 MCU上都存在系统引导加载程序。顾名思义&a…

[内网基础] 内网基础知识 —— Windows 工作组

关注这个专栏的其他相关笔记:[内网安全] 内网渗透 - 学习手册-CSDN博客 0x01:Windows 工作组介绍 在一个大型单位里,可能有成百上千台计算机互相连接组成局域网,如果不对这些计算机进行分组,网络的混乱程度是可想而知…

【新手初学】SQL注入之二次注入、中转注入、伪静态注入

二次注入 一、概念 二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。 二、原理 防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处…

Deepseek存算分离安全部署手册

Deepseek大火后,很多文章教大家部署Dfiy和ollamadeepseek,但是大部分都忽略了数据安全问题,本文重点介绍Deepseek存算分裂安全架设,GPU云主机只负责计算、CPU本地主机负责数据存储,确保数据不上云,保证私有…

单页图床HTML源码+本地API接口图床系统修复版源码

源码介绍 图床系统是一种用于存储和管理图片文件的在线服务。它允许用户上传图片文件,并生成相应的图片链接,从而方便用户在网页、社交媒体或其他平台上分享图片。 PS:源码压缩包分为两个版本,一个是调用360第三方api接口,另外一…

IDEA使用Maven方式构建SpringBoot项目

1、环境准备 确保你已经安装了以下工具: Java JDK(推荐 JDK 8 或更高版本) IntelliJ IDEA(推荐使用最新版本) 2、创建 Spring Boot 项目 (1) 打开 IntelliJ IDEA。 (2&#xff09…

【SPIE出版,见刊快速,EI检索稳定,浙江水利水电学院主办】2025年物理学与量子计算国际学术会议(ICPQC 2025)

2025年物理学与量子计算国际学术会议(ICPQC 2025)将于2025年4月18-20日在中国杭州举行。本次会议旨在汇聚全球的研究人员、学者和业界专家,共同探讨物理学与量子计算领域的最新进展与前沿挑战。随着量子技术的快速发展,其在信息处…

查看cmd下python的安装路径 + Windows 命令行添加环境变量和不重启刷新环境变量

1、查看cmd下python的安装路径 cmd ----》输入“python” 命令 ---》输入 import sys; print(sys.executable) 即可看到当前系统python的安装路径: 注:系统所使用的python实际上就是在系统环境变量下配置的python目录。 2、刷新path命令:在c…

C/C++跳动的爱心

系列文章 序号直达链接1C/C李峋同款跳动的爱心2C/C跳动的爱心3C/C经典爱心4C/C满屏飘字5C/C大雪纷飞6C/C炫酷烟花7C/C黑客帝国同款字母雨8C/C樱花树9C/C奥特曼10C/C精美圣诞树11C/C俄罗斯方块小游戏12C/C贪吃蛇小游戏13C/C孤单又灿烂的神14C/C闪烁的爱心15C/C哆啦A梦16C/C简单…

Cannot deserialize instance of java.lang.String out of START_ARRAY token

这个错误 Cannot deserialize instance of java.lang.String out of START_ARRAY token 表示 Jackson 正在尝试将一个 JSON 数组反序列化成一个 String 类型的字段,但是 JSON 中传递的是一个数组而不是单一的字符串。 具体来说,这段堆栈信息&#xff1a…

一、初始爬虫

1.爬虫的相关概念 1.1 什么是爬虫 网络爬虫(又被称为网页蜘蛛,网络机器人)就是模拟浏览器发送网络请求,接收请求响应,一种按照一定的规则,自动地爬取互联网信息的程序。 原则上,只要是浏览器…

在低功耗MCU上实现人工智能和机器学习

作者:Silicon Labs 人工智能(AI)和机器学习(ML)技术不仅正在快速发展,还逐渐被创新性地应用于低功耗的微控制器(MCU)中,从而实现边缘AI/ML解决方案。这些MCU是许多嵌入式…

QQ登录测试用例报告

QQ登录测试用例思维导图 一、安全性测试用例 1. 加密传输与存储验证 测试场景:输入账号密码并提交登录请求。预期结果:账号密码通过加密传输(如HTTPS)与存储(如哈希加盐),无明文暴露。 2. 二…

细说STM32F407单片机2个ADC使用DMA同步采集各自的1个输入通道的方法

目录 一、示例说明 二、工程配置 1、RCC、DEBUG、CodeGenerator 2、USART6 3、TIM3 (1)Mode (2)参数设置 (3) TRGO (4)ADC1_IN0 1)ADCs_Common_Settings 2&a…