损伤损伤区域与事件
损伤区域与事件
损伤区域告诉你的游戏,车身每一侧的凹陷有多严重。车身共六侧:前、后、左、右、上、下。每一侧报告其最深的凹陷和平均凹陷,取值从未受损车身的 0 到凹陷已达到其允许上限的 1。当任一侧发生变化时,事件 On Damage Changed 会被触发,使你的游戏能够对损伤作出反应,例如亮起警示灯、降低最高速度或计分。
六侧。 每一侧是车身沿根组件某一轴向的外侧三分之一。前侧为根的 +X,后侧为 -X,左侧为 -Y,右侧为 +Y,上侧为 +Z,下侧为 -Z。相邻的侧面在边缘处重叠,因此靠近拐角的凹陷会同时计入两侧。
最大值与平均值。 对每一侧,Max 是该侧最深的凹陷:晶格节点的最大位移,除以配置文件的 Max Displacement,并限制在 1 以内。Mean 是该侧所有节点上同一数值的平均值。两者的取值都在 0 到 1 之间。
任意盒体。 GetDamageInBox 可针对你选定的盒体,例如大灯周围的区域,返回相同的两个数值。该盒体位于根组件的空间中,与玻璃板的 Crush Link Box 处于同一空间。
仅计已确认的损伤。 区域读取的是服务器已确认的损伤。在客户端上,你预测的命中在服务器确认之前不会计入区域。因此,事件在每一端报告的数值都相同,而被服务器拒绝的命中永远不会显示。
事件何时触发。 事件每帧至多检查一次,并且是在车身晶格发生变化之后。只有当区域与上一次报告的内容不同时,它才会触发。它在每一端都会触发,包括专用服务器。修复会以零值触发一次该事件。中途加入的玩家,会在其所在的端上由复制的损伤构建出晶格之后,收到该事件。
所需条件。 车辆适配器需要开启 Dirt and Dents,配置文件需要开启 Dents。否则,区域读数为零,事件也永远不会触发。适配器会转发该事件以及两个获取函数,因此你可以直接绑定到车辆的适配器,而无需找到形变组件。
损伤区域与刚度区域不是同一回事。刚度区域是使车身的某部分变得更硬或更软的盒体,Crushform.ShowZones 会绘制它们。损伤区域只报告已经发生的损伤。关于刚度区域,参见软区。
- 打开车辆的蓝图,例如
BP_VehicleAdvSedan的副本。选中其 Crushform Chaos Vehicle Adapter 组件,并确保 Dirt and Dents 已开启。在关卡中放置第二辆车,供下面的检查使用,并使它远离你驾驶的车。 - 打开车辆的形变配置文件,确保 Dents 已开启。参见凹陷与晶格。
- 无需再创建任何其他内容。区域来自车身的晶格。下一节说明如何读取它们。
在蓝图中,将 On Damage Changed 绑定到车辆的适配器上。该事件以 Zones 的形式传递六侧数据。拆分 Zones 以获取 Front,再拆分 Front 以获取其 Max,并将其打印出来。同样的引脚可以得到其他各侧的数据,把 Max 换成 Mean 即可。
此图每次触发事件时都会打印前侧的 Max。它打印的是一个裸数字,没有标签:只有数值,没有侧面的名称。该事件也通过相同的引脚传递到其他每一侧。
在 C++ 中,将 lambda 绑定到形变组件的原生事件上,并以相同方式读取盒体。原生事件会在蓝图事件之前触发,且传递的区域数据相同。车身碰撞体跟随的正是同样的凹陷。
#include "CFDamageTypes.h"#include "CFDeformComponent.h"
Deform->OnDamageChangedNative.AddLambda([](const FCFDamageZones& Zones){ UE_LOG(LogTemp, Log, TEXT("Front max %.2f"), Zones.Front.Max);});
const FCFDamageValues Nose = Deform->GetDamageInBox(NoseBox); // NoseBox: an FBox in the owner's root spaceDeform 是车身的 UCFDeformComponent。NoseBox 是根组件空间中的 FBox。
| 属性 | 作用 | 默认值 |
|---|---|---|
UCFVehicleAdapterComponent::bDirtAndDents | 为车辆开启损伤。关闭时:区域读数为零,事件永不触发。 | 开 |
UCFProfile::bDents | 命中和挤压是否会使车身凹陷。关闭时:区域永不改变。 | 开 |
UCFProfile::MaxDisplacement | 计为完全凹陷的位移(cm)。Max 和 Mean 都以它为除数。 | 60 |
没有其他设置会改变区域。数值来自车身的晶格。
检查是否正常工作
Section titled “检查是否正常工作”在除 Shipping 之外的任何构建中,于编辑器内运行。Crushform.DebugImpact 不会命中你驾驶的车辆,因为轨迹会跳过它。因此,请使用带有图表的第二辆车的副本,停放在远离你自己车辆的地方。从其正面接近它,然后输入 Crushform.DebugImpact 10 <name>,并用你副本在 World Outliner 中显示的名称的一部分代替 <name>。命中会瞄准该车车身上离其中心最近的那一点,从你所在的位置看去,所以从正面接近时,命中落在车的前部。事件会触发,图表打印前侧的 Max。正面的命中应打印出大于零的数值。
若要检查后侧,将图表的断开引脚从 Front 改为 Back,然后从副本的后方接近,并以相同方式命中。运行 Crushform.RepairAll:每一侧都会回到零,并且事件会以零值触发一次。
在权威端,CFScriptedHits::ApplyScatteredHits 会在车身的随机点上施加若干次命中。调试模式的预设使用了它。
- On Damage Changed 从不触发。 车辆适配器上的 Dirt and Dents 已关闭,或配置文件中的 Dents 已关闭,或车身没有配置文件。请开启这些开关,并指定一个配置文件。
- 命中车辆后,区域立即显示为零。 在客户端上,你自己的命中只是预测,直到服务器确认为止,而区域只计入已确认的损伤。请稍等片刻,等待服务器的回应,或在服务器上读取区域。
- 在一处可见的凹陷上,盒体读数为零。 盒体不在根组件的空间中,或位于车身晶格之外,或尚未设置。请在车身所属根组件的空间中构建盒体,即与根组件的轴相同的空间。
- 前后看起来对调了。 各侧沿根组件的轴划分,以 +X 为前。如果车辆网格体的朝向不同,需要旋转其根组件以使其匹配。请检查根组件的旋转。