← 返回项目技术总览

按下 WASD 任一方向键 + LeftShift 触发空中闪现,角色沿相机方向瞬移 5000 单位距离,带溶解特效、径向模糊屏幕效果和四向闪避蒙太奇。蓝图版在 BP_Nyx 的 InputEventGraph,C++ 版在 ChangliCharacter::DoAirDash。

— 系统一句话总结

一、执行流程:蓝图 vs C++ 对照

两个版本走相同的逻辑链,C++ 把蓝图的 Timeline 驱动换成了 Tick 帧内驱动。

[输入] WASD + LeftShift(空中态)
  │
  ├─ [守卫] 闪现中不重复触发(AirDashRemaining > 0)
  ├─ [守卫] 打断当前普攻(IsAttacking → InterruptAttack / ResetAttackM)
  │
  ├─ [方向] W→前 / S→后 / A→左 / D→右
  │    GetDashDirection() → Controller.GetControlRotation().Vector()(含 Pitch,不压平 Z)
  │    GetDashRightVector() → Controller.GetControlRotation() + Yaw+90°
  │
  ├─ [安全落点] CalculateSafeDashLocation(Dir, DashLerpDistance=5000)
  │    胶囊体 Sweep:碰到 StaticMesh/Landscape 墙 → 回退到最近阻挡点
  │    植被放行:IsVegetationHit 判断关键词,树/草不挡
  │
  ├─ [特效 1] SpawnSystemAttached(DashDissolveFX) → 角色根组件
  ├─ [特效 2] ApplyAirDashScreenEffect() → EF_PP_RadialBlur_Dodge 挂相机 WeightedBlendables
  ├─ [特效 3] FlashCamLag_Disable() → SpringArm CameraLagSpeed = 9999
  ├─ [特效 4] WriteRadialBlurMPC(0.8f) → MPC_RadialBlur BlurIntensity 峰值
  ├─ [溶解] StartDissolveOut() → 角色溶解消失
  │
  ├─ [位移] VLerp(DashLerpStart, DashLerpTarget, α)  0.3s 插值
  │    α = curTime / DashLerpDuration(0.3)
  │    SetActorLocation(Sweep=true)
  │
  └─ [动画] PlayMontage(PickDashMontageByInput(), 1.0f)
          Nyx_Dodge_Montage / Dodge_Back / Dodge_Left / Dodge_Right

二、穿模修复:V1 → V5 五次迭代

闪现穿模是本功能最棘手的问题,先后经历 5 个版本修复。根因集中在 CalculateSafeDashLocation 的碰撞通道选择、Sweep 结果排序和 Z 轴处理上。

V1

蓝图独占版

全蓝图实现,无 C++ 安全计算 → 直接闪现,经常穿墙穿树

初版 · 穿模严重

V2

ECC_Visibility 通道

C++ LineTraceMultiByChannel(ECC_Visibility) → 漏检 StaticMeshActor 墙

ECC_Visibility 很多物体不响应

V3

ECC_WorldStatic + 植被放行

通道改为 WorldStatic,加 IsVegetationHit 关键词匹配("Vegetation"/"Grass"/"Tree")

墙能挡住了,但 Z 轴处理有问题

V4

Landscape 识别修复

类名判断 "Landscape" → "Landscape"(Contains 不匹配,导致地面不识别)

修类名匹配条件

V5

bypass Sweep + Z 钳位

蓝图端 bSweep=false 穿树;C++ 只改 Z 轴到地面位置,XY 保持方向一致

最终定案

关键修复:C++ CalculateSafeDashLocation 函数体(V5 定案)

// TransformCharacter.cpp · CalculateSafeDashLocation
FVector ATransformCharacter::CalculateSafeDashLocation(const FVector& Dir, float MaxDist)
{
    FVector Start = GetActorLocation();
    FVector End = Start + Dir.GetSafeNormal() * MaxDist;

    // 路径 Sweep(胶囊体)
    FHitResult Hit;
    FCollisionQueryParams Params(SCENE_QUERY_STAT(DashSafe), false, this);
    Params.AddIgnoredActor(this);
    GetWorld()->SweepSingleByChannel(Hit, Start, End, FQuat::Identity,
        ECC_WorldStatic, FCollisionShape::MakeCapsule(CapsuleRadius, CapsuleHalfHeight), Params);

    FVector SafeTarget = Hit.bBlockingHit ? Hit.Location : End;

    // Z 轴单独钳位到地面(Landscape + WorldStatic)
    FHitResult GroundHit;
    GetWorld()->LineTraceSingleByChannel(GroundHit,
        SafeTarget + FVector(0, 0, 100), SafeTarget + FVector(0, 0, -500),
        ECC_WorldStatic, Params);

    if (GroundHit.bBlockingHit) {
        // 只改 Z,XY 保持原方向(修复"闪现方向与镜头不对齐")
        SafeTarget.Z = GroundHit.Location.Z + CapsuleHalfHeight;
    }
    return SafeTarget;
}

关键修复:蓝图端 bSweep 设为 false

蓝图 CF51(SetActorLocation 节点)→ bSweep = false,让蓝图位移也穿树(树靠 C++ 层 Sweep 只挡墙,不挡植被)。

三、特效清单(精确到资产路径 + 挂载点)

类型资产路径挂载/注入点时序
Niagara 粒子NS_DodgeNyx/Game/Test_02/VFX/FlashVFX/角色根组件 SnapToTarget闪现开头立即 Spawn
Niagara 拖尾NS_FlyTrail/Game/Effect/蓝图 Niagara 组件 FlyParticle悬空飞行态 Activate
PP 径向模糊EF_PP_RadialBlur_Dodge/Game/Effect/MaterialInstance/PostProcess/相机 WeightedBlendables 权重 1.00.15s 后权重→0,0.4s 移除
MPC 径向MPC_RadialBlur全局 MPCBlurIntensity=0.8,WarpFlowIntensity=0.8峰值 → 跟随 Timeline 衰减
SpringArmCameraLag相机组件内建CameraLagSpeed=9999,RotationLagSpeed=9999闪现全程禁用 Lag,结束恢复

四、关键变量速查表

变量名类型默认值说明
DashLerpDistancefloat5000最大闪现距离(单位)
DashLerpDurationfloat0.3闪现插值时长(秒)
DashLerpStartFVector—闪现起点位置
DashLerpTargetFVector—安全落点位置
AirDashRemainingfloat0闪现剩余时间(>0 表示闪现中)
bIsAttackingboolfalse普攻进行中(闪现需先打断)
DashDissolveFXTObjectPtr\软路径加载闪现溶解特效资产
DashMontageForward/Back/Left/RightUPROPERTY FSoftObjectPath—四向闪避蒙太奇

五、踩坑速查