224 lines
9.4 KiB
C#
224 lines
9.4 KiB
C#
using Cielonos.MainGame.Buffs.Character;
|
||
using Cielonos.MainGame.Characters;
|
||
using SLSUtilities.General;
|
||
using UnityEngine;
|
||
|
||
namespace Cielonos.MainGame
|
||
{
|
||
/// <summary>
|
||
/// 脉冲力的方向计算模式。
|
||
/// </summary>
|
||
public enum ImpulseForceMode
|
||
{
|
||
/// <summary>使用预设的固定力矢量。</summary>
|
||
Custom,
|
||
/// <summary>沿攻击区域 forward 方向施加力(投射物常用)。</summary>
|
||
Dynamic,
|
||
/// <summary> 沿攻击区域 forward 方向施加力,但在计算时将竖直分量忽略(仅在水平面内施加力,适合地面攻击)。 </summary>
|
||
FlattenedDynamic,
|
||
/// <summary>从攻击区域中心向外推开目标。</summary>
|
||
Repulsion,
|
||
/// <summary>将目标拉向攻击区域中心。</summary>
|
||
Suction,
|
||
}
|
||
|
||
/// <summary>
|
||
/// 攻击区域的脉冲子模块:配置并向命中目标施加击退/击飞力。
|
||
/// 采用单构造函数 + 链式 With* 方法进行配置。
|
||
/// </summary>
|
||
public class ImpulseSubmodule : AttackAreaSubmoduleBase
|
||
{
|
||
private ImpulseForceMode forceMode;
|
||
private Vector3 customForce;
|
||
private float dynamicStrength;
|
||
private float strengthXZ;
|
||
private float strengthY;
|
||
|
||
private bool isLaunch;
|
||
private bool isParabolic;
|
||
private float impulseDuration;
|
||
private AnimationCurve impulseCurve;
|
||
private bool applyStun;
|
||
private float stunDuration;
|
||
|
||
private float gravityMultiplier = 1f;
|
||
private float gravityDuration;
|
||
|
||
// ────────────────────────────────────────────────────────────────────
|
||
// Constructor
|
||
// ────────────────────────────────────────────────────────────────────
|
||
|
||
/// <summary>
|
||
/// 创建一个新的 ImpulseSubmodule 实例。
|
||
/// </summary>
|
||
/// <param name="attackArea">所属的攻击区域。</param>
|
||
/// <param name="duration">脉冲持续时间(秒)。</param>
|
||
/// <param name="curve">速度衰减曲线。null 使用默认 EaseOut。</param>
|
||
public ImpulseSubmodule(AttackAreaBase attackArea, float duration, AnimationCurve curve) : base(attackArea)
|
||
{
|
||
this.impulseDuration = duration;
|
||
this.impulseCurve = curve;
|
||
}
|
||
|
||
// ────────────────────────────────────────────────────────────────────
|
||
// Chain Configuration
|
||
// ────────────────────────────────────────────────────────────────────
|
||
|
||
/// <summary>
|
||
/// 设置为斥力模式:从攻击区域中心向外推开目标。
|
||
/// </summary>
|
||
public ImpulseSubmodule WithRepulsion(float strengthXZ, float strengthY = 0)
|
||
{
|
||
this.forceMode = ImpulseForceMode.Repulsion;
|
||
this.strengthXZ = strengthXZ;
|
||
this.strengthY = strengthY;
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置为吸力模式:将目标拉向攻击区域中心。
|
||
/// </summary>
|
||
public ImpulseSubmodule WithSuction(float strengthXZ, float strengthY = 0)
|
||
{
|
||
this.forceMode = ImpulseForceMode.Suction;
|
||
this.strengthXZ = strengthXZ;
|
||
this.strengthY = strengthY;
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置为自定义力矢量模式。
|
||
/// </summary>
|
||
public ImpulseSubmodule WithCustomForce(Vector3 force)
|
||
{
|
||
this.forceMode = ImpulseForceMode.Custom;
|
||
this.customForce = force;
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置为动态力模式:沿攻击区域 forward 方向施加指定强度的力。
|
||
/// </summary>
|
||
public ImpulseSubmodule WithDynamicForce(float strength, bool isFlattened = true)
|
||
{
|
||
this.forceMode = isFlattened ? ImpulseForceMode.FlattenedDynamic : ImpulseForceMode.Dynamic;
|
||
this.dynamicStrength = strength;
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 标记为击飞:无视抗性,自动附加眩晕。
|
||
/// parabolic 为 true 时使用物理弧线(距离击飞),为 false 时使用曲线衰减(空战浮空)。
|
||
/// </summary>
|
||
/// <param name="strengthY">竖直方向的初始击飞强度。</param>
|
||
/// <param name="parabolic">是否使用抛物线物理。默认 true。</param>
|
||
public ImpulseSubmodule WithLaunch(float strengthY, bool parabolic = true)
|
||
{
|
||
this.isLaunch = true;
|
||
this.strengthY = strengthY;
|
||
this.isParabolic = parabolic;
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 标记击退时附加眩晕(击飞始终自动眩晕,无需此方法)。
|
||
/// </summary>
|
||
/// <param name="duration">眩晕持续时间(秒)。0 表示跟随脉冲持续时间。</param>
|
||
public ImpulseSubmodule WithStun(float duration = 0f)
|
||
{
|
||
this.applyStun = true;
|
||
this.stunDuration = duration;
|
||
return this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置命中后的重力修正。通过 VerticalMoveModification Buff 实现。
|
||
/// multiplier 小于 1 使目标浮空(空战连击),大于 1 使目标加速坠落(Finisher)。
|
||
/// 当 multiplier 大于 1 时,会先清除目标身上已有的浮空 Buff,确保坠落生效。
|
||
/// </summary>
|
||
/// <param name="multiplier">重力缩放倍率。0 = 完全浮空,1 = 正常,大于 1 = 加速坠落。</param>
|
||
/// <param name="duration">重力修正持续时间(秒)。</param>
|
||
public ImpulseSubmodule WithGravityModifier(float multiplier, float duration)
|
||
{
|
||
this.gravityMultiplier = multiplier;
|
||
this.gravityDuration = duration;
|
||
return this;
|
||
}
|
||
|
||
// ────────────────────────────────────────────────────────────────────
|
||
// Force Calculation & Application
|
||
// ────────────────────────────────────────────────────────────────────
|
||
|
||
/// <summary>
|
||
/// 根据当前力模式计算施加给目标的最终力矢量。
|
||
/// </summary>
|
||
public Vector3 GetFinalForce(CharacterBase target)
|
||
{
|
||
return forceMode switch
|
||
{
|
||
ImpulseForceMode.Repulsion =>
|
||
(target.centerPoint.position - attackArea.topParent.position).Flatten().normalized * strengthXZ
|
||
+ Vector3.up * strengthY,
|
||
|
||
ImpulseForceMode.Suction =>
|
||
(attackArea.topParent.position - target.centerPoint.position).Flatten().normalized * strengthXZ
|
||
+ Vector3.up * strengthY,
|
||
|
||
ImpulseForceMode.Dynamic =>
|
||
attackArea.topParent.forward * dynamicStrength,
|
||
|
||
ImpulseForceMode.FlattenedDynamic =>
|
||
attackArea.topParent.forward.Flatten().normalized * dynamicStrength,
|
||
|
||
_ => customForce,
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 对目标角色施加脉冲力。自动区分 Automata 和玩家的处理路径。
|
||
/// </summary>
|
||
public void ApplyImpulse(CharacterBase target)
|
||
{
|
||
Vector3 force = GetFinalForce(target);
|
||
|
||
if (target.movementSc is AutomataLandMovementSubcontroller automataSc)
|
||
{
|
||
automataSc.ApplyHitImpact(force, isLaunch, isParabolic,
|
||
impulseDuration, impulseCurve, applyStun, stunDuration,
|
||
gravityMultiplier, gravityDuration);
|
||
}
|
||
else
|
||
{
|
||
target.movementSc.impulseSm.ApplyImpulse(force, isLaunch, impulseDuration, impulseCurve, isParabolic);
|
||
ApplyGravityModifier(target);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 对非 Automata 目标(玩家等)施加重力修正 Buff。
|
||
/// </summary>
|
||
private void ApplyGravityModifier(CharacterBase target)
|
||
{
|
||
if (gravityDuration <= 0f) return;
|
||
|
||
if (gravityMultiplier > 1f)
|
||
{
|
||
ClearExistingGravityModifier(target);
|
||
}
|
||
|
||
new VerticalMoveModification(gravityDuration, gravityMultiplier).Apply(target);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清除目标身上已有的 VerticalMoveModification Buff(Finisher 坠落前调用)。
|
||
/// </summary>
|
||
private static void ClearExistingGravityModifier(CharacterBase target)
|
||
{
|
||
if (target.buffSm.TryGetBuff<VerticalMoveModification>(out var existingBuff))
|
||
{
|
||
existingBuff.Remove();
|
||
}
|
||
}
|
||
}
|
||
}
|