Scheduling Game Event

news2024/12/24 8:38:46

在游戏中管理事件:动画更新、对象碰撞等,如果没有清晰的理解事件是如何被组织和执行的,那么这将是一项艰巨的任务。这篇精华将解释调度器如何为你的游戏框架提供组织性和灵活性。

随着电脑游戏的日益复杂,实时事件和模拟几乎在今天的游戏架构中成为标准。所需要的是一种方式来管理和执行每帧多次或在一帧的时间步内多次的事件。调度器可以以非常灵活的方式管理游戏事件,同时也促进了一个模块化的方法以便扩展性。

可以有效利用调度程序的游戏技术包括物理模拟、角色动画、碰撞检测、游戏人工智能和渲染。所有这些技术中的一个关键方面就是时间。许多模拟技术都会变得非常复杂,数百个独立的对象和进程会以不同的时间间隔进行更新。例如,物理仿真会将每个对象的时间 c 分解成小的、离散的时间间隔,以便更新对象的运动[Bourg01]。通过提供更精细的时间分辨率,模拟的精确度将大大提高。在这种情况下,许多对象和时间间隔都由相同的调度代码管理,因此在预先防止调度瓶颈时,效率是一个至关重要的问题。

调度器的另一个重要方面是其能够即时添加和移除对象的能力。这允许新的实体进入游戏并参与模拟,与游戏的其他实体一起,不错过任何节奏,然后在不再需要时将它们从调度中移除。

Scheduler Concepts

调度程序的基本组件包括任务管理器、事件管理器和时钟(见图 1.1.1)。通过这些组件,调度程序可以生成基于时间或框架的事件并执行事件处理程序。在整个 gem 中,我们将把事件处理程序称为任务。

Task Manager

每个task 都有一个标准化接口,其中包含一个供任务管理器执行的回调函数。任务管理器维护一个任务列表,以及有关缓存的调度信息,如开始时间、执行频率、持续时间、优先级和其他信息。

Event Manager

事件管理器是调度程序的核心。例如,在图 1.1.2 中,任务 1 在时间 10 和 15 定义了事件。事件管理器根据需要生成事件,以触发任务的执行。

Real Time Versus Virtual Time 实时与虚拟时间

实时调度程序的概念相当简单--事件管理器坐在一个循环中,观察实时时钟,一旦达到目标时间,就触发一个事件。在实时系统中,延迟至关重要。如果一个任务运行时间过长,可能会影响下一个任务的启动。由于每个任务都是在预定时间内完成的,因此从调度程序的角度来看,任务之间的时间基本上是浪费掉了。

从任务的角度来看,时间只是一个数字。根据这个比较数字,可以对时间进行比较,并计算出经过的时间。调度员可以通过操作这个数字来模拟给定的时间或时间的流逝,而不受实时时间的影响--小时可以在眨眼间流逝,时间也可以停止。这就是虚拟时间的基础。

虚拟时间非常有用,因为它允许调度程序在最方便的时候执行任务,而不是在实时性要求的时候。它允许快速向前运行、停止、记录和重放一系列事件。虚拟时间调度器将时间划分为帧。虚拟时间调度器将时间划分为若干帧,任务在帧与帧之间分批执行,在 "虚拟时间 "中运行,然后在渲染每一帧时与实时时间同步。如果帧频足够高,就会产生实时的错觉。然而,帧与帧之间几十毫秒的时间对计算机来说是非常宝贵的,尤其是在有效管理的情况下。通过将所有任务集中到一个区块中,剩余的时间就可以用来做其他事情(参见可扩展性)。


在本 gem 中,我们将虚拟时间称为模拟时间,因为模拟中的所有对象都将其作为参考。如果模拟时间停止,那么仿真也会暂停。当模拟时间恢复时,模拟中的对象不会检测到任何中断。模拟时间从模拟开始时的零点开始。

例如,假设每帧的长度为 20 毫秒(见图 1.1.3),如果有事件发生在 51 毫秒和 54 毫秒处,那么它们将在第 2 帧期间被处理。事件管理器在第 2 帧结束前不知道第 2 帧有多长;因此在第 3 帧开始时,它查看实时时间,发现时间为 60 毫秒。任务 1 是第一个任务,时间为 51 毫秒;但模拟时钟仍处于帧 2 的起始位置,时钟前进到 51 毫秒后,任务 1 开始执行。如果使用的是离屏缓冲区,则该帧可能已经渲染完毕,此时只是将图像复制到显示屏上)。任何未使用的时间都可用于额外的处理(请参阅可扩展性了解如何使用这些额外的处理周期)。

在这种模式下,任务执行和帧渲染总是略微落后于实时速度。但这并不会被观看者察觉,而且我们还可以利用可变帧频进行工作。如果帧频变慢,调度程序可以进行补偿,使模拟看起来以恒定的帧频运行。如果帧频固定不变,调度程序就可以预测开始和结束时间,并提前执行事件处理。但是,如果机器严重超载,调度程序就无法补偿,游戏运行速度就会变慢。

Event Type

(Frame Event)帧事件是最简单的事件类型,每N帧发生一次,或者每帧发生一次(N=1)。它们也可以在渲染事件之前或之后发生。另一方面,时间事件发生在模拟时间中,并不特定于与帧同步。例如,一个时间事件可以每10毫秒发生一次,不管渲染帧率如何。也可以将时间事件和帧事件结合起来。例如,一个事件可以被安排在每个帧开始后的10毫秒发生,或者它可以在每个帧中执行五次,这在模拟时间中是均匀分布的。

Clock

调度器的时钟组件跟踪实时时间、当前模拟时间和帧计数。时钟的精确度将决定模拟的准确性——1纳秒分辨率的时钟将比1毫秒分辨率的时钟更加精确。对于大多数目的而言,1毫秒分辨率已经足够。如果需要更高的分辨率,可以使用1毫秒的硬件时钟,并根据需要细分实时滴答声以提高分辨率。也可以使用浮点数时钟,尽管需要小心处理舍入误差。

Sequencing 序列

事件管理器处理事件的序列和生成。由于任务是由事件触发的,因此自然而然地会发生正确的排序。例如,我们定义两个任务:

  • 任务1:从5毫秒到15毫秒,每5毫秒运行一次,优先级为普通。
  • 任务2:从11毫秒到19毫秒,每4毫秒运行一次,优先级为高(见表1.1.1)。

在某些情况下,任务可能被设置为同时执行。在这个例子中,任务1和任务2都在时间点15执行。由于任务2的优先级高于任务1,因此它首先执行。如果优先级相同,或者没有实现优先级系统,那么它们将按照轮询(round-robin)方式处理。优先级对于排序基于帧的任务也很有用。

Task Manager Details

面对数以百计的潜在任务,任务管理器必须进行智能化管理。虽然可以有多种方法,但光盘上的示例程序使用了有序列表。任务按照其下一个执行时间存储在列表中,列表的首部总是下一个要执行的任务。事件管理器只需查看第一个任务,就能确定下一个事件的发生时间。当事件发生时,最前面的任务会从列表中 "弹出 "并执行,它的下一次执行时间会被更新,并根据更新后的执行时间重新插入列表。


除了避免冗长的搜索外,这种方法还有一个优点,那就是经常执行的任务会保持在列表前列(几乎就像缓存一样),而不经常执行的任务则会在适当的时候自动 "弹出"。

通常情况下,必须对已注册的任务进行即时修改,这可能涉及调整其优先级、周期、持续时间,甚至在任务完成前将其删除。为了更新任务,必须有某种外部手段来定位它。可以分配一个唯一的注册 ID,以便在列表中定位任务。

A Simple Scheduler

在讨论了调度程序的各种概念和组件之后,我们将演示如何构建和使用一个简单的调度程序。所提供的示例代码可以在光盘中找到。

Design

调度程序的设计取决于两个组件--调度程序引擎本身和 ITask 插件界面(见图 1.1.4)。

为了让调度程序运行,需要有人调用它。在非图形用户界面的 prograrm 中,这就像编写一个循环并执行

while(app.IsRun())
    scheduler.ExecuteFrame();

将调度程序集成到消息泵图形用户界面(如 Windows)中有两种方法。第一种是通过修改消息循环来处理消息并执行调度程序。这是最明显的方法,但在调整窗口大小时会出现调度程序 "冻结 "的问题。

第二种方法是创建一个 Windows 定时器,并用它来调用调度程序。由于定时器不会被窗口拖动中断,因此调度程序可以在后台持续运行。光盘中提供了一个示例应用程序(Win),展示了如何在 Windows 应用程序中使用调度程序。让我们来仔细研究一下这个应用程序。

Windows 核心代码非常简单。调度程序通过 WM_TIMER 消息运行,有两种类型的计划事件:一种是每 15 毫秒更新一次每个小球的位置,而渲染事件则是将所有小球写入屏幕外的缓冲区。其中一个事件每 15 毫秒更新一次每个小球的位置,而渲染事件则将所有小球写入屏幕外的缓冲区,然后 Win-dows 可以根据需要从屏幕外的缓冲区绘制屏幕。本示例演示了如何使用多个模拟任务,以及如何快速添加/删除任务。


通常情况下,游戏的帧速率会随系统容量和负载的变化而变化,但移动物体的速度却保持不变。虽然两个示例应用程序的帧频都是固定的,但所提供的调度程序确实支持这种恒速技术。关键在于 ciock .Update( ) 方法,该方法会对实际实时时间进行采样,并根据所用时间推进模拟。如果一个物体在 60 毫秒内移动了 N 个单位,那么系统是渲染两个 30 毫秒帧还是三个 20 毫秒帧并不重要--物体在相同的实时时间内移动了相同的距离,因此速度是恒定的。如果想让模拟对象的速度随帧速率增大或减小,请更改 clock.Update( ) 方法,使其按固定间隔前进,而不是读取实时时钟。

那么,调度程序到底是如何管理时间的呢?我们需要注册一些事件,看看它是如何工作的。

Scheduling

调度任务的第一步是将其指定为时间事件、帧事件或 渲染事件。这段代码将调度一个帧事件,从第 200 帧开始,每隔三帧运行一次,并在第 210 帧之前结束(开始时间 200 + 持续时间 10):

scheduler.Schdule(TASK_FRAME, 200, 3, 10,
pSomeHandler, pUserPointer, &id);

该任务将在帧 200、203、206 和 209 上运行。执行最终迭代后,该任务将过期并被任务管理器删除。持续时间为 o 的任务是永久任务,永远不会过期。在某些情况下,你可能想在任务完成前将其删除,或者想手动结束一个永久任务。为此,可以根据 任务ID终止他 。Terminate(taskID)

每次调用调度程序 ExecuteFrame () 方法时,首先会调用 c1ock.BeginFrame ( ) ,通过更新帧计数和计算新的帧开始和结束时间来启动新的帧。 更新帧计数后,执行所有时间事件,将模拟时间提前到帧结束时间,执行所有帧事件,最后执行渲染任务(在示例调度程序中,渲染任务是一个特殊的帧任务,没有起始时间、周期或持续时间--它总是每帧执行一次)。
可以使用 Run( ) 和 stop() 方法停止或重新启动整个模拟。当调度程序停止并重新启动时,它会计算已过时间并从总模拟时间中减去。停止时,调度程序仍会执行渲染和帧事件,但时间事件会暂停。
 

可以使用 Run( )和 stop( )方法停止或重新启动整个模拟。当调度程序停止并重新启动时,它会计算已过时间并从总模拟时间中减去。停止时,调度程序仍会执行渲染和帧事件,但时间事件会暂停。
 

Advanced Concepts

有许多方法可以改进或更好地利用调度程序:可扩展性、模拟和多线程就是其中的几种方法。

游戏应该充分利用所有可用的处理能力,以提供更丰富的体验,但它仍然需要在性能较弱的系统上运行良好。计算成本高的功能需要被节流或完全关闭。游戏还应该在多任务环境中 "运行良好"--占用大部分 CPU 的游戏可能会妨碍操作系统及时响应用户输入。此外,如果操作系统在后台启动任何内务管理任务,也会减慢游戏的运行速度。

收集性能数据是成功的一半。由于调度程序会处理所有进程,从而成为瓶颈,因此它是放置性能监控器的理想场所。
 

如前所述,时钟会获取当前时间的快照,并将其与上一帧进行比较,以确定已用时间。调度程序还可以通过比较开始时间和结束时间来确定每个任务的已用时间。这一信息既可传达给任务,也可用于决定是否运行任务和/或运行的频率。

提供可扩展性的一种方法是要求时间预算--功率越大,允许的时间越多。调度程序会跟踪累计预算和累计运行时间,只有在当前预算超过实际时间时才会执行任务。例如,一个任务每帧的时间预算可能是 2 毫秒,但在慢速 CPU 上的运行时间是 3 毫秒。调度程序会每隔三帧跳转一次,以便将任务控制在预算范围内(见表 1.1.2)。
 

一些任务可能有时间预算 "阈值"--如果超过预算,它们就不会运行,而是部分时间不运行。调度程序还可以通过汇总所有任务来确定执行整个模拟所需的时间。调度程序可以添加任务来填补空闲时间,或移除任务来减少负载(当然,必须有一些规定来指定哪些任务可以安全地添加或移除)。通过向任务提供整体系统使用统计信息,任务可以根据接收到的数据自行调整使用时间的长短。最好将空闲目标设定为 5%-10%,以便在实际处理时间上出现微小波动时也不会减慢速度。

提供可扩展性的其他选项包括增加或减少时间预算、安排空闲任务(只在空闲时间运行)、垃圾收集或其他家务劳动、图形增强或人工智能改进。在进行此类管理时,重要的是要避免在两个极端之间摇摆不定,具体方法是将调整限制为小幅增量变化,而不是大幅跳跃,或者对之前调整的效果进行统计分析,以提高预测能力。
 

Simulation

调度程序可用于驱动仿真系统。本 gem 中描述的调度程序非常适合这类仿真系统。

在月球着陆器的一个简单例子中,着陆器有垂直速度和前进速度。每个时间步都会增加重力。如果我们使用人工智能来控制着陆器的垂直推进器,那么在每个时间步中,人工智能都会对速度进行采样并调整推力以进行补偿,从而实现可控的下降。时间步必须足够小,以便让人工智能有足够的时间做出反应,否则着陆器会在做出有效反应之前撞上地面。对于碰撞检测,同样需要较小的时间步长,以便着陆器与地面相交,而不是完全穿过地面。

Multithreading

调度程序可以管理子线程的执行[Carter01, Daw-son01]。例如,某些任务作为一个连续的进程,而不是一系列离散的事件,可能效果更好[Otaegui01]。这样的任务可以写成一个线程,调度程序可以控制允许线程处理多少时间。

多处理器系统正慢慢变得越来越普遍,在不久的将来,多处理器很可能会成为一种标准功能。能够利用多处理器的游戏将能够超越为单个 CPU 编写的游戏。

多 CPU 调度器可以同时激活多个线程,使它们可以同时运行。它还可以在特定线程中生成事件处理程序,以便同时处理多个事件。

Conclusion

使用调度程序有多种原因--便携性、灵活性和支持模拟。高质量的调度程序必须灵活高效。本手册介绍了调度程序的一些基本概念,提供了一个调度程序示例,并展示了如何将其集成到传统应用程序和基于图形用户界面的应用程序中。在您的下一款游戏中使用调度程序,让您的活动更有条理。

References

[Bourg01] Bourg, David M.,Poysics for Game Developers, O'Reilly, 2001. 

[Cartero1] Carter,Simon, "Managing Al with Micro-Threads,”Game Programming

[Dawson01] Dawson,Bruce“Micro-Threads for Game Object AI,”Game Programming Gems 2,Charles River Media,Inc.,2001.

[Llopis0i] Llopis,Noel,"Progranming with Abstract Interfaces,”Game Programming Gems 2,Charles River Media, Inc., 2001.

[Mirtichoo]Mirtich, Brian."Timewarp Rigid Body Simulation,”Computer Graphics Proceedings, SIGGRAPH 2000: pp.193-200.

[Oraeguio1] Otaegui,Javier,“Linear frogramming Model for Windows-Based Games,”Game Programming Gems 2,Charles River Media, Inc.,2001.
 

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

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

相关文章

接口测试之XML响应断言

目录 XPath 基本语法XML 响应结果解析XML 响应结果断言 XML 响应数据 如何提取 AddResult 中的值&#xff1f; <soap:Body><AddResponse xmlns"http://tempuri.org/"><AddResult>4</AddResult></AddResponse> </soap:Body> …

VB6 MQTT为什么在物联网应用中使用 MQTT 而不是 HTTP?

有需要VBA,VB6,VB.NET等方面的MQTT的可以找我 一、MQTT简介 MQTT被广泛用于物联网(IoT:Internet of Things)领域&#xff0c;其中大量的设备需要进行实时通信和数据交换。它采用了一种发布/订阅(publish/subscribe)模型&#xff0c;其中消息的发送者&#xff08;发布者&#…

CobaltStrike基本渗透

目录 CobaltStrike简介 主要功能&#xff1a; 使用注意&#xff1a; 在使用CobaltStrike进行渗透测试时&#xff0c;务必遵守法律法规&#xff0c;并获得合法授权。 CobaltStrike安装 前提 安装 服务端安装 windows安装 CS基本使用 监听器配置 一些基本的攻击…

C++/C 线性插值

插值 插值&#xff0c;是根据已知的数据序列&#xff08;可以理解为你坐标中一系列离散的点&#xff09;&#xff0c;找到其中的规律&#xff0c;然后根据找到的这个规律&#xff0c;来对其中尚未有数据记录的点 应用 对缺失的数据进行补偿对图像进行放大缩小 通用公式 如上…

小白跟做江科大32单片机之按键控制LED

原理部分 1.LED部分使用的是这样的连接方式 2.传感器模块的电路图 滤波电容如果接地&#xff0c;一般用于滤波&#xff0c;在分析电路时就不用考虑。下面这个电路就是看A端和B端哪端的拉力大&#xff0c;就能把电压值对应到相应的电压值 比较器部分 如果A端电压>B端电压&am…

【MySQL】表的连接和复合查询

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;MySQL 目录 &#x1f449;&#x1f3fb;连接JOIN&#x1f449;&#x1f3fb;子查询&#x1f449;&#x1f3fb;合并查询 &#x1f449;&#x1f3fb;连接JOI…

【算法】位运算算法——消失的两个数字(困难)

题解&#xff1a;消失的两个数字(位运算算法) 目录 1.题目2.题解3.示例代码如下4.总结 1.题目 题目链接&#xff1a;LINK 2.题解 本题要求时间复杂度O(N),空间复杂度O(1),分别否了我们 排序遍历 和 哈希数组 的想法。想要在规定时间/空间复杂度内完成本题&#xff0c;需要借…

辅导男朋友转算法岗第1天|tokenizer

文章目录 LLM训练流程LLM中的tokenizersBPEWordPieceUnigramSentencePiece&#xff08;使用BBPE或Unigram&#xff09; LLM训练流程 【大语言模型LLM基础之Tokenizer完全介绍-哔哩哔哩】 https://b23.tv/2kdTKxf LLM中的tokenizers 三种不同分词粒度的Tokenizers word-based…

python 获取网页乱码怎么解决

在使用python爬取网页时&#xff0c;经常会遇到乱码问题&#xff0c;一旦遇到乱码问题&#xff0c;就很难得到有用的信息。本人遇到乱码问题&#xff0c;一般有以下几个方式&#xff1a; 1、查看网页源码中的head标签&#xff0c;找到编码方式&#xff0c;例如&#xff1a; 可…

【UML用户指南】-02-UML基本元素的介绍(二)

1、语法和语义规则 命名——为事物、关系和图起的名字&#xff1b; 范围——使名字具有特定含义的语境&#xff1b; 可见性——这些名字如何让其他成分看见和使用&#xff1b; 完整性——事物如何正确、一致地相互联系&#xff1b; 执行——运行或模拟一个动态模型意味着什…

安卓 Flutter Channel 源码解析

Flutter 官方提供三种 Platform 与 Dart 端消息通信方式&#xff0c;他们分别是 MethodChannel 、 BasicMessageChannel 、 EventChannel MethodChanel &#xff1a;用于传递方法调用&#xff0c; MethodCallHandler 最终必须在 UI 线程通过 result. success(x) 方法返回…

【深度学习】YOLOv10实战:20行代码将笔记本摄像头改装成目标检测监控

目录 一、引言 二、YOLOv10视觉目标检测—原理概述 2.1 什么是YOLO 2.2 YOLO的网络结构 三、YOLOv10视觉目标检测—训练推理 3.1 YOLOv10安装 3.1.1 克隆项目 3.1.2 创建conda环境 3.1.3 下载并编译依赖 3.2 YOLOv10模型推理 3.2.1 模型下载 3.2.2 WebUI推理 …

成功解决“ImportError: cannot import name ‘mapping‘ from ‘collections‘”错误的全面指南

成功解决“ImportError: cannot import name ‘mapping’ from ‘collections’”错误的全面指南 成功解决“ImportError: cannot import name ‘mapping’ from ‘collections’”错误的全面指南 一、引言 在Python编程中&#xff0c;当我们尝试从某个模块中导入某个名称时&…

上弦外媒新闻发稿:2024年度国外主流新闻媒体和海外媒体软文分发平台有哪些?

2024年度主流海外媒体新闻发稿和海外媒体软文分发平台有很多&#xff0c;下面是一些常见的和广受认可的平台&#xff1a; 主流新闻媒体 CNN - 美国知名新闻网络&#xff0c;覆盖广泛的国际新闻。BBC - 英国广播公司&#xff0c;提供全球新闻和深入报道。纽约时报 - 美国主流报…

UnityAPI学习之 事件函数(生命周期函数)的整体调用流程及细节

事件函数(生命周期函数)的整体调用流程 Reset() 这个函数会在用户首次添加该组件时或单击 Reset 按钮时被调用&#xff0c;且只在编辑器生效,可用于保存默认值 示例&#xff1a; using System.Collections; using System.Collections.Generic; using UnityEngine;public cla…

Docker中布置Jenkins实现Android项目的自动化构建

因项目需要&#xff0c;要在服务器上使用Jenkins完成Android项目的自动化构建&#xff0c;但服务器上登录的账户没有管理员权限&#xff0c;无法用sudo命令&#xff0c;因此需要把相应环境布置在docker中。 环境搭建 docker容器相关命令 创建容器 docker create -it contai…

Android Handler机制使用及全面解析

前言 我是真的不想写这篇总结&#xff0c;说实话&#xff0c;关于Handler&#xff0c;全面且优秀的文章多的很。 但是这东西吧&#xff0c;还是想以自己的方式再去细看一下它的原理&#xff0c;实现源码&#xff0c;它的各种机制&#xff0c;在App中使用到的地方。 这样或许…

【深度揭秘GPT-4o】:全面解析新一代AI技术的突破与优势

目录 ​编辑 1.版本对比&#xff1a;从GPT-3到GPT-4&#xff0c;再到GPT-4o的飞跃 1.1 模型规模的扩展 1.2 训练数据的更新 1.3 算法优化与效率提升 1.4 案例分析 2.技术能力&#xff1a;GPT-4o的核心优势 2.1 卓越的自然语言理解 2.1.1 上下文理解能力 2.1.2 语义分…

地质灾害位移应急监测站

地质灾害位移应急监测站是一种专门用于地质灾害预警和应急响应的设施&#xff0c;它能够实时监测和分析山体、建筑物、管道等的位移变化情况。以下是关于地质灾害位移应急监测站的详细介绍&#xff1a; 主要组成部分 传感器&#xff1a;安装于需要监测的位置&#xff0c;用于…

chap4 simple neural network

全连接神经网络 问题描述 利用numpy和pytorch搭建全连接神经网络。使用numpy实现此练习需要自己手动求导&#xff0c;而pytorch具有自动求导机制。 我们首先先手动算一下反向传播的过程&#xff0c;使用的模型和初始化权重、偏差和训练用的输入和输出值如下&#xff1a; 我…