首页/编程/一年的雨:以前
编程

一年的雨:以前

2020-11-04T14:08:04 + 01:00

变化到一年的雨

自2019年11月的早期访问发布以来,雨队的一年宣布了一些变化。“在上几个月后,显而易见的是,福彩中心没有达到球队最初计划的球员人数。这会提示对服务器结构的一些更改,因为玩家正在努力寻找匹配项。而不是具有自动匹配的专用服务器,现在存在一个对等解决方案,允许玩家自己打开福彩中心或加入其他人的福彩中心。一年的雨后于2020年3月离开早期访问,比以前安排在没有一些最初计划的功能的情况下。最后,以下物品“以前”讨论了一种基于重建方法储蓄福彩中心状态的方法。可悲的是,这种方法没有进入完成的福彩中心,因为微调会占据大量时间。此外,重建方法旨在与专用服务器一起使用,由于官方雨水服务器的官方关闭而不再提供。但我们仍然希望与您分享关于重建方法的文章,因为它包含了很多智能想法,可以创建强大的Savegame结构!“

在更改之前,福彩中心程序员安卡克林Drews撰写了关于设计高效的Savegame结构以及如何使用虚幻引擎4创建它们。

在推进到特别艰难的老板之后,能够拯救福彩中心几乎是如今给出的。大多数时候,玩家甚至不得不记得拯救他们的福彩中心了,因为福彩中心定期为他们自动保存。

事件创建Savegame的概念非常简单:“拍摄福彩中心状态的快照,将其写入内存并按需恢复。”但是,当我们开始在雨中思考Savegames时,概念很快就会进入“福彩中心中的所有数据的快照,这与尽可能紧密地重建其状态。将其推入一个字节数,可以写入内存并使用它初始化新福彩中心会话而不是加载的默认初始化。“这听起来更复杂,也可能对其他人来说是更准确的描述。

在一年的雨中,我们将拥有不同的可储存福彩中心模式:广告系列,小冲突和定制福彩中心。在本文中,我们只会涵盖小冲突福彩中心模式,因为其他人正常工作SAM从SAM起草技术的角度来看。

杀了它!用火杀死它! Spark Mage Shen The Scarred的行动。

恢复vs重建
在我进入任何细节之前,我希望清楚地对恢复状态和重建状态之间的区别。谈论恢复状态时,状态本身存储在Savegame中,并将直接恢复。这适用于简单数据,让我们说出一个单位的当前健康价值。
单位行为不能轻松恢复。在一年的雨中,我们称之为我们的单位的“订单”,如:

  • 走向位置&在途中辩护。
  • 攻击另一个单位&如果你太遥远了,请靠近。
  • 抓住& defend a position.

首先,它们被实现为行为树,其通过设计并不意味着从某些内部叶节点开始。其次,它将占用更多的内存空间,而不是存储单位的顺序类型,目标和订单数据。重新发出订单并让单位的AI从已保存的数据中朝着清洁和有效状态进行,是我所说的重建状态。我们没有完全相同的状态,就像我们实际恢复的那样,但它将足够接近并且不太容易出错。它还允许更改行为树逻辑,而无需编写额外的代码以适应这些更改。

重建状态的另一个好原因是单位统计,即损坏,范围,速度,依赖于单位的级别,并从平衡表中读取。因此,为了保存一些内存空间,我们只需存储单位的级别进度并告诉它升级到保存的级别,而不是每一个统计值存储。将通过福彩中心逻辑重建适当的统计值,并且还反映对平衡表的可能更改而不编写额外的代码。

从演员收集数据的示意图。

Savegame实现
根据我们的概念,在规划我们的Savegame实施时,有三个要点是:

1.拍摄福彩中心中的所有数据的快照,该数据与尽可能紧密地重建其状态。

我们通过彻底了解构成我们福彩中心状态的原因来实现这一目标,以便我们能够有效地定义和收集与重建福彩中心会话相关的所有数据。

将改变福彩中心会话结果的一切,或者将改变整体经验与福彩中心状态和与Savegames相关的相关。这听起来有点摘要,所以让我们看看上面的截图。在形象中,我们看到一个福彩中心英雄,火花法师沉伤。在六级和额外的200经验中,她投入能力指向她的三个能力。其中一个让火元素(单位给她右侧),另一个是一个敌对单位到地面的法术(由蠕变的橙色发光表示),第三个是效果火球咒语的区域。其中三个都在很酷。

她还有统计数据(损坏,范围,冷却,速度,最大健康状况),这些统计数据依赖于她的水平。目前,她没有受到了,但是火元素和蠕变不是。总体上有六个单位:沉,火元素,三个蠕动和一棵树。树木以及任何类型的建筑和非静态结构,被认为是一年的雨中的单位。我们看不到的是两个球员,一个人类播放器和一个控制蠕动的中立敌对的人。

在一个实际的小冲突会议中,随着雨中的一年内的比赛,为四名球员设计了更多的比赛。

因此,福彩中心模式具有两个球员的两个团队,每个球员都伪造自己的基础,扩展到新的资源来源(也是单位),以及
发掘强大的军队。因此,有不同类型,建筑单位的陆军单位,以及许多英雄单位,为三个可玩派系中的每一个具有独特的培训能力。研究的技术也提供:它们可以根据您选择的角色而有所不同,也可以作为单位计算;喜欢召唤的单位,蠕变单元,老板单位和陷阱单元。所有这些都与福彩中心状态相关:

  • 单位国家
  • 球员国家
  • 脚本逻辑状态
  • 地图,经过了福彩中心时间& Difficulty Level

这是很多,通过查看清单,虽然我已经将其崩溃到了四个子弹点,但在写这一点之前,在一个Savegame中,我们甚至将其崩溃并将其定义为每年雨的福彩中心状态:

  • Savegame相关的行为者
  • 元数据

2.将快照推入可以写入内存的字节数组。

现在我们将进入本文中最具技术部分。准备好。我们跳下序列化的兔子洞。

幸运的是,虚幻引擎4有一些非常方便但易于忽视的功能,因为它们没有充分记录。

指针序列化 
虚幻引擎具有一个不替换的结构,具有若干派生的儿童结构。基本上,法拉利队将包装一个字节数组并为此添加过载<<运营商提供阅读&写入功能。取决于Farchive是否使用FMemoryReader或/和FmemoryWriter创建的行档案<<可重少将归档值读取成分或将值从存档中的值写入存档。此读/写功能包括将UObject指针转换为可节省的字符串ID值,该值可以代表虚幻映射中的对象的路径,或者在福彩中心资产目录中的资产路径以及其他方式。有一种技术限制,将字符串ID解析为内存地址需要一个对象抵抗路径;否则,它将解析为NULLPTR。这使我们可以处理指针,即,我可以处理价值类型的方式,我们可以跳过ID系统的实现,以恢复演员之间的关系。

树的两个状态。

Savegame旗帜
Savegame标志是Uproperty说明符,可在源中提供,以及每个变量启用/禁用它的蓝图代码。它由UObjects的内置序列化方法与Farchive的BissaveGame标志组合使用。如果bissavegame标志设置为true,则序列化方法只会读/写具有savegame标志的UPRopertys。我们使用Savegame标志主要用于让Blueprint Logic Savegame Ready,因此设计师不必考虑自定义序列化。为了实际使用Savegame标志,我们编写了自己的Farchive子类型,默认情况下具有BissaveGameFlag。

我们的SaveGames对象本身没有过于复杂的结构,并且基于虚幻的USAVEGAME对象。它们包含一系列代理(见左图),它通过迭代所有现有的演员并告诉他们在Farchive中储存他们通过它们,以及我们需要重建的一些数据来迭代我们检索的所有相关数据。以及我们需要重建的一些数据演员后来。

此外,Savegames还包括SaveMeMetainfo对象,其中包含我们在会话上下文之外所需的福彩中心会话的所有元信息:

  • 经过了福彩中心时间
  • 地图名称
  • 难度级别

以及有关Savegame对象的元信息以及

  • 福彩中心版本
  • 创建时间戳
  • savegame name.

在一方面,在Savegame对象和元信息对象中拆分数据的原因是更清晰的结构。另一方面,它允许我们更快地阅读元信息,因为我们不需要将整个Savegame对象加载到内存中,如果我们感兴趣的只是Save中显示的元信息& Load menu.

persistablecomponent.
要识别我们感兴趣的演员,我们将一个特殊的演员组合物附加到它,我们称之为PersistableComponent,现在,如果我们迭代当前地图上的所有演员,我们可以轻松地跳过所有没有持久性的演员。例如,它还为我们提供了一个地方,例如我们可能会放置的位置。给定演员的Savegame版本。

persistentdatacontainer接口(仅在c ++中)
我们让所有包含相关的非静态数据的ActorComponents实现一个接口,以将其标记为持久性数据容器,并为组件强制执行存储()/ restore()方法。现在我们可以通过我们的Farchvie并让组件句柄存储/恢复本身,因为它们有时需要访问私人成员。我们决定在案例外,我们是否通过调用ActorComponent的虚幻序列化方法来存储数据,或者写入自定义代码以读取/写入Farchive的值。

启动新福彩中心的简化流程图VS加载福彩中心。

序列化方法
我们始终使用Actor的内置序列化方法来存储/恢复来自Actor本身感兴趣的所有数据,因为这是我们将存储Savegame标记的给定演员的蓝图变量的地方。

3.使用它来初始化新的福彩中心会话,而不是加载的默认初始化。

我不希望加载Savegame的过程,因为有几个原因,从开始新福彩中心的过程中大不相同。首先,实现尽可能接近现有代码的功能总是一个好主意;它为您节省了维护不同的实现的麻烦,这些实施基本相同。其次,更改新福彩中心的初始化会自动更改加载福彩中心的初始化。但大多数情况下,我没有看到它不同的原因。想象一下,我们正在谈论加载一个策略福彩中心会话与较不重要的设置,如国际象棋。将通过将电路板从其盒子中取出,将所有棋子放在他们指定的起始位置,并将所有棋子放在董事会上的新象棋福彩中心。将通过将电路板从其盒子中取出,将其放置起来,并将所有剩余的棋子放在董事会上,将所有剩余的棋子放在他们之前的位置。差异是:

  • 哪些碎片放在板上?
  • 碎片在哪里?

设置福彩中心的实际过程保持不变。现在看看左边的流程图。绿色盒子突出了两个过程的差异;灰色盒子是相同的。

由于左分支显示,首先从地图池中装载随机地图,首先初始化新的小冲突匹配,这已经有一些由我们的设计人员放置的中立单位。然后将玩家产生生成,为每个播放器生成用于小冲突模式的初始单元(四个工人单位和主建筑物),并且将分配播放器前存在的单位。福彩中心开始后,工人单位获得收集命令,以便自动开始收集资源。

右分支显示了Savegame的加载过程。我们仍然加载地图;但是,它不是随机挑选的,而是通过从Savegame中获取ID。我们仍然产卵玩家,分配中性单位,并以相同的顺序启动福彩中心。我们只有一个主要区别:以前的催产单位再次产生,死中立单位被摧毁。从已保存的会话中,初始单位将在生成播放器之前重建。

如上所知的原因:如果对象存在于路径上,我们只能解析存储的指针。因此,在DeserialIsing保存数据之前,我们首先确保为我们要恢复的所有演员提供关系。

最后
我们继续玩,好像几乎没有任何事情发生过。


安卡克林德鲁斯
福彩中心程序员

Ann-Kathrin是DaeDalic娱乐的福彩中心程序员;五年前,在获得汉堡大学的计算机科学学士学位之后,几乎直接实习了六个月的实习。在加入一年的雨之前,她一直在致力于多个不同的功能的多平台项目,随时准备跳进新的挑战。

关于作者: 4. 2020年11月
类别:
去顶级