跳转到内容
CRUSHFORMV1.1.0
在 Fab 上获取

世界围栏与道具

围栏与道具

围栏是沿关卡中一条样条线排列的一行立柱和段。车辆撞上围栏的某个单元时,会把该单元破坏:栅栏条碎裂,铁丝网板倒塌。车辆会损失一部分速度,破碎的部分则作为碎片抛向空中。

编辑器俯视图,选中了一段木栅栏:它的一排栅栏条沿着 S 形样条线排列,样条线的点、切线控制柄和变换 Gizmo 显示在其末端。
所选 BP_CF_FencePicket 的栅栏条沿 S 形样条线排列。

Proving Ground 上有两段这样的围栏:一段木制栅栏和一段铁丝网围栏。两者分别随附为 BP_CF_FencePicket 和 BP_CF_FenceChainLink。

轿车撞破了栅栏:栅栏条碎裂,碎片飞散。
轿车撞破了铁丝网围栏:网板折叠并落下。

围栏是一个 ACFBreakableFence Actor。它的 Spline 就是这条线。Actor 沿这条线放置立柱和段,每个立柱或段就是一个单元。单元有一组等级,从完好到最后一种破损形态。击中会提高单元的等级,最高可达该单元的最高等级。

  • 定义。 单元由 UCFBreakablePropDefinition 类的数据资产构成。围栏为它的段使用一个定义,如果这条线有立柱,还可以再为立柱使用一个定义。定义包含网格体以及各项规则:如何破碎、车辆会损失多少、何时重生。
  • 布局。 在编辑器中构建围栏时,这条线会变成单元。布局随 Actor 一起保存。在联网游戏中,围栏不会重新布局:它的布局来自已保存的那一份。
  • 烘焙碎片。 单元抛出的碎片,由其完好网格体通过定义上的 Bake Pieces 生成。烘焙会把它们作为资产保存在定义旁边。未烘焙的定义不会抛出任何碎片。
  • 车辆。 车辆以足够快的速度撞上单元时,会将其破坏。每个被破坏的单元都会分走车辆的一部分速度,并且单元还可能使车身凹陷。
  • 任何刚体。 开启 Breaks from Any Body 的定义,会被任何足够重、足够快的物理刚体或行走的 Pawn 破坏,而不只是车辆。
Bake
Bake as Single Piece
Density Kg Per Cm 30.0005
Max Piece Length Cm125.0
Min Piece Volume Cm 350.0
Cut Tilt Degrees15.0
Bake Seed1
Bake Revision1
Pieces16 Array elements
Bake Pieces
DA_CF_FencePicket 的 Bake 分组,末尾是 Bake Pieces 按钮。

定义的 Bake 分类中有 Bake Pieces 按钮。它会替换之前的烘焙结果。编辑器工具蓝图可以通过 CFBreakable Piece Bake Library 的静态函数 BakePieces(Definition, OutError) 执行同样的烘焙(仅限编辑器)。

本节使用 Proving Ground 上的木栅栏。要制作自己的围栏,请参见第 3 步。

  1. 在 Content Browser 中,随附的围栏位于 Plugins › Crushform Content › Fences。
  2. 把 BP_CF_FencePicket 拖入关卡,或者从 Place Actors 面板放置一个 ACFBreakableFence。样条线的长度决定数量:围栏大约每隔 Post Spacing Cm 的距离放置一段。要得到更长的一排,请拉长样条线。
  3. 要制作自己的围栏,首先创建一个定义。在 Content Browser 中选择 Add › Miscellaneous › Data Asset,选择类 CFBreakable Prop Definition,并为它命名。把它的 Intact Mesh 设为该单元的网格体,然后在 Bake 分类中点击 Bake Pieces。碎片会出现在该资产旁边。
  4. 在关卡中选中该围栏。在 Details 面板中,于 Fence 下把 Span Definition 设为你的定义。如果这条线上有立柱,也请设置 Post Definition。
Fence
Post DefinitionNone
Span DefinitionDA_CF_FencePicket
Post Spacing Cm0.0
已放置的栅栏条的 Fence 分组,其中有段定义和立柱间距。
  1. 把 Post Spacing Cm 设为立柱之间的距离。设为 0 时使用段定义的瓦片长度。围栏会把立柱沉入地面,沉入深度为 Post Sink Cm(默认 5 cm);开启 Snap to Ground 时,立柱会吸附到地面上。

蓝图可以通过一次击中破坏单元。用单元所属的对象类型(而不是通道)通过 Line Trace For Objects 追踪该单元。默认的单元配置文件为 OverlapAllDynamic:它的单元是与所有通道重叠的 WorldDynamic 对象,因此通道追踪(例如基于 Visibility 的追踪)永远不会在它们上停下。把追踪的对象类型设为单元的类型(默认为 WorldDynamic),然后用 ApplyHitResultOnAuthority 把击中应用到追踪找到的单元上。它接收追踪得到的 Hit Result、一个 Strength 和一个 Hit Kind:该类型必须在定义的 Hit Responses 中有一行,并且强度必须达到其某个 Hit Level Thresholds。请在自定义事件中运行此操作,并且从服务器代码调用 ApplyHitResultOnAuthority,而不要从客户端调用:它是静态函数,只在权威端运行。

在 C++ 中,同样的调用无需追踪即可把击中应用到单元上:

#include "CFBreakableInstancesComponent.h"
#include "CFBreakableTypes.h"
// Needs the CrushformBreakable module in your Build.cs (see Installation).
void BreakFirstUnitOnServer(UCFBreakableUnitsComponent* Units, const FVector& Location, const FVector& Direction)
{
if (IsValid(Units) && Units->GetUnitCount() > 0)
{
FCFBreakableHit Hit;
Hit.Location = Location;
Hit.Direction = Direction;
Hit.Strength = 900.f;
Hit.Kind = FName(TEXT("Bullet"));
Units->ApplyHitOnAuthority(0, Hit);
}
}

签名为 UCFBreakableUnitsComponent 上的 virtual bool ApplyHitOnAuthority(int32 UnitIndex, const FCFBreakableHit& Hit)。FCFBreakableHit 有 Location、Direction、Strength 和 Kind。用 Fence->GetBreakableInstances() 从 Actor 获取围栏的组件;它是 UCFBreakableInstancesComponent,是 UCFBreakableUnitsComponent 的子类。

在 Hit Responses 中没有对应行的类型不会产生任何效果,并且单元只会被它所达到的 Hit Level Thresholds 提升等级。因此在测试之前,请在定义的 Hit Responses 中为你的类型添加一行,并设置你的强度能够达到的阈值。示例中的 Bullet 类型只是一个例子。

定义的设置位于其 Details 面板中。围栏的设置位于围栏 Actor 上。默认值来自插件本身。

属性作用默认值
ACFBreakableFence::PostSpacingCm立柱之间的距离。0 使用段的瓦片长度。0
ACFBreakableFence::bSnapToGround立柱和段是否吸附到线下方的地面。true
ACFBreakableFence::PostSinkCm立柱沉入地面的深度。5
UCFBreakablePropDefinition::TileLengthCm网格体的相邻副本在围栏上相隔的距离。0 使用网格体自身沿 X 轴的长度。0
UCFBreakablePropDefinition::VehicleSpeedLossFraction每破坏一个单元,车辆损失的速度比例。0.025
UCFBreakablePropDefinition::MaxVehicleSpeedLossCmS一个单元从车辆上最多带走的速度,单位 cm/s。150
UCFBreakablePropDefinition::VehicleDentSpeedFraction传入单元并使车身凹陷的车辆速度比例。0 表示该单元永远不会使车身凹陷。0.5
UCFBreakablePropDefinition::bBreaksFromAnyBody是否任何物理刚体或行走的 Pawn 都能破坏该单元。false
UCFBreakablePropDefinition::AnyBodyMinMassKg能从任意刚体破坏该单元的最轻刚体质量。20
UCFBreakablePropDefinition::AnyBodyMinSpeedCmS能从任意刚体破坏该单元的最慢刚体速度,单位 cm/s。300
UCFBreakablePropDefinition::PawnMinSpeedCmS能破坏该单元的最慢行走 Pawn 速度,单位 cm/s。250
UCFBreakablePropDefinition::RespawnDelaySeconds被破坏的单元保持倒下的时长。0 表示永不重生。300
UCFBreakableDefinition::HitLevelThresholds外部击中要把单元提升到各个等级所需的强度:第一项对应等级 1,下一项对应等级 2。空
UCFBreakableDefinition::HitResponses每种外部击中类型如何影响单元。没有对应行的类型不产生任何效果。空
UCFBreakableDefinition::bBakeAsSinglePiece把整个完好网格体烘焙为一块碎片,不进行切割。false
UCFBreakableDefinition::MaxPieceLengthCm长度超过此值的孤岛会被切割成块。60
UCFBreakableDefinition::DensityKgPerCm3碎片质量等于烘焙体积乘以此密度。0.0005
UCFBreakableSettings::UnitCollisionProfile单元实例的碰撞配置文件。None(使用 OverlapAllDynamic)

项目设置位于 Project Settings › Plugins › Crushform Breakable 下的 Units、Any Body 和 Respawn 分组中。被破坏的单元,在定义允许的情况下,会在没有玩家 Pawn 位于 RespawnClearRadiusCm(4000 cm)之内、并且没有属于 RespawnBlockingObjectTypes 的刚体与其位置重叠时重新立起。

在除 Shipping 之外的任何构建中,用波浪号键打开控制台。

  • stat CFBreakableInstances 会显示 Breakable Respawn Check 和任意刚体的周期。stat CFPropContact 显示车辆一侧的情况。
  • 撞上 BP_CF_FencePicket:一个单元碎裂开来,它的碎片四散。
  • 撞上 BP_CF_FenceChainLink:它的网板倒塌。

调试模式可以让世界中所有被破坏的道具同时重生:在其面板的 World 下,点击 Respawn props 按钮。参见调试模式。

原因。 围栏没有已保存的布局,而且这是一个联网游戏。日志会显示这一行:

%s: no saved layout; a networked fence must be placed and laid out in the editor

单机(Standalone)游戏会在运行时为围栏布局。联网游戏则不会,否则每个端都会各自选出自己的单元。

修复。 在编辑器中放置围栏,设置好它的样条线和段定义,并让布局完成构建。保存关卡。布局会随围栏一起保存。

原因。 这条线要求的单元数超过了围栏能容纳的上限,即 256。若带有立柱,则上限为 127 段。日志会显示:

%s: %d spans requested, capped to %d; split the line into several fences

修复。 把这条线拆分成几座围栏,每座的段数都少一些。

原因。 该单元的定义没有被烘焙,而没有烘焙碎片的定义不会生成任何碎片。破坏仍然会发生,但没有东西可以抛出。

修复。 在定义的 Bake 分类中点击 Bake Pieces。烘焙会替换之前的结果,因此在更改网格体或烘焙设置后需要重新烘焙。

非车辆的刚体撞上单元却无法破坏它

Section titled “非车辆的刚体撞上单元却无法破坏它”

原因。 定义上的 bBreaksFromAnyBody 是关闭的。或者该刚体比 AnyBodyMinMassKg 轻,或比 AnyBodyMinSpeedCmS 慢,又或者 Pawn 比 PawnMinSpeedCmS 慢。

修复。 开启定义上的 Breaks from Any Body,并降低质量和速度限制,使其适合你希望破坏该单元的刚体。

关于碎片本身,参见碎片。关于破坏时的声音与特效,参见撞击反馈。