游戏引擎架构-游戏支持的系统

这篇具有很好参考价值的文章主要介绍了游戏引擎架构-游戏支持的系统。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本篇知识点来源于《游戏引擎架构》第五章,此章节主要讨论多数游戏引擎中都会出现的底层支持系统。

系统的启动和终止次序控制

C++静态初始化次序是无法使用的,原因是我们无法预引擎子系统的构造函数调用次序和析构函数调用次序。比如我要启动引擎的A,B,C系统,无法保证这些系统是按照规定次序进行创建的。所以这对含有互相依赖关系的引擎系统都不适合。

虽然我们可以通过全局静态单例构造来实现控制构建次序,但是依然没办法控制析构次序,而且我们无法确定什么时候这个单例会被创建(即显式调用:get())

游戏引擎架构-游戏支持的系统,游戏引擎,游戏,unity,c#,架构

简单有效的方法就是不在构造函数和析构函数里做事,而是定义一个启动和终止函数,再在一个主管理器里去显式调用这些函数即可达到效果。

游戏引擎架构-游戏支持的系统,游戏引擎,游戏,unity,c#,架构

更高端的方式即是让各个管理器登记在一个全局的优先队列里,之后就可以按照恰当的顺序逐一启动所有管理器,在结束之前就可以逐一弹出并调用相应的终止函数,以此来达到自动管理。

内存管理

实际上C++的全局new/delete运算符,或者malloc()/free()来动态分配内存(又称为堆分配)是很低效的,原因一个是必须处理任何大小的分配请求,这需要大量的管理开销,二是分配内存需要从用户模式转换至内核模式,上下文切换可能会耗费非常多的时间。因此我们需要做到:维持最低限度的堆分配,并且永不在紧凑循环中使用堆分配。

当然多数游戏引擎会实现一个或多个定制分配器。

基于堆栈的分配器

分配一大块连续内存,再安排一个指针指向堆栈的顶端,指针以下的内存是已分配的,以上的内存是未分配的,对于分配需求,只是移动指针位置即可。注意,这个模式下必须是以请求内存时的相反次序来释放内存。

游戏引擎架构-游戏支持的系统,游戏引擎,游戏,unity,c#,架构

当然有个高阶分配技巧,即双端堆栈分配器,由两个指针进行管理,一个从内存底端向上分配,一个从内存顶端向下分配。有个使用案例即是底堆栈用来加载和卸载游戏关卡,顶堆栈用来分配临时内存块,这些临时内存块会频繁被分配/释放,此举可保证不会产生内存碎片问题。

游戏引擎架构-游戏支持的系统,游戏引擎,游戏,unity,c#,架构

池分配器

预分配一大块内存,大小刚好是分配元素的大小的倍数。池内每个元素被加到一个存放自由元素的单链中,分配的时候从链表中取出一个来用,释放的时候再返回链表即可。分配和释放都是O(1)。

含对齐功能的分配器

分配内存时,分配比请求多一点的内存,再向上调整其内存地址至适当的对齐,最后传回调整后的地址。大多数实现里,额外分配的字节等于对齐字节。

单帧和双缓冲分配器

单帧分配器即是预留一块内存用作简单堆栈分配管理器,每段重复地做着以下工作:每帧开始时,把堆栈的顶端指针重置到内存块底端地址,用于这一帧的分配需求。指针只在目前的帧里使用,分配器每帧会自动清除所有内存。

双缓冲分配器即是两个单帧分配器循环交替使用,用以在第i+2帧之前仍能处理第i帧的结果,防止数据被重写。

内存碎片

动态堆分配会产生另一个问题,即是会随时间产生内存碎片。分配次序和释放次序不一样、尺寸不一样的情况随着时间愈演愈烈,会发现自由区域被切成无数个相对很小的“洞”,此为内存碎片。会导致就算有足够的自由内存,分配请求也仍然可能会失败。

游戏引擎架构-游戏支持的系统,游戏引擎,游戏,unity,c#,架构

可以使用虚拟内存技术,即把不连续的物理内存块映射至虚拟地址空间,使它看上去是连续的。

当然可以使用上述说的堆栈分配器和池分配器解决问题,前者分配和释放后剩下的内存块总是连续的,而后者因为每片内存都是完全一样大的,所以释放和使用都不会因为缺乏足够大的连续内存块。

游戏引擎架构-游戏支持的系统,游戏引擎,游戏,unity,c#,架构

我们也可以对堆定期进行碎片整理,也就是把“洞”从低地址移向高地址,所有可用堆内存空间沉到底端。但那些原先指向已分配的内存块的指针就会失效,于是引出一个新概念:指针重定位,即碎片整理后指针重新指向正确的位置。可以使用智能指针或者句柄来完成这项工作。

智能指针是一个类,可以编写代码正确处理内存重定位,其中一个方法即是把自身加进全局链表中,移动内存后通知全局链表扫描并找到那些指向相关内存的智能指针去更新他们的指向。

句柄通常实现为索引,这些索引指向表内的元素,元素存储指针。句柄表本身不能被重定位。移动内存块时,扫描整个句柄表并更新指针。

重定位另一个问题就是有些内存不能被重定位,有一个方法是让这些内存置于特别缓冲区中,这缓冲区在可重定位内存的范围之外。另一个方法是这些内存块直接不能被重定位。

碎片整理通常很慢,我们可以把碎片整理成本分摊至多个帧,每帧进行N(很小)次内存块移动。只要分配及释放的次数低于碎片整理的移动次数,那么堆就会经常保持接近完全整理的状态。如果是重定位非常大的内存块,可以把它切分成两个或更多的小块进行重定位。

容器

动态数组

数组大小不能编译时期决定时,常用链表或者动态数组来代替。动态数组的简单使用技巧即是在开始时分配n个元素缓冲区,当已含有n个元素并想再次扩大时,则创建一个更大的缓冲区(可以翻倍当前大小,也可以只加n个元素的大小),将原缓冲区内的元素移动到新缓冲区并释放原缓冲区。

链表

游戏引擎架构-游戏支持的系统,游戏引擎,游戏,unity,c#,架构

链表的每个元素都有指针指向下一个节点,在双向链表中,每个元素还有指针指向上一个节点。分为两种数据结构形式。

外露式表是一种链表,其节点数据结构完全和元素的数据结构分离,每个节点含指针指向元素(类似于编程课上那种最简单形式的,数据结构内部维护一个指针)。

侵入式表是另一种链表,数据结构被嵌进目标元素本身。

游戏引擎架构-游戏支持的系统,游戏引擎,游戏,unity,c#,架构

循环链表里,真正的首个节点的prev指针和真正的最后节点的next指针可指向同一个root节点。有时候还会包括头尾指针这两个属性变量用来存储头部和尾部节点。这样设计可以非常快检测节点是否属于链表(任何一个节点在循环链表里都有prev指针指向和next指针指向)。

在大学里学到的链表概念默认是单向链表,单向链表的劣势是移除某个特定节点时因为没有存储prev节点,所以删除时要遍历整个链表并找到前一个节点才能移除,相当于O(n)操作,而双向链表仅需O(1)。它的最大缺点还在于不能高效的逆向遍历。如果仅是栈或者队列需求,那么可以采用单向链表来节省一些内存。

字典和散列表

字典是由键值对组成的表,通过字典能快速用键找到对应的值。通常实现方式是二叉查找树或者散列,只不过前者所需复杂度是O(logn)而后者是O(1)。

散列表的实现就是所有值存在固定大小的表里,表的每个位置表示1个或多个键。插入键值对时把键转换为整数(不同类型有不同映射整数的方式,比如str可以映射ascii码,浮点数可以按照32位模式转换为32位整数),再把整数除表的大小就能获得表的索引。如果两个或以上的键会占用散列表的同一位置,即索引是一样的,这种情况称之为碰撞,对此有两种解决方式:

开放式散列里,多个相同的键会以链表形式存储,容易实现,但是每次在相同的索引中插入键值对都需要动态分配内存。

闭合式散列里,会进行探查过程,在附近或者通过其他巡查规律来找到下一个键值对位置。比较难实现,而且必须要设定表的键值对数目上限,好处是建立之后不用再动态分配内存。

游戏引擎架构-游戏支持的系统,游戏引擎,游戏,unity,c#,架构文章来源地址https://www.toymoban.com/news/detail-793321.html

到了这里,关于游戏引擎架构-游戏支持的系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【架构】Java实现游戏引擎

    学过编程后,感觉所有的游戏都离不开两个方法,一个是画面更新,一个是指令输入。大概所有的游戏都有这几步流程: 输入指令 根据指令做业务逻辑的判断 根据判断结果更新画面 既然大多数的游戏都离不开这几步,那么为了便利游戏的开发,一些工程师就把这几个方法抽

    2024年02月13日
    浏览(29)
  • 《游戏引擎架构》--学习

    维持最低限度的堆分配,并且永不在紧凑循环中使用堆分配   迭代器 未完待续。。。  

    2024年02月19日
    浏览(28)
  • 《游戏引擎架构》--学习3

    维持最低限度的堆分配,并且永不在紧凑循环中使用堆分配   迭代器

    2024年02月22日
    浏览(29)
  • Games104现代游戏引擎笔记 网络游戏进阶架构

    玩家2的视角看玩家1的移动是起伏一截一截,并且滞后的 interpolation:内插值,在两个旧的但已知的状态计算 extrapolation:外插值,本质是预测 内插值:但网络随着时间不停地给我信息包时,信息包可以不均匀(由于网络波动等因素),客户端可以根据给的时间将中间值插出来

    2024年02月08日
    浏览(31)
  • Games104现代游戏引擎笔记 网络游戏架构基础

    挑战1:网络同步 挑战2:是网络的可靠性,包括应对网络的延迟,丢包和掉线 挑战3: 反作弊和安全系统,因为网络游戏的本质是经济系统 挑战4:多样性(不同设备,不同服务器),在不停服的情况下热更新 挑战5:大量人数时对高并发,高操作的要求 Socket编程,通过接口,确认好相

    2024年02月08日
    浏览(46)
  • 十八、Unity游戏引擎入门

    1、下载     首先需要下载Unity Hub,下载网址:https://unity.com/cn。     然后在其中下载Unity编辑器并安装,可选择最新版本。     接着需要选择适合的开发环境,例如Android Studio或Xcode,以便进行手机游戏开发。在安装完Unity后,需要根据项目需求下载对应的模块和插件,例

    2024年02月16日
    浏览(51)
  • 游戏引擎UE如何革新影视行业?创意云全面支持UE云渲染

     虚幻引擎UE(Unreal Engine)作为一款“殿堂级”的游戏引擎,占据了全球80%的商用游戏引擎市场,但如果仅仅将其当做游戏开发的工具,显然是低估了它的能力。比如迪士尼出品的电视剧《曼达洛人》、电影《狮子王》等等都使用了虚幻的虚拟场景。  可见 游戏行业与影视行

    2024年02月16日
    浏览(20)
  • 使用团结引擎开发Unity 3D射击游戏

           本案例是初级案例,意在引导想使用unity的初级开发者能较快的入门,体验unity开发的方便性和简易性能。       本次我们将使用团结引擎进行开发,帮助想体验团结引擎的入门开发者进行较快的环境熟悉。      本游戏是一个俯视角度的射击游戏。主角始终位于屏幕

    2024年01月19日
    浏览(52)
  • Unity、UE、Cocos游戏开发引擎的区别

    Unity、Unreal Engine(UE)和Cocos引擎是三个常用的游戏开发引擎,它们在功能和特性上有一些区别。以下是它们之间的主要区别: 编程语言:Unity使用C#作为主要的编程语言,开发者可以使用C#脚本进行游戏逻辑编写。Unreal Engine主要使用C++作为编程语言,但也支持蓝图系统,允许

    2024年02月22日
    浏览(47)
  • 30分钟了解所有引擎组件,132个Unity 游戏引擎组件速通!【收藏 == 学会】

    🎬 博客主页:https://xiaoy.blog.csdn.net 🎥 本文由 呆呆敲代码的小Y 原创,首发于 CSDN 🙉 🎄 学习专栏推荐:Unity系统学习专栏 🌲 游戏制作专栏推荐:游戏制作 🌲Unity实战100例专栏推荐:Unity 实战100例 教程 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📆 未来很长

    2024年02月11日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包