给线加入风力和空气阻力相关逻辑

This commit is contained in:
2026-02-25 00:07:57 +08:00
parent 3affe183f7
commit b41ee35cd4
11 changed files with 264 additions and 92 deletions

View File

@@ -86,7 +86,7 @@ public class SceneSettings : MonoBehaviour
private void UpdateTimeOfDay()
{
var p = GameTimer.GetGameDayProgress();
p = 0;
// p = 0;
// Debug.Log(p);
EnviroManager.instance.Time.SetTimeOfDay(p * 24f);
// if(AzureCoreSystem)

View File

@@ -51,12 +51,19 @@ namespace NBF
}
private void Update()
{
}
private void LateUpdate()
{
UpdateMove();
Fsm?.Update();
Data.EyeAngle = GameUtils.GetVerticalAngle(transform, FppLook);
}
private void OnDestroy()
{

View File

@@ -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;

View File

@@ -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()
{