给线加入风力和空气阻力相关逻辑
This commit is contained in:
@@ -51,12 +51,19 @@ namespace NBF
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
UpdateMove();
|
||||
Fsm?.Update();
|
||||
|
||||
Data.EyeAngle = GameUtils.GetVerticalAngle(transform, FppLook);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace NBF
|
||||
|
||||
// Debug.Log($"addNum={addNum}");
|
||||
Player.ModelAsset.PlayerAnimator.FishingUp += addNum;
|
||||
Debug.LogError($"ishingFinal={Player.ModelAsset.PlayerAnimator.FishingUp}");
|
||||
// Debug.LogError($"ishingFinal={Player.ModelAsset.PlayerAnimator.FishingUp}");
|
||||
if (Player.ModelAsset.PlayerAnimator.FishingUp >= 1)
|
||||
{
|
||||
Player.ModelAsset.PlayerAnimator.FishingUp = 1;
|
||||
|
||||
@@ -41,11 +41,10 @@ public class Rope : MonoBehaviour
|
||||
[Header("Head Segment Clamp")] [Tooltip("第一段(起点->第1节点)允许的最小长度,避免收线时第一段被压到0导致数值炸")] [SerializeField, Min(0.0001f)]
|
||||
private float headMinLen = 0.01f;
|
||||
|
||||
|
||||
[Header("Collision Filter")]
|
||||
[SerializeField, Tooltip("只对这些Layer进行物理检测(Raycast/SphereCast等)。不在这里的层完全不检测。")]
|
||||
|
||||
[Header("Collision Filter")] [SerializeField, Tooltip("只对这些Layer进行物理检测(Raycast/SphereCast等)。不在这里的层完全不检测。")]
|
||||
private LayerMask collisionMask = ~0;
|
||||
|
||||
|
||||
[Header("Simple Ground/Water Constraint (Cheap)")] [SerializeField]
|
||||
private bool constrainToGround = true;
|
||||
|
||||
@@ -61,6 +60,32 @@ public class Rope : MonoBehaviour
|
||||
[Header("Render (High Resolution)")] [SerializeField, Min(1), Tooltip("每段物理线段插值加密的数量(越大越顺,越耗)")]
|
||||
private int renderSubdivisions = 6;
|
||||
|
||||
|
||||
[Header("Air / Wind (For Fishing Line Feel)")]
|
||||
[SerializeField, Range(0f, 5f), Tooltip("空气线性阻力(越大越不飘,空中更自然)")]
|
||||
private float airDrag = 0.9f;
|
||||
|
||||
[SerializeField, Range(0f, 2f), Tooltip("横向额外阻力(减少左右飘得太夸张)")]
|
||||
private float airDragXZ = 0.6f;
|
||||
|
||||
[SerializeField, Tooltip("风方向(世界空间)")]
|
||||
private Vector3 windDir = new Vector3(1f, 0f, 0f);
|
||||
|
||||
[SerializeField, Range(0f, 10f), Tooltip("基础风强度(m/s 级别的感觉)")]
|
||||
private float windStrength = 0.3f;
|
||||
|
||||
[SerializeField, Range(0f, 2f), Tooltip("阵风幅度(0=无阵风)")]
|
||||
private float windGust = 0.25f;
|
||||
|
||||
[SerializeField, Range(0.1f, 5f), Tooltip("阵风频率")]
|
||||
private float windFreq = 1.2f;
|
||||
|
||||
[Header("Bending (Smooth Curve)")]
|
||||
[SerializeField, Range(0f, 1f), Tooltip("抗折/弯曲刚度(0=完全不抗折,0.1~0.3 比较像鱼线)")]
|
||||
private float bendStiffness = 0.18f;
|
||||
|
||||
|
||||
|
||||
[SerializeField, Tooltip("是否使用 Catmull-Rom 平滑(推荐开启)")]
|
||||
private bool smooth = true;
|
||||
|
||||
@@ -98,7 +123,7 @@ public class Rope : MonoBehaviour
|
||||
AllocateAndInitNodes();
|
||||
RebuildRenderBufferIfNeeded();
|
||||
}
|
||||
|
||||
|
||||
private FRod _rod;
|
||||
|
||||
public void Init(FRod rod)
|
||||
@@ -121,7 +146,7 @@ public class Rope : MonoBehaviour
|
||||
maxPhysicsNodes = Mathf.Max(maxPhysicsNodes, minPhysicsNodes);
|
||||
|
||||
headMinLen = Mathf.Max(headMinLen, 0.0001f);
|
||||
|
||||
|
||||
// 如果你希望只用一个mask控制,避免 groundMask 忘了配
|
||||
if (groundMask == ~0)
|
||||
groundMask = collisionMask;
|
||||
@@ -137,15 +162,6 @@ public class Rope : MonoBehaviour
|
||||
|
||||
private void AllocateAndInitNodes()
|
||||
{
|
||||
// 若锚点存在:最小长度就是两锚点直线距离 + minSlack(防抖)
|
||||
// if (startAnchor && endAnchor)
|
||||
// {
|
||||
// float minFeasible = Vector3.Distance(startAnchor.position, endAnchor.position) + minSlack;
|
||||
// minFeasible -= 0.2f;
|
||||
// currentLength = Mathf.Max(currentLength, minFeasible);
|
||||
// targetLength = Mathf.Max(targetLength, minFeasible);
|
||||
// }
|
||||
|
||||
physicsNodes = Mathf.Clamp(ComputeDesiredNodes(currentLength), 2, maxPhysicsNodes);
|
||||
pCurr = new Vector3[physicsNodes];
|
||||
pPrev = new Vector3[physicsNodes];
|
||||
@@ -180,7 +196,7 @@ public class Rope : MonoBehaviour
|
||||
{
|
||||
targetLength = Mathf.Max(0f, lengthMeters);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public float GetCurrentLength() => currentLength;
|
||||
public float GetTargetLength() => targetLength;
|
||||
@@ -195,8 +211,8 @@ public class Rope : MonoBehaviour
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
private void FixedUpdate2()
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (!startAnchor || !endAnchor)
|
||||
return;
|
||||
@@ -212,6 +228,7 @@ public class Rope : MonoBehaviour
|
||||
for (int it = 0; it < iterations; it++)
|
||||
{
|
||||
SolveDistanceConstraints_HeadOnly();
|
||||
SolveBendConstraint();
|
||||
LockAnchorsHard();
|
||||
}
|
||||
|
||||
@@ -221,10 +238,19 @@ public class Rope : MonoBehaviour
|
||||
LockAnchorsHard();
|
||||
}
|
||||
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (!startAnchor || !endAnchor || pCurr == null || physicsNodes < 2) return;
|
||||
|
||||
int last = physicsNodes - 1;
|
||||
Vector3 s = startAnchor.transform.position;
|
||||
Vector3 e = endAnchor.transform.position;
|
||||
|
||||
pCurr[0] = s; pPrev[0] = s; // ✅ 关键:同步 pPrev
|
||||
pCurr[last] = e; pPrev[last] = e; // ✅ 关键:同步 pPrev
|
||||
|
||||
DrawHighResLine();
|
||||
FixedUpdate2();
|
||||
}
|
||||
|
||||
private void UpdateLengthSmooth()
|
||||
@@ -348,18 +374,69 @@ public class Rope : MonoBehaviour
|
||||
private void Simulate()
|
||||
{
|
||||
float dt = Time.fixedDeltaTime;
|
||||
float invDt = 1f / Mathf.Max(dt, 1e-6f);
|
||||
|
||||
// 风方向归一化(避免填了0向量导致NaN)
|
||||
Vector3 wDir = windDir;
|
||||
if (wDir.sqrMagnitude < 1e-6f) wDir = Vector3.right;
|
||||
wDir.Normalize();
|
||||
|
||||
for (int i = 0; i < physicsNodes; i++)
|
||||
{
|
||||
Vector3 v = (pCurr[i] - pPrev[i]) * velocityDampen;
|
||||
pPrev[i] = pCurr[i];
|
||||
// Verlet 速度(由当前位置和上一帧位置推出来)
|
||||
Vector3 vel = (pCurr[i] - pPrev[i]) * invDt;
|
||||
|
||||
pCurr[i] += v;
|
||||
pCurr[i] += gravity * dt;
|
||||
// 先做“惯性推进”
|
||||
Vector3 next = pCurr[i] + (pCurr[i] - pPrev[i]) * velocityDampen;
|
||||
|
||||
// 加速度 = 重力 + 空气阻力 + 风(相对速度)
|
||||
Vector3 acc = gravity;
|
||||
|
||||
// --- 空气阻力(与速度成正比)---
|
||||
// drag = -vel * airDrag,并且横向更强一点
|
||||
Vector3 drag = -vel * airDrag;
|
||||
drag.x *= (1f + airDragXZ);
|
||||
drag.z *= (1f + airDragXZ);
|
||||
acc += drag;
|
||||
|
||||
// --- 风(让线在空中不那么“只会垂直掉”)---
|
||||
if (i != 0 && i != physicsNodes - 1 && windStrength > 0f)
|
||||
{
|
||||
float t = Time.time;
|
||||
float gust = 1f + Mathf.Sin(t * windFreq + i * 0.35f) * windGust;
|
||||
|
||||
// windVel:风希望空气把线速度拉向这个“风速”
|
||||
Vector3 windVel = wDir * (windStrength * gust);
|
||||
|
||||
// 相对风:让加速度朝 (windVel - vel) 方向
|
||||
// 系数越大,越“被风带着走”
|
||||
acc += (windVel - vel) * 0.5f;
|
||||
}
|
||||
|
||||
// Verlet:位置 += acc * dt^2
|
||||
pPrev[i] = pCurr[i];
|
||||
pCurr[i] = next + acc * (dt * dt);
|
||||
}
|
||||
|
||||
// 物理步末尾硬锁端点
|
||||
LockAnchorsHard();
|
||||
}
|
||||
|
||||
// private void Simulate()
|
||||
// {
|
||||
// float dt = Time.fixedDeltaTime;
|
||||
//
|
||||
// for (int i = 0; i < physicsNodes; i++)
|
||||
// {
|
||||
// Vector3 v = (pCurr[i] - pPrev[i]) * velocityDampen;
|
||||
// pPrev[i] = pCurr[i];
|
||||
//
|
||||
// pCurr[i] += v;
|
||||
// pCurr[i] += gravity * dt;
|
||||
// }
|
||||
//
|
||||
// LockAnchorsHard();
|
||||
// }
|
||||
|
||||
private void LockAnchorsHard()
|
||||
{
|
||||
@@ -367,7 +444,7 @@ public class Rope : MonoBehaviour
|
||||
float dt = Time.fixedDeltaTime;
|
||||
Vector3 s = startAnchor.position;
|
||||
Vector3 e = endAnchor.position;
|
||||
|
||||
|
||||
pCurr[0] = s;
|
||||
pPrev[0] = s - startAnchor.linearVelocity * dt;
|
||||
|
||||
@@ -399,6 +476,35 @@ public class Rope : MonoBehaviour
|
||||
pCurr[i + 1] -= corr * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
private void SolveBendConstraint()
|
||||
{
|
||||
if (bendStiffness <= 0f) return;
|
||||
if (physicsNodes < 3) return;
|
||||
|
||||
// bendStiffness 在迭代里用太大很容易爆,先做一个安全钳制
|
||||
float kBase = Mathf.Clamp01(bendStiffness);
|
||||
|
||||
for (int i = 1; i < physicsNodes - 1; i++)
|
||||
{
|
||||
// 端点不要动(你本来就没动,这里保持)
|
||||
if (i == 0 || i == physicsNodes - 1) continue;
|
||||
|
||||
Vector3 mid = (pCurr[i - 1] + pCurr[i + 1]) * 0.5f;
|
||||
|
||||
float k = kBase;
|
||||
if (i <= 2) k *= 1.25f; // 靠近竿尖稍微更“直”一点
|
||||
|
||||
Vector3 old = pCurr[i];
|
||||
Vector3 newPos = Vector3.Lerp(old, mid, k);
|
||||
|
||||
Vector3 delta = newPos - old;
|
||||
|
||||
// ✅ 关键:同样把 pPrev 挪过去,避免“凭空制造速度”
|
||||
pCurr[i] = newPos;
|
||||
pPrev[i] += delta;
|
||||
}
|
||||
}
|
||||
|
||||
private void ConstrainToGroundAndWater()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user