《游戏编程模式》学习笔记(九)游戏循环 Sequencing Patterns

news2024/11/17 7:55:23

定义
一个游戏循环会在游玩时不断运行。 每一次循环,它都会无阻塞地处理玩家的输入,更新游戏的状态,渲染游戏。它追踪时间的消耗并控制游戏的速度。游戏循环需要做到始终以固定的速度运行游戏。

一个游戏循环中通常包含处理输入部分,物理,AI等游戏逻辑部分,以及渲染部分。这一章给出了一些实现游戏循环的方法。

1.固定时间步长,没有同步
用while,尽可能快地运行游戏, 能跑多快跑多块。

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

在这里插入图片描述

优点就是一个简单,没了
缺点是,游戏速度直接会受到硬件处理的速度以及单次循环中的复杂度的影响。在你的外星人上,子弹可能会飞的非常快。在你爷爷的大屁股电脑上,子弹会变得非常慢。

2. 固定时间步长,有同步
就是说在之前的基础上,每次循环后等一会。调用sleep()方法,让这个循环在固定时间段运行。

while (true)
{
  double start = getCurrentTime();
  processInput();
  update();
  render();

  sleep(start + MS_PER_FRAME - getCurrentTime());
}

优点,简单,省电,游戏不会运行得太快。
缺点是如果执行方法花了很多时间,游戏仍然会运行的过慢。

3.动态时间步长

用真实的时间做循环,每次循环会计算上一次循环到这一次循环所用的时间间隔,然后在update的时候传入这个时间间隔。这个方法很少见,几乎没有人会用。

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

优点,能适应并且调整,避免游戏运行的过快或者过慢
缺点,这会导致很多东西都不稳定。在物理和网络部分使用动态时间步长会遇见更多的困难。例如有些电脑上一个子弹一秒更新50次位置,另一台电脑上这颗子弹只更新了5次,浮点数的舍入偏差会导致这个子弹不同步。

4.扔掉渲染帧
以固定的时间步长更新游戏,但是在动态时刻渲染。

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();
}

在代码中可以看到,这个循环会计算上一次循环到现在间隔的时间,如果间隔时间过长,就会进入里边的小循环,多次调用update方法以追上现实时间。当最终追上后,才会结束,调用渲染,结束整个大循环。

技巧在于我们将渲染拉出了更新循环。 这释放了一大块CPU时间。 最终结果是游戏以固定时间步长模拟,该时间步长与硬件不相关。 高端硬件玩家会有多次渲染,游戏体验更加平滑,而使用低端硬件的玩家看到的内容会有抖动。

在这里插入图片描述

优点是能适应并调整,避免运行得太快或者太慢。 只要能实时更新,游戏状态就不会落后于真实时间。如果玩家用高端的机器,它会回以更平滑的游戏体验。
缺点是比较复杂,你需要将更新的时间步长调整得尽可能小来适应高端机,同时不至于在低端机上太慢。一种方法是限制小循环的最大次数,来防止低端机上跑得太慢的问题,本质上就是扔掉一些逻辑帧。

有时候会出现这种情况:
在这里插入图片描述

由于渲染是动态的,在每次大循环结束才开始,中间有时候会隔着好多个小循环。所以有时候会出现渲染在两次更新之间的情况,而这个时候,渲染的往往是前一次更新的时候的情况,这会造成困扰,例如玩家看见子弹在左边,下一次渲染的时候应该在中间但还是显示在左边。在下一次渲染的时候就变成了右边,而不是玩家期待的中间。

解决方法就是 给render()方法也传入时间,让其插值预测来达到平滑的目的。
当我们要渲染时,我们将它传入:
render(lag / MS_PER_UPDATE);
假设子弹在屏幕左边20像素的地方,正在以400像素每帧的速度向右移动。 如果在两帧正中渲染,我们会给render()传0.5。 它绘制了半帧之前的图形,在220像素,啊哈,平滑的移动。

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

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

相关文章

01-基础例程1

基础例程1 01-LED /* 深圳市普中科技有限公司(PRECHIN 普中)技术支持:www.prechin.net* 实验名称:LED流水灯实验* 接线说明:LED模块-->ESP32 IO* (D1-D8)-->(15,2,0,4,16,17,5,18)* * 实验现象&#x…

stm32----SPI协议

一、概述 SPI(Serial Peripheral Interface,串行外围设备接口),是Motorola公司提出的一种同步串行接口技术,是一种高速、全双工、同步通信总线,在芯片中只占用四根管脚用来控制及数据传输,节约…

jmeter性能测试入门完整版

1. Jmeter简介 Apache JMeter是一款纯java编写负载功能测试和性能测试开源工具软件。相比Loadrunner而言,JMeter小巧轻便且免费,逐渐成为了主流的性能测试工具,是每个测试人员都必须要掌握的工具之一。 本文为JMeter性能测试完整入门篇&…

IT项目标准实施流程

一、IT项目标准实施流程、参与角色与职责架构图 二、IT项目阶段交付文档明细目录 NO. 阶段 中文名称 英文名称 缩写 是否必须 1 1.分析 1.1 项目业务需求分析文档 Business Requirement analysis Document BRD X 2 2.设计 2.1 硬件&软件配置清单 Bill Of Ma…

Excel:如何实现分组内的升序和降序?

一、POWER 1、构建辅助列D列,在D2单元格输入公式: -POWER(10,COUNTA($A$2:A2)3)C2 2、选中B1:D10,注意不能宣导A列的合并单元格,进行以下操作: 3、删除辅助列即可 二、COUNTA 第一步,D2建立辅助列&#xf…

6.Redis-hash

hash 哈希类型中的映射关系通常称为field-value,⽤于区分 Redis 整体的键值对(key-value),注意这⾥的value是指field对应的值,不是键(key)对应的值,请注意 value 在不同上下⽂的作⽤…

同源策略与解决方法

同源策略与解决方法 1.浏览器的同源策略 1.1 同源策略 同源策略(same origin policy),一种安全策略,用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互。 浏览器默认两个不同的源之间是可以互相访问资源和…

reactantd(12)动态表单的默认值问题

最近遇到一个需求是有一个表单可以输入各种信息,然后还需要有一个编辑功能,点击编辑的时候需要把当前数据填入到表单里面。在网上查了很多种方法,然后我的思路是使用initialValues搭配setState()使用。默认值都为空,然后点击单条数…

Microsoft Edge 主页启动diy以及常用的扩展、收藏夹的网站

一、Microsoft Edge 主页启动diy 二、常用的扩展 1、去广告:uBlock Origin 2、翻译: 页面翻译:右键就有了,已经内置了划词翻译 3、超级复制 三、收藏夹的网站

函数(个人学习笔记黑马学习)

1、函数定义 #include <iostream> using namespace std;int add(int num1, int num2) {int sum num1 num2;return sum; }int main() {system("pause");return 0; } 2、函数的调用 #include <iostream> using namespace std;int add(int num1, int num2…

java内存模型讨论及案例分析

常用内存选项 -Xmx&#xff1a; 最大堆大小 -Xms&#xff1a;最小堆大小 -Xss &#xff1a;线程堆栈大小&#xff0c;默认1M 生产环境最好保持 Xms Xmx java内存研究 内存布局 可见&#xff1a; 堆大小 新生代 老年代&#xff0c;新生代EFrom SurvivorTo Survivor。新…

【数学建模竞赛】各类题型及解题方案

评价类赛题建模流程及总结 建模步骤 建立评价指标->评价体系->同向化处理&#xff08;都越多越好或越少越少&#xff09;->指标无量纲处理 ->权重-> 主客观->合成 主客观评价问题的区别 主客观概念主要是在指标定权时来划分的。主观评价与客观评价的区别…

Vulnhub内网渗透DC-6靶场通关

个人博客 xzajyjs.cn IP DC-6: 192.168.168.4 Kali: 192.168.168.5 信息搜集 arp-scan -l # nmap -sn 192.168.168.0/24进行主机发现&#xff0c;探测到靶机IP。 使用nmap进行端口扫描 nmap -sV -A 192.168.168.4开放了一个ssh和http端口&#xff0c;80端口是wordpress5.1…

MinIO框架安装使用+实现上传需求

MinIO框架 什么是MinIO框架如何安装&#xff08;Docker版&#xff09;安装步骤1. 查询MinIO的服务版本2. 拉取MinIO3.启动报错在docker中没有操作文件的权限 4. 访问 简单配置1.找到创建用户界面2. 设置用户信息3. 创建一个桶 使用MinIO依赖搭建MinIO的初始化API存储桶的基本操…

uniapp 开发小程序,封装一个方法,让图片使用线上地址

1.在main.js文件中&#xff0c;添加以下代码&#xff1a; 复制使用&#xff1a; // 图片使用网络地址 Vue.prototype.localImgSrc function(img){//项目的地址域名&#xff0c;例如百度return "https://baidu.cn/static/index/images/" img; }2.在页面中直接使用&…

PMP是什么?项目管理证书好考吗?

PMP是由项目管理协会&#xff08;Project Management Institute&#xff0c;简称PMI&#xff09;发起的项目管理专业人士资格认证&#xff0c;严格评估项目管理人员知识技能是否具有高品质的资格认证考试。PMP证书究竟难不难考呢&#xff1f;接下来的文章将简要讨论PMP证书的考…

git 基础

1.下载安装Git&#xff08;略&#xff09; 2.打开git bash窗口 3.查看版本号、设置用户名和邮箱 用户名和邮箱可以随意起&#xff0c;与GitHub的账号邮箱没有关系 4.初始化git 在D盘中新建gitspace文件夹&#xff0c;并在该目录下打开git bash窗口 git init 初始化完成后会…

【微服务部署】06-日志集成

文章目录 1. EFK日志三件套集成1.1 核心组件1.2 部署 2. Exceptionless日志系统2.1 Exceptionless核心特性2.2 Exceptionless部署文件2.3 K8s中使用Exceptionless 1. EFK日志三件套集成 1.1 核心组件 Elasticsearch&#xff08;存储&#xff09;Fluentd&#xff08;收集器&am…

文件上传漏洞-upload靶场3-4(全网最详细解读)

文件上传漏洞-upload靶场3-4关通关笔记&#xff08;全网最详细解读&#xff09; upload 第三关&#xff08;特殊后缀&#xff09; 思路 按照第一关和第二关的思路&#xff0c;先随便上传一个文件用burpsuite工具抓包&#xff0c;看它到底是前段验证还是后端验证。 上传一个we…

ADB安装及命令-自用查询

常用ADB命令整理 ADB简介常用命令整理查看设备及安装卸载屏幕事件⽇志查询查询系统服务情况其它 adb 命令 ADB安装ADB连接设备Android 实体机连接准备Android 虚拟机连接准备 ADB简介 ADB&#xff0c;即 安卓调试桥 (Android Debug Bridge, adb)&#xff0c;它是 Android 开发…