From d7028a56644ea64570071e55eb7235e3d053efb9 Mon Sep 17 00:00:00 2001
From: "Bob.Song" <605277374@qq.com>
Date: Fri, 17 Apr 2026 00:21:55 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Assets/Scenes/RopeTest.unity | 27 +++++-
.../New/View/FishingLine/FishingLineNode.cs | 35 +++++++-
.../New/View/FishingLine/FishingLineSolver.cs | 83 +++++++++++++++++--
.../FishingLine/FishingLineTestController.cs | 4 +-
4 files changed, 137 insertions(+), 12 deletions(-)
diff --git a/Assets/Scenes/RopeTest.unity b/Assets/Scenes/RopeTest.unity
index 3f97e72fc..35aef6f1e 100644
--- a/Assets/Scenes/RopeTest.unity
+++ b/Assets/Scenes/RopeTest.unity
@@ -119,6 +119,17 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
+--- !u!114 &145783537 stripped
+MonoBehaviour:
+ m_CorrespondingSourceObject: {fileID: 6741752443570310990, guid: ea6901d8aa7c41d41987d8ca92b02f6d, type: 3}
+ m_PrefabInstance: {fileID: 1672280511}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 78dc478e56ff48849761861244c93535, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineSolver
--- !u!1 &203844586
GameObject:
m_ObjectHideFlags: 0
@@ -582,7 +593,7 @@ Transform:
m_GameObject: {fileID: 1181671545}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: -21.88, y: -1, z: -16.13}
+ m_LocalPosition: {x: -21.88, y: 0, z: -16.13}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
@@ -611,7 +622,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 4162208118158024875, guid: ea6901d8aa7c41d41987d8ca92b02f6d, type: 3}
propertyPath: m_LocalPosition.y
- value: -1
+ value: 1
objectReference: {fileID: 0}
- target: {fileID: 4162208118158024875, guid: ea6901d8aa7c41d41987d8ca92b02f6d, type: 3}
propertyPath: m_LocalPosition.z
@@ -649,6 +660,14 @@ PrefabInstance:
propertyPath: anchorTransform
value:
objectReference: {fileID: 2055159199}
+ - target: {fileID: 6741752443570310990, guid: ea6901d8aa7c41d41987d8ca92b02f6d, type: 3}
+ propertyPath: breakLimitDuration
+ value: 3
+ objectReference: {fileID: 0}
+ - target: {fileID: 6741752443570310990, guid: ea6901d8aa7c41d41987d8ca92b02f6d, type: 3}
+ propertyPath: breakStretchThreshold
+ value: 0.08
+ objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects:
@@ -695,7 +714,7 @@ Transform:
m_GameObject: {fileID: 2055159198}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
- m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalPosition: {x: 0, y: 1, z: 0}
m_LocalScale: {x: 0.01, y: 0.01, z: 0.01}
m_ConstrainProportionsScale: 0
m_Children: []
@@ -818,7 +837,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 5382d66f55f6463cb469c5094b0e7a6b, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::NBF.FishingLineTestController
- solver: {fileID: 0}
+ solver: {fileID: 145783537}
initialFirstSegmentLength: 1.2
minFirstSegmentLength: 0.1
maxFirstSegmentLength: 5
diff --git a/Assets/Scripts/Fishing/New/View/FishingLine/FishingLineNode.cs b/Assets/Scripts/Fishing/New/View/FishingLine/FishingLineNode.cs
index eef56bd4d..e15820b41 100644
--- a/Assets/Scripts/Fishing/New/View/FishingLine/FishingLineNode.cs
+++ b/Assets/Scripts/Fishing/New/View/FishingLine/FishingLineNode.cs
@@ -44,7 +44,17 @@ namespace NBF
set => nodeType = value;
}
- public float Lenght => _joint != null ? _joint.linearLimit.limit : 0f;
+ public float Lenght { get; private set; }
+
+ ///
+ /// 真实实际长度
+ ///
+ public float RealLength { get; private set; }
+
+ ///
+ /// 当前逻辑链总长度超出配置总长度的部分,小于等于零时记为 0。
+ ///
+ public float StretchLength { get; private set; }
public Rigidbody Body => body;
@@ -77,6 +87,7 @@ namespace NBF
{
EnsureFeatureCache();
UpdateMotionControl(Time.fixedDeltaTime);
+ UpdateLenght();
}
private void OnValidate()
@@ -87,6 +98,28 @@ namespace NBF
}
segmentLengthToNext = Mathf.Max(0f, segmentLengthToNext);
+
+ }
+
+ private void UpdateLenght()
+ {
+ //更新长度
+ Lenght = 0;
+ RealLength = 0;
+ StretchLength = 0;
+ if (_joint)
+ {
+ Lenght = _joint.linearLimit.limit;
+ if (_joint && _joint.connectedBody)
+ {
+ RealLength = Vector3.Distance(transform.position, _joint.connectedBody.transform.position);
+ }
+ }
+
+ if (RealLength > Lenght)
+ {
+ StretchLength = RealLength - Lenght;
+ }
}
#region Line
diff --git a/Assets/Scripts/Fishing/New/View/FishingLine/FishingLineSolver.cs b/Assets/Scripts/Fishing/New/View/FishingLine/FishingLineSolver.cs
index 7818ab78b..e856b8b1e 100644
--- a/Assets/Scripts/Fishing/New/View/FishingLine/FishingLineSolver.cs
+++ b/Assets/Scripts/Fishing/New/View/FishingLine/FishingLineSolver.cs
@@ -53,7 +53,7 @@ namespace NBF
private void FixedUpdate()
{
UpdateAnchorNode();
- UpdateStretchLength();
+ UpdateBreakCountdown(Time.fixedDeltaTime);
}
#region Start Node
@@ -221,7 +221,7 @@ namespace NBF
///
[Header("Limit Detection")]
public float CurrentStretchLength { get; private set; }
-
+
[Min(0f)]
// 极限判定的长度容差,允许链路在总长或单段长度上存在少量误差。
[SerializeField]
@@ -230,7 +230,12 @@ namespace NBF
[Min(0f)]
// 达到极限后,只有当前超长值大于该阈值时,才开始进入断线候选计时。
[SerializeField]
- private float breakStretchThreshold = 0.05f;
+ private float breakStretchThreshold = 0.08f;
+
+ [Min(0f)]
+ // 断线候选状态允许持续的最大时间;超过后会发出一次断线消息。
+ [SerializeField]
+ private float breakLimitDuration = 3f;
///
/// 当鱼线达到断线条件时发出的一次性消息。
@@ -238,12 +243,24 @@ namespace NBF
///
public event Action OnLineBreakRequested;
+ ///
+ /// 当前是否处于极限状态。
+ /// 只要整链超出总长度容差,或任一逻辑段超出单段容差,即认为到达极限。
+ ///
+ public bool IsAtLimit { get; private set; }
+
///
/// 当前断线候选状态的累计时间。
/// 只有在处于极限状态,且 CurrentStretchLength 大于断线阈值时才会累加;否则重置为 0。
///
public float LimitStateTime { get; private set; }
+ ///
+ /// 当前极限断线消息是否已经发出过。
+ /// 在退出断线候选状态前只会发一次,避免重复通知。
+ ///
+ public bool HasBreakNotificationSent { get; private set; }
+
///
/// 当前拉力极限百分比。
/// 当超长值小于等于 lengthLimitTolerance 时为 0;
@@ -252,6 +269,10 @@ namespace NBF
///
public float CurrentBreakStretchPercent => EvaluateBreakStretchPercent(CurrentStretchLength);
+ ///
+ /// 当前是否正在进行断线候选计时。
+ ///
+ public bool IsBreakCountdownActive => IsAtLimit && CurrentStretchLength > breakStretchThreshold;
private float EvaluateBreakStretchPercent(float stretchLength)
{
@@ -273,9 +294,61 @@ namespace NBF
return Mathf.InverseLerp(lengthLimitTolerance, breakStretchThreshold, stretchLength) * 100f;
}
- private void UpdateStretchLength()
+ private void SetLimitState(bool isAtLimit)
{
-
+ IsAtLimit = isAtLimit;
+ }
+
+ private void UpdateBreakCountdown(float deltaTime)
+ {
+ if (logicalNodes == null || logicalNodes.Length == 0)
+ {
+ SetLimitState(false);
+ ResetLimitState();
+ return;
+ }
+
+ CurrentStretchLength = 0;
+ //计算长度
+ foreach (var node in logicalNodes)
+ {
+ CurrentStretchLength += node.StretchLength;
+ }
+
+ SetLimitState(CurrentStretchLength > lengthLimitTolerance);
+
+ if (!IsBreakCountdownActive)
+ {
+ LimitStateTime = 0f;
+ HasBreakNotificationSent = false;
+ return;
+ }
+
+ LimitStateTime += Mathf.Max(0f, deltaTime);
+ if (HasBreakNotificationSent || LimitStateTime < breakLimitDuration)
+ {
+ return;
+ }
+
+ HasBreakNotificationSent = true;
+ NotifyLineBreakRequested();
+ }
+
+ ///
+ /// 发出鱼线达到断线条件的消息。
+ /// 这里预留给外部订阅,当前不在求解器内部直接执行断线逻辑。
+ ///
+ private void NotifyLineBreakRequested()
+ {
+ OnLineBreakRequested?.Invoke(this);
+ }
+
+ private void ResetLimitState()
+ {
+ CurrentStretchLength = 0f;
+ IsAtLimit = false;
+ LimitStateTime = 0f;
+ HasBreakNotificationSent = false;
}
#endregion
diff --git a/Assets/Scripts/Fishing/New/View/FishingLine/FishingLineTestController.cs b/Assets/Scripts/Fishing/New/View/FishingLine/FishingLineTestController.cs
index 5211bc17f..5ebb9b67c 100644
--- a/Assets/Scripts/Fishing/New/View/FishingLine/FishingLineTestController.cs
+++ b/Assets/Scripts/Fishing/New/View/FishingLine/FishingLineTestController.cs
@@ -79,9 +79,9 @@ namespace NBF
solver.SetLenght(targetFirstSegmentLength);
}
- if (solver.CurrentBreakStretchPercent > 0)
+ if (solver.CurrentBreakStretchPercent > 10)
{
- // Debug.LogError(solver.CurrentBreakStretchPercent);
+ Debug.LogError($"当前极限情况,CurrentBreakStretchPercent={solver.CurrentBreakStretchPercent} CurrentStretchLength={solver.CurrentStretchLength} LimitStateTime={solver.LimitStateTime}");
}
}
}