Skip to content

Latest commit

 

History

History
327 lines (304 loc) · 29.7 KB

2017-07-30-GameProgrammingGems3.markdown

File metadata and controls

327 lines (304 loc) · 29.7 KB
layout title subtitle date author header-img
post
游戏编程精粹 第四卷阅读笔记
做新游戏
2017-07-29 15:00:00 -0700
tachen
img/post-GameProgrammingGems3-bg-00.jpg

第四卷:共享时代


业界的现状

> 当本书付印之时,我们正期盼着有关下一代游戏主机的信息。我们不由得猜疑,需要学哪些技术才能有效地在下一代主机上进行开发呢?然而,它们将带来的 > 新的功能仍然是个迷。 > > 近在眼前的是便携式游戏设备掀起的高潮。任天堂公司的GameBoy®已经以其各种型号独领风骚十多年了,但其他的公司正纷纷携各自有竞争力的产品进入这个市场。 > 从Nokia的N-Gage™到Tapwave的Zodiac™到索尼的PSP,也许微软心中也自由妙计,手持游戏市场已到了爆发的时候了。 > > 时机选得正好,家用游戏机上的游戏软件开发费用昂贵而且风险也很大,因此有另一种开发成本较低的平台无疑是件好事。如果你也是一名“蜗居”在车库中的游戏开发者, > 这对你一定是天大的好消息。今时今日,除了那些大发行商之外,又有谁能负担得起开发一个高质量游戏所需的至少1500万美元呢。 > > 开发游戏的成本逐年上升,这在业界造成了不少麻烦问题,逐渐多见的炒冷饭问题只是其中之一。你又怎能埋怨游戏发行商不愿意承担风险呢?如果你有1500万美元钱用于投资, > 难道你不会倾向于较安全可靠的途径吗?今日的市场上,有着许多的续集、已有的游戏的克隆版以及各种各样的官方特许产品。这都是可以理解的,但并不令人满意。如果你是一名游戏 > 玩家,重复玩雷同的游戏多半无法使你兴奋起来。 > > 出路在何方?怎样才能把我们这些开发者从枷锁中释放出来,使我们有更大余地创新?我无法给你现成的答案,但我有个有益的建议。 > > 贡献 > > 常有人问我这样的问题,是什么原因让那些作者坚持为“游戏编程精粹”系列撰稿呢?难道他们不正是在将自己宝贵的技术成果泄露给竞争对手么?这样问我,一定是从未在其 > 他行业中见到类似的情况——可口可乐公司就绝对不会把它的绝密配方和百事可乐公司共享!那么,面对那些开发与你的游戏竞争的开发者和发行商,为什么你会将你的算法与之 > 共享呢? > > 从这个角度看问题吧。如果你每次开发游戏都把代码从头写过,那就意味着每次都要重写保存游戏的函数库,对不对?可是你愿意每次都推到重来吗?你一定会找个方法来节约时间, > 也免得让那些重复劳动逼得你发疯。那么在写完这个函数库之后,让你的朋友也使用它吧。也许你会问,我干嘛要把自己辛苦好久才写出来的东西给别人用呢?答案是,你的朋友和你所处 > 的情况一模一样。他已经重写了好多遍消除内存碎片的功能模块,这些重复劳动让他也一样很郁闷。如果你俩能共享各自的函数库,你们就能事半功倍。这不是一件值得做的事情吗? > > 在较高层次来看,譬如说你为一家发行商工作,目前正在配合两家开发工作室工作。这两家工作室都正在从零开始编写全部代码。他们将各自编写功能完全相同的两套底层函数库。 > 难道你不会倾向于将两者的开发工作在某种程度上予以合并,从而减少成本吗?一个游戏的基本模块并不会对游戏有太大的影响,何必要为两家工作室各自开发同样的东西而付双份钱呢? > 又譬如你为其中一家游戏工作室工作,合并部分模块工作的做法,将节约你的时间,使你能够更专注与朝游戏中增添feature,而正是feature将使你的游戏鹤立鸡群。而且,既然 > 发行商因其对工作室提供的服务而将抽取游戏销售收入中的大部分,那么若能在履行合同之余顺便获得一些有用的代码,不是很划算吗? > > 让我们在更高的层次看这个问题。我们是一个大行业,其中有着上千个游戏开发工作室。上千个工作室正在重复地开发着相同功能的函数库,这又是何苦呢?这正是诸如STL那样的库 > 存在的理由:节约每个人的时间,也就等于节约每个工作室的开发成本。何不让这些工作室在某种抽象的层次进行协作,使其各自能将更多时间用来开发自己的游戏中独特的部分? > 今时今日,似乎无人有时间来创作革新的游戏,每个人都把如此多的时间耗在底层代码的重写上了(也变得与时俱进地复杂)以至于无法在日程中塞进更多创新的工作。 > > 充分共享 > > 于是你会说:好啊,那真是非常好。我只要等别人写完代码并“泄”(share)出来,随便拿来用就好。这样子一来,我既不用泄出一行自己的代码,又可以从中获益匪浅。对不起, > 这不符合游戏规则。若每个人都这么想,那就不会有会议、书、杂志等等的存在,也不存在任何性质的信息共享了。为了共享体系能够正常运行,每个人都应当出一份力。 > > 你可以拿这个体系和税务体系想比拟。若没有人缴税,政府就会失去经济来源。道路龟裂不会有人来修,桥梁也会年久失修甚至断裂,冬天街上的积雪也不会有人从中开辟出通路。 > 或许,你也能够自己来打理这一切,维护自己住的地方的附近区域。但是,更有效率的做法是缴一些税金,然后由各方面的专家为所有人解决一切。在软件开发上也是类似的。当你贡献 > 出部分自己特别擅长的资源后,你就能从其他业界专家贡献出的资源中受益。 > 在一个税务制度完善的社会里,每一个要求权利但不愿同时履行缴税义务的人,在一定程度上侵犯了这个社会的利益。因为有这些拖欠税款的人的存在,其他人就需要缴更多的税。 > 在技术领域也是类似的。这些不向群里做贡献的人,是拒绝分享自己的聪明才智。而同时,他人就不得不耗费较多时间,无谓地重写他们本来已经写好的完美的记忆卡函数库。在这种 > 情况下,他们又有什么权利来抱怨业界缺乏创新精神呢?是你使得好多人不得不重头编写那可怜的记忆卡函数库!他们又怎会有时间来创新! > > 所以,简单说来这就是共享体系的根基,也是为何这对我们开发者团体来说是如此重要。在他人的成果中获益的同时,每个向团体做出贡献的人也能得到各种形式的正面反馈,也许 > 团体中的其他人进一步改进了相关代码,也许你获得了声望,甚至可能是一份酬金。 > > 诚然,你也可能有一些不能与他人共享的商业机密,这是可以理解的。若你刚开发了一个效果美轮美奂的pixel shader,那么等到你使用该shader的游戏发售之后再共享该shader也是 > 可以理解的。事实上,在你的游戏发售以后,对于任何细心分析你的游戏的人来说,其中的技术就不再是秘密了。因此,何不公开共享呢?日积月累,这样做的人们积累了较多的信息, > 也提高了复杂度。这推动了许多像本书——《游戏编程精粹4》一样的书的出现。精粹丛书之所以存在于今日,与全世界范围内巨大数量的支持者是分不开的。至今已有200人曾为游戏编程精粹 > 系列撰稿,他们来自美国、加拿大、英国、发过、德国、瑞士、澳大利亚、巴西等地。显然,许多人都认同这一共享体系。 > > 请认真考虑一下,你也能为游戏开发团体做出一份贡献。无论是向游戏编程精粹系列投稿、向杂志投稿、写书、在自己的网站上发表文章或披露部分你上一款游戏中的代码都行。 > 比起什么都不做,只有给予能给你带来更多的获取。阅读他人的想法正是我们学习计算机科学的方式,也是未来的游戏开发者学习实用有效地技术、从而避免重复开发的方式。这终将 > 释放我们大家的创新力,带来前所未有的愉快体验。作为游戏开发者,也作为游戏玩家的一份子,这难道不正是我们真心希望的吗? > > 生生不息 > > 有许多的几年前开始从事游戏开发的同行任然记得那激发自己从事游戏开发的冲动的时刻。对我个人而言,一切都是从我六年级时懂得可以用一种叫“几何学”的神奇“玩意” > 在计算机屏幕上画圆开始的。从那时起,我们自学了许多书,那些书现在早已翻旧了,其中有高德纳先生(Donald E.Knuth)的The Are of Computer Programming、Sedgwick的Algorithms、 > Graphics Gems系列,也许还有James D.Foley和Andries van Dam合著的Computer Graphics一书中圆的Bresenham算法。就在数年之前,我曾在一次面试中被要求推导出该算法,这令 > 我甜蜜地回想起六年级时再Atari 800计算机上绘制圆的情景。 > > 如果你是一名专业游戏工作者,我希望此书能够唤醒你的求知欲。如果你刚刚起步,我希望你能够在本书中找到能够让你穷尽一生去追求和发现的美好事物。 >

创新基于共享

时钟:游戏的脉搏尽在掌握

> 在游戏里,一切都是由时钟(clock)来驱动的。时钟使时间向前,而正是这流逝的时间让游戏世界中的万物运动起来,使镜头跟随着玩家,甚至在游戏结束使开发者名单 > 不断向上卷。不幸的是,“每当游戏需要时就直接查询某些系统定时器来取得当前时间”这样天真的做法伴有很多问题。下面是几个问题的例子。 > > • 在一帧内的不同地方查询时间会返回不同的值(导致屏幕上的对象在更新时产生奇怪的扭曲失真)。 > > • 暂停游戏,但是允许游戏的一些部件继续允许会有问题的。例如,当游戏暂停时,用户界面动画和旋转中的镜头仍然处于动态。 > > • 帧速率的变化会导致动画以及镜头运动有容易察觉的抖动。 > > 关于时间的基础 > > 在很久以前,那是游戏开发的黑暗(无知)年代,大多数程序员根本不使用时钟。他们将尽可能多的东西放在一帧内执行(通常帧的长度由CPU能够执行多少计算来决定, > 或由相邻的两个显示器垂直同步信号(vertical sync signal)之间的时间决定)。这样做的效果不错——只要游戏总是在同等配置的电脑上运行就没问题。但如果有人试图在 > 较快的CPU上运行此游戏,整个游戏都会变快。而且不单是游戏的显示帧速率加快而已,实际上一切物体在屏幕上的运动都加快了,以至于游戏变得没法让人玩下去。 > > 在今日,过去的早已烟消云散。大多数现代的游戏都利用某种形式的时钟来驱动游戏,并使游戏运行的速度独立于运行游戏的系统的速度。即使是运行平台硬件配置相对 > 固定的电视游戏机游戏,也能从使用时钟系统中获益,例如根据PAL(Phase Alternating Line)或HTSC(National Television System Committee)视频制式以不同的频率来 > 刷新游戏。 > > 大部分游戏都运用主游戏循环(main game loop)的机制。只要游戏还在运行,这循环就会反复执行,每帧一次。一帧内的所有处理都必须在循环体内进行。下面列出一些一般在 > 帧内处理的主要事件。 > > • 处理用户的任意输入。 > > • 运行人工智能(AI)。 > > • 接受网络分组数据包(Packet)。 > > • 更新游戏世界中的所有对象。 > > • 渲染所有当前可见的对象。 > > 时钟系统的组成 > > 我们要开发一个具备如下功能的时钟系统。 > > • 可靠地获取当前时间、一帧长度。 > > • 使游戏时间值得暂停与缩放独立于程序的其他部分。 > > • 时间归零,或用任意值重设时钟。 > > • 支持可变帧长度,也支持固定帧长度。 > > • 避免因连续几帧的长度彼此差别过大而产生失真(artifact)。 > > • 避免精度问题。

想起很早前传奇加速外挂

内存操作

> 频繁地进行内存分配与删除可能会造成过多的内存碎片。而且可能导致下面这种情况:有足够的空间内存可以满足应用程序的申请,但是没有足够大的连续内存块可以满足申请。 > 在通常所用的PC上遇到这种情况时,我们的每秒帧数立刻会跌入低谷,此时操作系统正试图通过虚拟内存来满足要求。在家用游戏机上问题就更大,由于没有救命的交换文件, > 内存碎片几乎总能使游戏崩溃。 > > 频繁地分配和删除操作带来的而另一个副作用就是低的访问局部性。访问局部性指的是应用程序对领近的内存位置进行引用操作的方式。一个频繁地引用随机分散在堆中的内存位置 > 的应用程序,具有较差的应用局部性。此类行为会导致缓存错失(cache miss)这个在任何系统中都会使性能降低的罪魁祸首,在数据缓存和指令缓存较小的视频游戏机上此症状尤 > 甚。一个连续引用领近的内存位置的应用程序,具有较好的应用局部性。此类行为降低了缓存错失,因而提高了应用程序的性能。频繁地分配和删除将使理想难于实现。 > > 默认的内存管理器是导致性能进一步降低的另一个罪魁祸首。通用的内存管理器不得不在后台替我们解决很多问题。每次我们申请一块内存,内存管理器都要在可用块列表中搜索最佳匹配, > 若是没有找到,则需要一块较大的空闲块划分成多个小块,以避免在一次分配中浪费过多空间。当释放一块内存的时候,内存管理器会试图将它与相邻的空闲块合并以减少碎片。确实, > 我们希望一个通用的内存管理器替我们进行这些操作,但作为代价而消耗的多个CPU运行周期是我们所不希望的。

想起在大二学习C++的时候就是通过实现一个内存池来入门的

弱引用和空对象

> 程序员常常对指针又爱又恨。指针占用很少的存储空间,而且可以很有效率地处理,用户通过指针可以真正自由地进行内存操作。但是,在指针问题上,哪怕是最小的错误可常会导致内存泄漏, > 或者在最坏的情况下带来程序崩溃和用户的崩溃。 > > 本文关注一些处理游戏资源的时候,由在内存中进行对象移动操作而导致的常见问题。在此讨论的技术也将与关于载入和卸载内存对象的问题密切相关。我们将看到弱引用是如何成为直接使用C++ > 指针之外的一个好的选择。作为弱引用的补充,我们将用到空对象,从此再也不必每次使用对象前检查指针是否为空了,而且这还将带来一些有价值的附加作用。 > > 使用指针 > > 虽然指针是很方便,而且我们也对指针使用有着多年的经验,但是对于有些任务,指针并不是最好的方法。让我们举操作游戏中的动态资源为例。在这里的资源一词,是指所有从磁盘读入的数据: > 纹理贴图、场景模型、声音等等。 > > 我们在处理指针时遇到的根本问题就是确定资源的生命周期。如果你载入一张大贴图,同时有两个模型共享这同一张贴图,它们一定是指向内存中的同一个位置。那么在其中一个模型被删除的时候 > 应怎么办呢?肯定不能删除贴图,因另一个模型还用着它。但是这贴图怎能知道是否还有其他对象在引用自身呢?肯定我们也不能不进行任何处理,因为要是那样,等两个模型都被删除的时候, > 这个贴图就是一大块内存泄漏。 > > 在这样的情况下,我们必须提出自己的方案。通行的做法是进行引用计数。也就是说每当一个模型获得了一个指向某张纹理的指针,该纹理的引用计数器加一。相应地,每当一个模型被删除时,它 > 原先引用着的纹理的引用计数器就减一。当引用计数器的值降到零时,就自动删除该纹理。在理论上,这是个很好的主意,但它倾向于产生臃肿的代码,常常成为编程错误的发源地。 > > 还有相关的问题,比如在内存中移动资源,或只是暂时地将资源卸出内存而旋即载回。如果那张贴图仅仅被用在游戏世界的一小部分里,那么我们何不当玩家身处其他地方的时候将其卸载, > 当玩家再次接近这个区域时再将其载入?这样做将节省很可观的内存数量,从而使我们能够突破目标开发平台上的内存限制,也不再局限于是能设计小规模的关卡。 > > 我们如何将贴图交换出去呢?方法之一是通知程序中拥有该贴图指针的部分,使其暂停使用该贴图。要不然当它们试图使用该贴图的时候,程序多半会崩溃。即使这张贴图一直没有显示出来的机会, > 但等到重新读入这张贴图的时候,该贴图很可能会保存在一个不同的内存位置里。为了避免该问题,我们需要一个方法来更新所有使用该贴图的对象里指针的值。 > > 理想的解决方案应该给我们这样的功能,即对离开镜头很远的模型载入中等程度的、仅包含一些mipmap的贴图,而对距离镜头很近的那些模型载入最清晰的、也是占用内存最多的贴图版本。 > > 和许多其他计算机科学领域里的两难问题一样,该问题可以通过增加一层间接引用来解决。使用句柄是可行的方法之一。每一个资源都由叫做句柄的唯一的ID来标示(可能在载入时由资源管理系统指定)。 > 游戏本身承诺决不保存指向资源的指针,而是保存句柄。每一帧,每当游戏需要显示一个模型或进行任何需要访问该贴图的计算时,应要求资源管理器返回对应该句柄的贴图指针。然后我们检查 > 返回的指针是否是空的(NULL),如果非空,则加以处理。 > > 这给了我们卸载资源,或改变它们在内存中的位置的自由。资源管理器能够跟踪响应的改动,而程序的其他部分总是通过句柄间接地获得指针来进行操作。不幸的是,这很不方便:每次都要从句柄转换成指针, > 还非得检测得到的指针是否为空不可,很快就让人厌烦了。而且还有一个问题,如果我们决定将一个指针保存"几帧而已",可是资源在这几帧里卸载了优惠怎样? > > 下面将介绍一个解决方案,在提供直接操纵指针的舒适感和自由度的同时,解决了之前我们提到的大多数问题。 > > 弱引用 > > 从本文的角度来看,弱引用指的是那种和实际指向的对象之间至少存在一层间接地引用。例如之前提到的句柄,因为通过映射机制实现了一层间接,就是一个很好的弱引用的例子。 > 而基本的C语言指针,因为采用直接的引用模式,则是一种强引用(指针包含所引用的对象的实际内存地址)。 > > 注意“弱引用”这一名词通常在关于内存管理的文献中有另外的含义。在内存管理中,缺乏强引用指向的对象将被系统释放,因此弱引用并不强制保留对象。 > > 我们的目的是使弱引用像指针一样容易使用。由于其行为像指针,但内嵌的逻辑会处理间接引用的本质,这一类引用通常称作智能指针(smart pointer)。 > > 本文对使用指针来记录游戏资源介绍了一种灵活的替代方案。新方案使我们对资源的生命周期有更好的控制,也允许我们自由移动资源。甚至可以在游戏运行时将 > 一些资源从内存中卸出。所有这些新功能将使我们能够开发更大的游戏关卡,创造连续的游戏世界。 > > 本文也介绍了空对象的概念,也就是用来替代那些不在内存中的资源的特殊资源。这些特殊资源的行为和其他同类资源相同,因此游戏代码无需在每次使用资源的时候 > 检查该资源是否已经载入。空资源一般是看不见的,以避免被显示出来而造成的瑕疵,不过在调试阶段也可以让资源醒目地显示。

智能指针在学校也写过,后来在项目中提过这个方案,但是并没被采用,现在想想当时还是太年轻,不够强势

游戏中的实体管理系统

> 新入门的游戏开发者们常常会被自己的劳动成果给迷倒:开发一个新的shader程序,创建一个例子系统或者播放3D的音效。虽然这些层面的开发是很重要,而且的确有趣, > 然而使一堆松散的代码变成完整功能的游戏就常常不是那么迷人的任务了。本篇文章则把焦点集中在此游戏实体的管理上。 > > 概述 > > 现代游戏充满各种各样的实体。玩家、敌人和发射的炮弹,这些要素在游戏世界里乱哄哄地跑来跑去。地形、建筑物、天空和云彩定义环境。路径点(waypoint)、触发器 > (trigger)和脚本指导玩家的体验。得分、破坏和物理方面组成游戏世界的逻辑和规则。 > > 不是对于所有的这些东西分别对待,作为特殊目的的要素,把它们结合为一个系统并且提供一个共用的结构和通信方法是很方便的。基于消息的方法来管理实体能够解决很多问题 > 并提供一种方法来统一大部分的关键游戏要素。 > > 任何事情通过消息来出现 > > 在一个基于消息的系统中,实体做的任何事情是对应消息的。为了画出一个实体,你发送出一条消息。为了让实体在空间移动,你则给它也发送一条消息。假如它们都没有取得任何消息, > 实体会无所事事而不做任何事情。 > > Win32的windowing API就是个很好的比方。Windows GUI做的任何事情是对应消息的,它们从应用程序、其他窗体(windows)或者操作系统而来。实体,像窗体一样对于它内部数据或 > 者实现一无所知。它们简单地发送和响应定义好的消息集。实体对于它们不关心或不能理解的消息则不予理睬。 > > 万事万物都是实体 > > 构建实体管理系统中的一个关键方面,就是将任何事物都作为能通过消息来控制的实体来考虑。试图统一像发射物、地形和游戏脚本这样多样的要素,虽然看起来优点不可理解, > 但是通过统一,我们得到了系统的强大和简单性。 > > 就像一颗子弹需要更新位置、检查碰撞以及被画出,场景需要被画出并响应碰撞检测。一个脚本测量一关的“赢的条件”需要在每一帧执行,但是不对任何消息响应。从这个简单的例子, > 我们能够开始通过消息统一我们的实体。

子弹、地形和脚本实体怎样响应各种消息

||子 弹| 地 形 | 脚 本 | |---|---|---| |更新|处理|忽略|处理| |画|处理|处理|忽略| |检查碰撞|处理|忽略|忽略| |响应碰撞检测|忽略|处理|忽略|

在这个方案中,即使每个逻辑脚本在世界的物理意义上不存在,也能够像其他任何实体那样对待。这个实体机制能够在更加复杂的游戏代码周围充当一个简单但强大的封装层。

系统的要素

实体管理系统由4个主要的组件组成。

• 实体消息:定义实体怎样沟通。

• 实体代码:实现一实体类的代码和数据。

• 类列表:维护一个已经注册在案的实体类的列表。

• 实体管理器:创建实体、管理实体树、支持发送消息到一个或者多个实体。

基于消息的实体系统的实际好处很多:

• 同质性:各不相同的游戏实体能够使用相同的系统来管理和控制,即隐藏更加复杂代码到精简型实体wrapper。

• 功能分权:帮助加强渲染、动力学、逻辑甚至客户端相对服务器端任务的分离。这对于大的项目至关重要。

• 单控制点:实体的所有扩展头式通过单控制点,EntSendMessage指令。因此,消息日志、DLL接口和挂靠系统到脚本语言就变得容易。

• 完全抽象:发射一颗子弹和发射一飞弹的过程是相同的。只是改变类的名字和发送相同的消息。简化后的类将忽略更多兄弟姐妹类需要的消息。

• 可扩展性:增加新的特性就常常如创建一个新消息那么简单。因为老的实体能够忽略新的指令,增加的特性不会打破什么。旧的代码能够调上来在后面加速。

• 有限的依赖性:在一个纯消息驱动的系统,只有消息列表(或者基类)需要用每个实体模块来包含。

• 重用:正确地构建,实体能够无需做任何改变就可以重用到新游戏中。FPS中的天空实体能够在飞行模拟器中工作得很好,只要支持正确地消息。

创建一个强健的实体管理系统是一个游戏程序员能够承担的最有价值的任务之一。它提供了一个全局框架,游戏剩余的部分可以适应它。更重要的是, 它创建了一系列标准和协定,方便快速地原型化和开发。实现系统和对于老的系统花样翻新需要时间,但相比增加新特性来说有上十倍的好处。

在上一卷中也讨论过实体,同样推荐学习Game Framework中实体系统的封装:结合使用了C# ObjectPool、编辑器查看实体状态、自动回收机制等等

使用XML而不牺牲速度

> 制作新游戏最大的挑战之一,就是如何生成游戏中那海量的数据。像XML这样标准数据元格式,能够通过重用已有的工具,方便数据的创建和编辑。然而, > XML也有一些缺点,最大的问题就是数据过大、载入和解析(parse)过慢。 > > 在本文中,我们介绍一种新的二进制流式文件格式XDS,在大致达到XML的表达力的同时,避免了XML的这些缺点。我们也给出既支持XML又支持XDS数据的工具集, > 你可在游戏制作周期中在XML和XDS两者之间安全地切换。 > > 为什么要使用XML呢? > > XML在几年之前,就已经被证明其在开发性和协同方面的价值,而当制作一个新游戏的时候,这两件事情通常没有在优先考虑之列。在那同时,环绕在XML周围的 > 大肆宣传从来没有减弱过。好像在你所能到达的地方,就有人在吹捧XML是以前不知道的解决问题的方法。那么,这些吹捧真的言过其实吗?难道就真的和游戏一点边 > 都不沾? > > 美好的事物 > > XML并不是无关紧要的。在现代软件开发中它是一个很重要的工具,使用它所带来的好处远远超过其缺点。虽然它不是万能的,但它必定会在你的开发过程中占有一席之地。 > > 虽然有很多可选的存储技术,然而XML超过其他任何特有的数据格式,其专有的最大的优点是它有一个制定得很好的标准且有一个相对庞大的产业作为后盾。确实有成百上千 > 个现成可用的工具,你可以立即拿来为你的项目服务,从编辑器到展示工具以及转换工具。通过使用XML用于游戏数据,你可以最大程度地利用这些工具。例如,你采用一个XML > 编辑器和增加一个XML schema来描述你的游戏的数据时,无需写一行代码,你就能得到一个简单层次的编辑器用于你的游戏。这意味你的设计团队能够很快开始产生游戏数据。 > > 假如你的游戏数据在开发中需要改变,你将无需删掉所有已经生成的数据,也不需要写一个一次性的程序将其转换为新的数据格式。事实上,你能够简单地编写一个XSL转换, > 用他将数据转换成新的格式。 > > 使用XML允许设计人员在游戏中改变且立即看到它们。相反,假如他们看到在游戏中有些奇怪问题,他们能够打开XML文件然后使用编辑器或浏览器来检查、识别和改正问题。 > > 天堂中的陷阱 > > 然而,在XML世界中也不那么完美。从一开始,读取XML比读取一般应用程序中特定的二进制文件格式更加复杂。因此普通的XML库庞大而复杂。对于一完整特征的XML库来说, > 超过1M的编译代码量不算奇怪。试图把那个压进你那页已拥挤不堪的存储区域。XML的负担也扩展到数据文件占据空间数和所花费读它们的时间总量。 > > 最后,在允许设计者从浏览器中检查的同时也允许终端用户也做同样的事情。虽然这对于培育游戏的MOD社区有很大的帮助,但同时也泄漏了游戏中所有你不想让玩家知道的秘密。 > > 很明显XML的大部分优点都来自于设计和开发的阶段,而大部分二进制数据的优点则来自发布阶段。如果我们既希望利用XML给我们好处,又不想再较慢的代码和较大的内存和 > 磁盘存储方面付出代价。那么XDS元格式就是为解决这个问题而设计的。

公司开发的编辑器第一版用XML序列化和反序列化,第二版用Scriptable Objects

小结

技术分享才会带来创新

题外话

BTG第一个项目开发在完成7卷读书笔记后会正式开始,还剩下3卷。同时梳理之前的编辑器代码,做第三版重构,增加新特性

参考资料

Introduction to Scriptable Objects

Saving and Loading Data: XmlSerializer