686 lines
21 KiB
C#
686 lines
21 KiB
C#
using UnityEngine;
|
||
|
||
namespace NBF
|
||
{
|
||
public enum FishingBobberControlMode
|
||
{
|
||
AirPhysics,
|
||
WaterPresentation,
|
||
}
|
||
|
||
public enum FishingBobberBiteType
|
||
{
|
||
None,
|
||
Tap,
|
||
SlowSink,
|
||
Lift,
|
||
BlackDrift,
|
||
}
|
||
|
||
public enum BobberTiltAxis
|
||
{
|
||
LocalX,
|
||
LocalZ,
|
||
}
|
||
|
||
[DisallowMultipleComponent]
|
||
[RequireComponent(typeof(Rigidbody))]
|
||
public class FishingBobberFeature : FishingLineNodeMotionFeature
|
||
{
|
||
protected override int DefaultPriority => 100;
|
||
|
||
#region 检测入水
|
||
|
||
[Header("入水检测")]
|
||
[Tooltip("当前测试阶段固定水面高度。")]
|
||
public float waterLevel = 0f;
|
||
|
||
[Tooltip("浮漂底部进入水面达到该深度后,切换为水面表现控制。")]
|
||
public float enterWaterDepth = 0.002f;
|
||
|
||
[Tooltip("浮漂底部高于该深度时退出水面表现控制。通常设为负值用于滞回。")]
|
||
public float exitWaterDepth = -0.01f;
|
||
|
||
[Tooltip("浮漂总高度,单位米。")]
|
||
public float floatHeight = 0.08f;
|
||
|
||
[Tooltip("如果 Pivot 在浮漂底部填 0;如果 Pivot 在模型中部,填底部相对 Pivot 的本地 Y 偏移。")]
|
||
public float bottomOffsetLocalY;
|
||
|
||
[Tooltip("Y 轴控制的平滑时间。")]
|
||
public float ySmoothTime = 0.08f;
|
||
|
||
[Tooltip("Y 轴平滑时允许的最大竖直速度。")]
|
||
public float maxYSpeed = 2f;
|
||
|
||
[Tooltip("Y 轴死区,小范围内直接贴目标值以减少微抖。")]
|
||
public float yDeadZone = 0.0005f;
|
||
|
||
#endregion
|
||
|
||
#region 吃水控制
|
||
|
||
[Header("吃水控制")]
|
||
[Tooltip("基准底部重量。当前重量等于该值时,使用基础吃水深度。")]
|
||
public float neutralBottomWeight = 1f;
|
||
|
||
[Tooltip("当前底部总重量。运行时可由其他脚本更新。")]
|
||
public float currentBottomWeight = 1f;
|
||
|
||
[Tooltip("基准重量下的基础吃水深度。")]
|
||
public float baseDraftDepth = 0.02f;
|
||
|
||
[Tooltip("每单位重量变化对应增加或减少的吃水深度。")]
|
||
public float draftDepthPerWeight = 0.01f;
|
||
|
||
[Tooltip("吃水深度下限。")]
|
||
public float minDraftDepth = 0.005f;
|
||
|
||
[Tooltip("吃水深度上限。")]
|
||
public float maxDraftDepth = 0.08f;
|
||
|
||
[Tooltip("吃水深度变化的平滑时间。")]
|
||
public float draftSmoothTime = 0.18f;
|
||
|
||
#endregion
|
||
|
||
#region 漂相动画
|
||
|
||
[Header("漂相动画")]
|
||
[Tooltip("漂相位移动画的平滑时间。")]
|
||
public float biteSmoothTime = 0.03f;
|
||
|
||
[Tooltip("点漂默认振幅。")]
|
||
public float tapAmplitude = 0.008f;
|
||
|
||
[Tooltip("点漂默认时长。")]
|
||
public float tapDuration = 0.18f;
|
||
|
||
[Tooltip("缓沉默认振幅。")]
|
||
public float slowSinkAmplitude = 0.025f;
|
||
|
||
[Tooltip("缓沉默认时长。")]
|
||
public float slowSinkDuration = 1.2f;
|
||
|
||
[Tooltip("顶漂默认振幅。")]
|
||
public float liftAmplitude = 0.015f;
|
||
|
||
[Tooltip("顶漂默认时长。")]
|
||
public float liftDuration = 1.2f;
|
||
|
||
[Tooltip("黑漂默认振幅。")]
|
||
public float blackDriftAmplitude = 0.06f;
|
||
|
||
[Tooltip("黑漂默认时长。")]
|
||
public float blackDriftDuration = 0.8f;
|
||
|
||
#endregion
|
||
|
||
#region 输入测试
|
||
|
||
[Header("输入测试")]
|
||
[Tooltip("是否启用运行时按键测试漂相。")]
|
||
public bool enableDebugInput = true;
|
||
|
||
[Tooltip("停止当前漂相的按键。")]
|
||
public KeyCode stopBiteKey = KeyCode.R;
|
||
|
||
[Tooltip("触发点漂的按键。")]
|
||
public KeyCode tapKey = KeyCode.T;
|
||
|
||
[Tooltip("触发缓沉的按键。")]
|
||
public KeyCode slowSinkKey = KeyCode.G;
|
||
|
||
[Tooltip("触发顶漂的按键。")]
|
||
public KeyCode liftKey = KeyCode.H;
|
||
|
||
[Tooltip("触发黑漂的按键。")]
|
||
public KeyCode blackDriftKey = KeyCode.B;
|
||
|
||
#endregion
|
||
|
||
#region 姿态控制
|
||
|
||
[Header("姿态控制")]
|
||
[Tooltip("重量低于该值时,姿态趋向躺漂。")]
|
||
public float lyingWeightThreshold = 0.4f;
|
||
|
||
[Tooltip("重量达到该值附近时,姿态趋向半躺。")]
|
||
public float tiltedWeightThreshold = 0.8f;
|
||
|
||
[Tooltip("重量达到该值及以上时,姿态趋向立漂。")]
|
||
public float uprightWeightThreshold = 1.2f;
|
||
|
||
[Tooltip("躺漂对应的倾角。")]
|
||
public float lyingAngle = 88f;
|
||
|
||
[Tooltip("半躺对应的倾角。")]
|
||
public float tiltedAngle = 42f;
|
||
|
||
[Tooltip("立漂对应的倾角,通常为 0。")]
|
||
public float uprightAngle = 0f;
|
||
|
||
[Tooltip("绕哪个本地轴做倾倒。")]
|
||
public BobberTiltAxis tiltAxis = BobberTiltAxis.LocalX;
|
||
|
||
[Tooltip("是否反转倾倒方向。")]
|
||
public bool invertTiltDirection;
|
||
|
||
[Tooltip("姿态旋转的平滑速度。")]
|
||
public float rotationLerpSpeed = 8f;
|
||
|
||
[Tooltip("入水后用于压制旋转抖动的角阻尼。")]
|
||
public float waterAngularDamping = 999f;
|
||
|
||
#endregion
|
||
|
||
#region 运行时状态
|
||
|
||
public FishingBobberControlMode CurrentMode => _mode;
|
||
public FishingBobberBiteType CurrentBiteType => _activeBiteType;
|
||
public float CurrentDraftDepth => _currentDraftDepth;
|
||
public float CurrentBottomWeight => currentBottomWeight;
|
||
|
||
private Rigidbody _rb;
|
||
private FishingBobberControlMode _mode = FishingBobberControlMode.AirPhysics;
|
||
|
||
private bool _defaultsCached;
|
||
private bool _waterStateInitialized;
|
||
private float _defaultAngularDamping;
|
||
private bool _defaultUseGravity;
|
||
private RigidbodyConstraints _defaultConstraints;
|
||
|
||
private float _draftVelocity;
|
||
private float _currentDraftDepth;
|
||
private float _ySmoothVelocity;
|
||
private float _biteOffsetY;
|
||
private float _biteOffsetYVelocity;
|
||
|
||
private bool _uprightPoseCached;
|
||
private Quaternion _cachedUprightRotation;
|
||
private Quaternion _uprightReferenceRotation;
|
||
private Quaternion _targetRotation;
|
||
|
||
private FishingBobberBiteType _activeBiteType = FishingBobberBiteType.None;
|
||
private float _biteTimer;
|
||
private float _biteDuration;
|
||
private float _biteAmplitude;
|
||
|
||
#endregion
|
||
|
||
#region Unity 生命周期
|
||
|
||
private void Awake()
|
||
{
|
||
EnsureRuntimeReferences();
|
||
InitializeRuntimeState();
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
HandleDebugInput();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 运动控制接入
|
||
|
||
public override bool IsSupportedNode(FishingLineNode node)
|
||
{
|
||
return node != null && node.Type == FishingLineNode.NodeType.Float;
|
||
}
|
||
|
||
protected override void OnBind()
|
||
{
|
||
EnsureRuntimeReferences();
|
||
InitializeRuntimeState();
|
||
}
|
||
|
||
public override bool CanControl()
|
||
{
|
||
EnsureRuntimeReferences();
|
||
if (_rb == null || !IsSupportedNode(Node))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
var submergeDepth = GetSubmergeDepth();
|
||
if (_mode == FishingBobberControlMode.WaterPresentation)
|
||
{
|
||
return submergeDepth >= exitWaterDepth;
|
||
}
|
||
|
||
return submergeDepth > enterWaterDepth;
|
||
}
|
||
|
||
public override void OnMotionActivated()
|
||
{
|
||
EnsureRuntimeReferences();
|
||
EnterWaterPresentationMode();
|
||
}
|
||
|
||
public override void OnMotionDeactivated()
|
||
{
|
||
EnsureRuntimeReferences();
|
||
ExitWaterPresentationMode();
|
||
}
|
||
|
||
public override void TickMotion(float deltaTime)
|
||
{
|
||
EnsureRuntimeReferences();
|
||
if (_rb == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var submergeDepth = GetSubmergeDepth();
|
||
if (submergeDepth < exitWaterDepth)
|
||
{
|
||
ExitWaterPresentationMode();
|
||
return;
|
||
}
|
||
|
||
if (_mode != FishingBobberControlMode.WaterPresentation)
|
||
{
|
||
EnterWaterPresentationMode();
|
||
}
|
||
|
||
UpdateBiteAnimation(deltaTime);
|
||
UpdateDraft(deltaTime);
|
||
var nextRotation = CalculateNextRotation(deltaTime);
|
||
UpdateVerticalPosition(deltaTime, nextRotation);
|
||
ApplyRotation(nextRotation);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 漂相接口
|
||
|
||
public void SetBottomWeight(float weight)
|
||
{
|
||
currentBottomWeight = weight;
|
||
}
|
||
|
||
public void PlayTap(float amplitude = -1f, float duration = -1f)
|
||
{
|
||
StartBite(
|
||
FishingBobberBiteType.Tap,
|
||
amplitude > 0f ? amplitude : tapAmplitude,
|
||
duration > 0f ? duration : tapDuration);
|
||
}
|
||
|
||
public void PlaySlowSink(float amplitude = -1f, float duration = -1f)
|
||
{
|
||
StartBite(
|
||
FishingBobberBiteType.SlowSink,
|
||
amplitude > 0f ? amplitude : slowSinkAmplitude,
|
||
duration > 0f ? duration : slowSinkDuration);
|
||
}
|
||
|
||
public void PlayLift(float amplitude = -1f, float duration = -1f)
|
||
{
|
||
StartBite(
|
||
FishingBobberBiteType.Lift,
|
||
amplitude > 0f ? amplitude : liftAmplitude,
|
||
duration > 0f ? duration : liftDuration);
|
||
}
|
||
|
||
public void PlayBlackDrift(float amplitude = -1f, float duration = -1f)
|
||
{
|
||
StartBite(
|
||
FishingBobberBiteType.BlackDrift,
|
||
amplitude > 0f ? amplitude : blackDriftAmplitude,
|
||
duration > 0f ? duration : blackDriftDuration);
|
||
}
|
||
|
||
public void StopBite()
|
||
{
|
||
_activeBiteType = FishingBobberBiteType.None;
|
||
_biteTimer = 0f;
|
||
_biteDuration = 0f;
|
||
_biteAmplitude = 0f;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 内部实现
|
||
|
||
private void EnsureRuntimeReferences()
|
||
{
|
||
if (_rb == null)
|
||
{
|
||
_rb = Node != null && Node.Body != null ? Node.Body : GetComponent<Rigidbody>();
|
||
}
|
||
}
|
||
|
||
private void InitializeRuntimeState()
|
||
{
|
||
if (_rb == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (!_defaultsCached)
|
||
{
|
||
_defaultAngularDamping = _rb.angularDamping;
|
||
_defaultUseGravity = _rb.useGravity;
|
||
_defaultConstraints = _rb.constraints;
|
||
_defaultsCached = true;
|
||
}
|
||
|
||
_currentDraftDepth = CalculateRawDraftDepth();
|
||
_draftVelocity = 0f;
|
||
_ySmoothVelocity = 0f;
|
||
_biteOffsetY = 0f;
|
||
_biteOffsetYVelocity = 0f;
|
||
_targetRotation = _rb.rotation;
|
||
|
||
if (!_uprightPoseCached)
|
||
{
|
||
_cachedUprightRotation = _rb.rotation;
|
||
_uprightPoseCached = true;
|
||
}
|
||
|
||
_uprightReferenceRotation = _cachedUprightRotation;
|
||
}
|
||
|
||
private void EnterWaterPresentationMode()
|
||
{
|
||
if (_rb == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
_mode = FishingBobberControlMode.WaterPresentation;
|
||
_waterStateInitialized = true;
|
||
_uprightReferenceRotation = _cachedUprightRotation;
|
||
_targetRotation = _rb.rotation;
|
||
_draftVelocity = 0f;
|
||
_ySmoothVelocity = 0f;
|
||
_biteOffsetYVelocity = 0f;
|
||
_currentDraftDepth = CalculateRawDraftDepth();
|
||
|
||
_rb.useGravity = false;
|
||
_rb.angularDamping = waterAngularDamping;
|
||
_rb.constraints = _defaultConstraints | RigidbodyConstraints.FreezeRotation;
|
||
_rb.angularVelocity = Vector3.zero;
|
||
}
|
||
|
||
private void ExitWaterPresentationMode()
|
||
{
|
||
_mode = FishingBobberControlMode.AirPhysics;
|
||
RestorePhysicsState();
|
||
}
|
||
|
||
private void RestorePhysicsState()
|
||
{
|
||
if (_rb == null || !_defaultsCached)
|
||
{
|
||
return;
|
||
}
|
||
|
||
_rb.useGravity = _defaultUseGravity;
|
||
_rb.angularDamping = _defaultAngularDamping;
|
||
_rb.constraints = _defaultConstraints;
|
||
}
|
||
|
||
private float GetSubmergeDepth()
|
||
{
|
||
return waterLevel - GetBottomWorldPosition().y;
|
||
}
|
||
|
||
private Vector3 GetBottomWorldPosition()
|
||
{
|
||
return transform.TransformPoint(new Vector3(0f, bottomOffsetLocalY, 0f));
|
||
}
|
||
|
||
private float CalculateRawDraftDepth()
|
||
{
|
||
var weightDelta = currentBottomWeight - neutralBottomWeight;
|
||
var targetDraft = baseDraftDepth + weightDelta * draftDepthPerWeight;
|
||
return Mathf.Clamp(targetDraft, minDraftDepth, maxDraftDepth);
|
||
}
|
||
|
||
private void UpdateDraft(float deltaTime)
|
||
{
|
||
var targetDraft = CalculateRawDraftDepth();
|
||
_currentDraftDepth = Mathf.SmoothDamp(
|
||
_currentDraftDepth,
|
||
targetDraft,
|
||
ref _draftVelocity,
|
||
Mathf.Max(0.0001f, draftSmoothTime),
|
||
Mathf.Infinity,
|
||
deltaTime);
|
||
}
|
||
|
||
private void UpdateVerticalPosition(float deltaTime, Quaternion targetRotation)
|
||
{
|
||
var position = _rb.position;
|
||
var targetY = waterLevel - _currentDraftDepth - GetBottomOffsetWorldY(targetRotation) + _biteOffsetY;
|
||
|
||
if (Mathf.Abs(position.y - targetY) < yDeadZone)
|
||
{
|
||
position.y = targetY;
|
||
_ySmoothVelocity = 0f;
|
||
}
|
||
else
|
||
{
|
||
position.y = Mathf.SmoothDamp(
|
||
position.y,
|
||
targetY,
|
||
ref _ySmoothVelocity,
|
||
Mathf.Max(0.0001f, ySmoothTime),
|
||
maxYSpeed,
|
||
deltaTime);
|
||
}
|
||
|
||
_rb.MovePosition(position);
|
||
|
||
var velocity = _rb.linearVelocity;
|
||
if (Mathf.Abs(velocity.y) > 0f)
|
||
{
|
||
velocity.y = 0f;
|
||
_rb.linearVelocity = velocity;
|
||
}
|
||
}
|
||
|
||
private Quaternion CalculateNextRotation(float deltaTime)
|
||
{
|
||
var targetTiltAngle = EvaluateTargetTiltAngle();
|
||
var signedAngle = invertTiltDirection ? -targetTiltAngle : targetTiltAngle;
|
||
var localAxis = tiltAxis == BobberTiltAxis.LocalX ? Vector3.right : Vector3.forward;
|
||
|
||
_targetRotation = _uprightReferenceRotation * Quaternion.AngleAxis(signedAngle, localAxis);
|
||
_rb.angularVelocity = Vector3.zero;
|
||
return Quaternion.Slerp(
|
||
_rb.rotation,
|
||
_targetRotation,
|
||
1f - Mathf.Exp(-Mathf.Max(0.01f, rotationLerpSpeed) * deltaTime));
|
||
}
|
||
|
||
private void ApplyRotation(Quaternion nextRotation)
|
||
{
|
||
_rb.rotation = nextRotation;
|
||
}
|
||
|
||
private float GetBottomOffsetWorldY(Quaternion rotation)
|
||
{
|
||
return (rotation * new Vector3(0f, bottomOffsetLocalY, 0f)).y;
|
||
}
|
||
|
||
private float EvaluateTargetTiltAngle()
|
||
{
|
||
if (currentBottomWeight <= lyingWeightThreshold)
|
||
{
|
||
return lyingAngle;
|
||
}
|
||
|
||
if (currentBottomWeight <= tiltedWeightThreshold)
|
||
{
|
||
var t = Mathf.InverseLerp(lyingWeightThreshold, tiltedWeightThreshold, currentBottomWeight);
|
||
return Mathf.Lerp(lyingAngle, tiltedAngle, t);
|
||
}
|
||
|
||
if (currentBottomWeight <= uprightWeightThreshold)
|
||
{
|
||
var t = Mathf.InverseLerp(tiltedWeightThreshold, uprightWeightThreshold, currentBottomWeight);
|
||
return Mathf.Lerp(tiltedAngle, uprightAngle, t);
|
||
}
|
||
|
||
return uprightAngle;
|
||
}
|
||
|
||
private void StartBite(FishingBobberBiteType type, float amplitude, float duration)
|
||
{
|
||
if (_mode != FishingBobberControlMode.WaterPresentation)
|
||
{
|
||
return;
|
||
}
|
||
|
||
_activeBiteType = type;
|
||
_biteTimer = 0f;
|
||
_biteDuration = Mathf.Max(0.01f, duration);
|
||
_biteAmplitude = Mathf.Max(0f, amplitude);
|
||
_biteOffsetYVelocity = 0f;
|
||
}
|
||
|
||
private void UpdateBiteAnimation(float deltaTime)
|
||
{
|
||
if (_activeBiteType == FishingBobberBiteType.None)
|
||
{
|
||
_biteOffsetY = Mathf.SmoothDamp(
|
||
_biteOffsetY,
|
||
0f,
|
||
ref _biteOffsetYVelocity,
|
||
Mathf.Max(0.0001f, biteSmoothTime),
|
||
Mathf.Infinity,
|
||
deltaTime);
|
||
return;
|
||
}
|
||
|
||
_biteTimer += deltaTime;
|
||
var t = Mathf.Clamp01(_biteTimer / _biteDuration);
|
||
var targetOffset = 0f;
|
||
|
||
switch (_activeBiteType)
|
||
{
|
||
case FishingBobberBiteType.Tap:
|
||
if (t < 0.35f)
|
||
{
|
||
var downT = t / 0.35f;
|
||
targetOffset = -Mathf.SmoothStep(0f, _biteAmplitude, downT);
|
||
}
|
||
else
|
||
{
|
||
var upT = (t - 0.35f) / 0.65f;
|
||
targetOffset = -Mathf.Lerp(_biteAmplitude, 0f, upT);
|
||
}
|
||
break;
|
||
|
||
case FishingBobberBiteType.SlowSink:
|
||
targetOffset = -Mathf.SmoothStep(0f, _biteAmplitude, t);
|
||
break;
|
||
|
||
case FishingBobberBiteType.Lift:
|
||
targetOffset = Mathf.SmoothStep(0f, _biteAmplitude, t);
|
||
break;
|
||
|
||
case FishingBobberBiteType.BlackDrift:
|
||
targetOffset = -Mathf.SmoothStep(0f, _biteAmplitude, t);
|
||
break;
|
||
}
|
||
|
||
_biteOffsetY = Mathf.SmoothDamp(
|
||
_biteOffsetY,
|
||
targetOffset,
|
||
ref _biteOffsetYVelocity,
|
||
Mathf.Max(0.0001f, biteSmoothTime),
|
||
Mathf.Infinity,
|
||
deltaTime);
|
||
|
||
if (_biteTimer >= _biteDuration &&
|
||
_activeBiteType != FishingBobberBiteType.SlowSink &&
|
||
_activeBiteType != FishingBobberBiteType.BlackDrift)
|
||
{
|
||
_activeBiteType = FishingBobberBiteType.None;
|
||
}
|
||
}
|
||
|
||
private void HandleDebugInput()
|
||
{
|
||
if (!Application.isPlaying || !enableDebugInput)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (Input.GetKeyDown(stopBiteKey))
|
||
{
|
||
StopBite();
|
||
}
|
||
|
||
if (Input.GetKeyDown(tapKey))
|
||
{
|
||
PlayTap();
|
||
}
|
||
|
||
if (Input.GetKeyDown(slowSinkKey))
|
||
{
|
||
PlaySlowSink();
|
||
}
|
||
|
||
if (Input.GetKeyDown(liftKey))
|
||
{
|
||
PlayLift();
|
||
}
|
||
|
||
if (Input.GetKeyDown(blackDriftKey))
|
||
{
|
||
PlayBlackDrift();
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 参数校验
|
||
|
||
#if UNITY_EDITOR
|
||
private void OnValidate()
|
||
{
|
||
floatHeight = Mathf.Max(0.001f, floatHeight);
|
||
ySmoothTime = Mathf.Max(0.001f, ySmoothTime);
|
||
maxYSpeed = Mathf.Max(0.01f, maxYSpeed);
|
||
yDeadZone = Mathf.Max(0f, yDeadZone);
|
||
|
||
neutralBottomWeight = Mathf.Max(0f, neutralBottomWeight);
|
||
currentBottomWeight = Mathf.Max(0f, currentBottomWeight);
|
||
minDraftDepth = Mathf.Max(0f, minDraftDepth);
|
||
maxDraftDepth = Mathf.Max(minDraftDepth, maxDraftDepth);
|
||
baseDraftDepth = Mathf.Clamp(baseDraftDepth, minDraftDepth, maxDraftDepth);
|
||
draftDepthPerWeight = Mathf.Max(0f, draftDepthPerWeight);
|
||
draftSmoothTime = Mathf.Max(0.001f, draftSmoothTime);
|
||
|
||
biteSmoothTime = Mathf.Max(0.001f, biteSmoothTime);
|
||
tapAmplitude = Mathf.Max(0f, tapAmplitude);
|
||
tapDuration = Mathf.Max(0.01f, tapDuration);
|
||
slowSinkAmplitude = Mathf.Max(0f, slowSinkAmplitude);
|
||
slowSinkDuration = Mathf.Max(0.01f, slowSinkDuration);
|
||
liftAmplitude = Mathf.Max(0f, liftAmplitude);
|
||
liftDuration = Mathf.Max(0.01f, liftDuration);
|
||
blackDriftAmplitude = Mathf.Max(0f, blackDriftAmplitude);
|
||
blackDriftDuration = Mathf.Max(0.01f, blackDriftDuration);
|
||
|
||
lyingWeightThreshold = Mathf.Max(0f, lyingWeightThreshold);
|
||
tiltedWeightThreshold = Mathf.Max(lyingWeightThreshold, tiltedWeightThreshold);
|
||
uprightWeightThreshold = Mathf.Max(tiltedWeightThreshold, uprightWeightThreshold);
|
||
uprightAngle = Mathf.Clamp(uprightAngle, 0f, 89f);
|
||
tiltedAngle = Mathf.Clamp(tiltedAngle, uprightAngle, 89f);
|
||
lyingAngle = Mathf.Clamp(lyingAngle, tiltedAngle, 89.9f);
|
||
rotationLerpSpeed = Mathf.Max(0.01f, rotationLerpSpeed);
|
||
waterAngularDamping = Mathf.Max(0f, waterAngularDamping);
|
||
}
|
||
#endif
|
||
|
||
#endregion
|
||
}
|
||
}
|