From 3b587e6c4f815c50f356be5925c6985eaa9318bc Mon Sep 17 00:00:00 2001
From: "Bob.Song" <605277374@qq.com>
Date: Fri, 8 May 2026 23:26:44 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8F=90=E4=BA=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Scripts/Fishing/Item/FishingLine/FLine.cs | 474 ++----------------
.../Item/FishingLine/FLineLogicNode.cs | 42 +-
.../Fishing/Item/FishingLine/FLineTest.cs | 26 +-
.../Player/States/PlayerStageViewFight.cs | 17 +-
4 files changed, 69 insertions(+), 490 deletions(-)
diff --git a/Assets/Scripts/Fishing/Item/FishingLine/FLine.cs b/Assets/Scripts/Fishing/Item/FishingLine/FLine.cs
index 6cc60daf5..80aac7453 100644
--- a/Assets/Scripts/Fishing/Item/FishingLine/FLine.cs
+++ b/Assets/Scripts/Fishing/Item/FishingLine/FLine.cs
@@ -16,15 +16,6 @@ namespace NBF
SpinningFloat,
}
- ///
- /// 线模式
- ///
- public enum LineMode
- {
- Joint,
- Constraint
- }
-
public class FLine : FGearBase
{
public LineType LineType;
@@ -41,78 +32,17 @@ namespace NBF
[SerializeField] private bool showDebugInfo = true;
[Header("动态间距设置")] [SerializeField] private float defaultTransitionSpeed = 2f; // 默认长度变化速度(单位/秒)
- private LineMode _lineMode = LineMode.Joint;
- // [SerializeField] private bool isLureConnect;
- //
- // [SerializeField] private RodLine rodLine;
- //
- // ///
- // /// 主线
- // ///
- // [SerializeField] private Rope fishingRope;
- //
- // ///
- // /// 浮漂和鱼钩线
- // ///
- // [SerializeField] private Rope bobberRope;
-
-
- // public LureController Lure;
- // public BobberController Bobber;
- //
- // public JointPinchController PinchController;
-
- private readonly List _constraints = new List();
-
public FLineLogicNode StartNode { get; private set; }
public FLineLogicNode BobberNode => GetNode(FLineLogicNodeType.Bobber);
public FLineLogicNode EndNode { get; private set; }
- public LineMode LineMode => _lineMode;
+
+ private bool _isFixed = false;
+ // public LineMode LineMode => _lineMode;
public float LinelenghtDiferent;
- [System.Serializable]
- public class ConnectionConstraint
- {
- public FLineLogicNodeType NodeType;
- public Rigidbody bodyA;
- public Rigidbody bodyB;
- public float maxDistance;
- public float minDistance;
- public float currentDistance;
- public Vector3 direction;
-
- // 动态目标距离(用于平滑过渡)
- public float targetMaxDistance;
- public bool hasPendingTransition;
- public bool hasPendingMaxTransition;
- public float maxTransitionSpeed;
-
- public ConnectionConstraint(Rigidbody a, Rigidbody b, float maxDist, float minDist = 0f)
- {
- bodyA = a;
- bodyB = b;
- maxDistance = maxDist;
- minDistance = minDist;
- targetMaxDistance = maxDist;
- hasPendingTransition = false;
- hasPendingMaxTransition = false;
- maxTransitionSpeed = 0f;
- }
-
- public void UpdateCurrentState()
- {
- if (bodyA && bodyB)
- {
- Vector3 delta = bodyB.position - bodyA.position;
- currentDistance = delta.magnitude;
- direction = currentDistance > 0.0001f ? delta.normalized : Vector3.right;
- }
- }
- }
-
protected override void OnInit()
{
if (anchorTransform == null)
@@ -123,10 +53,8 @@ namespace NBF
}
}
-
private void Start()
{
- BuildConstraints();
StartNode = GetNode(FLineLogicNodeType.Start);
EndNode = GetNode(FLineLogicNodeType.End);
}
@@ -142,17 +70,6 @@ namespace NBF
private void FixedUpdate()
{
UpdateAnchorNode();
- FixedUpdateConstraints();
- }
-
- public void ChangeMode(LineMode mode)
- {
- _lineMode = mode;
-
- foreach (var fLineLogicNode in lineNodes)
- {
- fLineLogicNode.ChangeMode(mode);
- }
}
public List GetLineNodes()
@@ -165,6 +82,35 @@ namespace NBF
// Log.Info($"当前线情况 TotalLength={TotalLength} CurrentStretchLength={CurrentStretchLength}");
}
+
+ public void SetFixed(bool isFixed)
+ {
+ _isFixed = isFixed;
+ var totalLenght = 0f;
+ foreach (var fLineLogicNode in lineNodes)
+ {
+ totalLenght += fLineLogicNode.Lenght;
+ }
+
+ // var startNode = StartNode;
+ if (isFixed)
+ {
+ // EndNode.Joint.connectedBody = StartNode.Rigidbody;
+ BobberNode.gameObject.SetActive(false);
+ BobberNode.Rope.gameObject.SetActive(false);
+ EndNode.SetConnectedBody(StartNode.Rigidbody);
+ EndNode.SetLenght(totalLenght);
+ }
+ else
+ {
+ BobberNode.gameObject.SetActive(true);
+ BobberNode.Rope.gameObject.SetActive(true);
+ EndNode.SetConnectedBody(BobberNode.Rigidbody);
+ EndNode.SetLenght(Rod.FloatLength);
+ }
+ // var totalLenght = lineNodes
+ }
+
#region 连接点
private void UpdateAnchorNode()
@@ -207,366 +153,12 @@ namespace NBF
var node = GetNode(type);
if (node != null)
{
- if (_lineMode == LineMode.Joint)
- {
- node.SetLenght(lenght);
- }
- else
- {
- SetSegmentMaxLength(lenght, type);
- }
+ node.SetLenght(lenght);
}
}
#endregion
- #region 脚本约束
-
- private void FixedUpdateConstraints()
- {
- if (_lineMode != LineMode.Constraint) return;
- if (!enabled || lineNodes.Count < 2) return;
-
- // 更新动态过渡
- UpdateTransitions();
-
- for (int iteration = 0; iteration < constraintIterations; iteration++)
- {
- ApplyDistanceConstraints();
- }
-
- ApplyDamping();
- }
-
- private void BuildConstraints()
- {
- _constraints.Clear();
- if (lineNodes.Count < 2) return;
-
- // 创建约束
- for (int i = 0; i < lineNodes.Count - 1; i++)
- {
- FLineLogicNode currentNode = lineNodes[i];
- FLineLogicNode nextNode = lineNodes[i + 1];
- Rigidbody bodyA = currentNode ? currentNode.Rigidbody : null;
- Rigidbody bodyB = nextNode ? nextNode.Rigidbody : null;
-
- if (bodyA != null && bodyB != null)
- {
- var constraint = new ConnectionConstraint(
- bodyA,
- bodyB,
- nextNode.Lenght
- );
- constraint.NodeType = nextNode.NodeType;
- _constraints.Add(constraint);
- }
- }
- }
-
- private void ApplyDistanceConstraints()
- {
- for (int i = 0; i < _constraints.Count; i++)
- {
- var constraint = _constraints[i];
- if (!constraint.bodyA || !constraint.bodyB) continue;
-
- constraint.UpdateCurrentState();
-
- float currentDist = constraint.currentDistance;
- float maxDist = constraint.maxDistance;
- float minDist = constraint.minDistance;
-
- float error = 0f;
- bool needCorrection = false;
-
- if (currentDist > maxDist)
- {
- error = currentDist - maxDist;
- needCorrection = true;
- }
-
- if (!needCorrection || Mathf.Abs(error) < 0.0001f) continue;
-
- float invMassA = constraint.bodyA.isKinematic ? 0f : 1f / constraint.bodyA.mass;
- float invMassB = constraint.bodyB.isKinematic ? 0f : 1f / constraint.bodyB.mass;
- float totalInvMass = invMassA + invMassB;
-
- if (totalInvMass < 0.0001f) continue;
-
- float weightA = useMassWeighting ? (invMassA / totalInvMass) : 0.5f;
- float weightB = useMassWeighting ? (invMassB / totalInvMass) : 0.5f;
-
- Vector3 correction = constraint.direction * error;
- Vector3 positionCorrectionA = correction * weightA;
- Vector3 positionCorrectionB = -correction * weightB;
-
- constraint.bodyA.position += positionCorrectionA;
- constraint.bodyB.position += positionCorrectionB;
-
- Vector3 velocityCorrectionA = positionCorrectionA / Time.fixedDeltaTime;
- Vector3 velocityCorrectionB = positionCorrectionB / Time.fixedDeltaTime;
-
- constraint.bodyA.AddForce(velocityCorrectionA * constraint.bodyA.mass, ForceMode.Impulse);
- constraint.bodyB.AddForce(velocityCorrectionB * constraint.bodyB.mass, ForceMode.Impulse);
- }
- }
-
- private void ApplyDamping()
- {
- for (int i = 0; i < _constraints.Count; i++)
- {
- var constraint = _constraints[i];
- if (!constraint.bodyA || !constraint.bodyB) continue;
-
- if (constraint.currentDistance <= constraint.maxDistance) continue;
-
- Vector3 relativeVelocity = constraint.bodyB.linearVelocity - constraint.bodyA.linearVelocity;
- float velocityInConstraintDir = Vector3.Dot(relativeVelocity, constraint.direction);
-
- if (velocityInConstraintDir > 0)
- {
- float dampingForce = -velocityInConstraintDir * dampingCoefficient;
- Vector3 dampingImpulse = constraint.direction * dampingForce * Time.fixedDeltaTime;
-
- constraint.bodyA.AddForce(-dampingImpulse * constraint.bodyA.mass, ForceMode.Impulse);
- constraint.bodyB.AddForce(dampingImpulse * constraint.bodyB.mass, ForceMode.Impulse);
- }
- }
- }
-
- ///
- /// 按速度过渡某段的最大距离
- ///
- private void SetSegmentMaxLength(float targetLength, FLineLogicNodeType type = FLineLogicNodeType.Bobber,
- float transitionSpeed = 2f)
- {
- var constraint = _constraints.Find(t => t.NodeType == type);
- if (constraint == null) return;
-
- targetLength = Mathf.Max(0.01f, targetLength);
- float speed = Mathf.Max(0.01f, transitionSpeed > 0 ? transitionSpeed : defaultTransitionSpeed);
-
- constraint.targetMaxDistance = targetLength;
- constraint.maxTransitionSpeed = speed;
- constraint.hasPendingMaxTransition = Mathf.Abs(constraint.maxDistance - targetLength) >= 0.0001f;
- constraint.hasPendingTransition = constraint.hasPendingMaxTransition;
- }
-
-
- ///
- /// 更新所有活跃的过渡
- ///
- private void UpdateTransitions()
- {
- float deltaTime = Time.fixedDeltaTime;
-
- for (int i = 0; i < _constraints.Count; i++)
- {
- var constraint = _constraints[i];
-
- if (constraint.hasPendingMaxTransition)
- {
- float nextMaxDistance = Mathf.MoveTowards(
- constraint.maxDistance,
- constraint.targetMaxDistance,
- constraint.maxTransitionSpeed * deltaTime
- );
- constraint.maxDistance = nextMaxDistance;
- var node = GetNode(constraint.NodeType);
- // SyncSegmentMaxLength(i, nextMaxDistance);
- node.SetLenght(nextMaxDistance);
-
- if (Mathf.Abs(nextMaxDistance - constraint.targetMaxDistance) < 0.0001f)
- {
- constraint.maxDistance = constraint.targetMaxDistance;
- constraint.hasPendingMaxTransition = false;
- // SyncSegmentMaxLength(i, constraint.targetMaxDistance);
- node.SetLenght(constraint.targetMaxDistance);
- }
- }
-
- constraint.hasPendingTransition = constraint.hasPendingMaxTransition;
- }
- }
-
-
- ///
- /// 获取某个段是否正在进行过渡
- ///
- public bool IsSegmentTransitioning(int segmentIndex)
- {
- if (segmentIndex >= 0 && segmentIndex < _constraints.Count)
- {
- return _constraints[segmentIndex].hasPendingTransition;
- }
-
- return false;
- }
-
- #endregion
-
- // #region 极限判定
- //
- // ///
- // /// 当前逻辑链总长度超出配置总长度的部分,小于等于零时记为 0。
- // ///
- // [Header("Limit Detection")]
- // public float CurrentStretchLength { get; private set; }
- //
- // ///
- // /// 总长度
- // ///
- // public float TotalLength { get; private set; }
- //
- // [Min(0f)]
- // // 极限判定的长度容差,允许链路在总长或单段长度上存在少量误差。
- // [SerializeField]
- // private float lengthLimitTolerance = 0.01f;
- //
- // [Min(0f)]
- // // 达到极限后,只有当前超长值大于该阈值时,才开始进入断线候选计时。
- // [SerializeField]
- // private float breakStretchThreshold = 0.3f;
- //
- // [Min(0f)]
- // // UI 百分比开始起算的最小超长值;低于或等于该值时统一按 0% 处理。
- // [SerializeField]
- // private float breakStretchPercentMinThreshold = 0.06f;
- //
- // [Min(0f)]
- // // 断线候选状态允许持续的最大时间;超过后会发出一次断线消息。
- // [SerializeField]
- // private float breakLimitDuration = 3f;
- //
- // ///
- // /// 当鱼线达到断线条件时发出的一次性消息。
- // /// 外部可订阅该事件,在回调中执行切线、播放表现或状态切换。
- // ///
- // public event Action OnLineBreakRequested;
- //
- // ///
- // /// 当前是否处于极限状态。
- // /// 只要整链超出总长度容差,或任一逻辑段超出单段容差,即认为到达极限。
- // ///
- // public bool IsAtLimit { get; private set; }
- //
- // ///
- // /// 当前断线候选状态的累计时间。
- // /// 只有在处于极限状态,且 CurrentStretchLength 大于断线阈值时才会累加;否则重置为 0。
- // ///
- // public float LimitStateTime { get; private set; }
- //
- // ///
- // /// 当前极限断线消息是否已经发出过。
- // /// 在退出断线候选状态前只会发一次,避免重复通知。
- // ///
- // public bool HasBreakNotificationSent { get; private set; }
- //
- // ///
- // /// 当前拉力极限百分比。
- // /// 当超长值小于等于 breakStretchPercentMinThreshold 时为 0;
- // /// 当超长值大于等于 breakStretchThreshold 时为 100;
- // /// 中间区间按线性比例映射,供 UI 显示使用。
- // ///
- // public float CurrentBreakStretchPercent => EvaluateBreakStretchPercent(CurrentStretchLength);
- //
- // ///
- // /// 当前是否正在进行断线候选计时。
- // ///
- // public bool IsBreakCountdownActive => IsAtLimit && CurrentStretchLength > breakStretchThreshold;
- //
- // private float EvaluateBreakStretchPercent(float stretchLength)
- // {
- // var percentMinThreshold = Mathf.Max(lengthLimitTolerance, breakStretchPercentMinThreshold);
- //
- // if (stretchLength <= percentMinThreshold)
- // {
- // return 0f;
- // }
- //
- // if (stretchLength >= breakStretchThreshold)
- // {
- // return 100f;
- // }
- //
- // if (breakStretchThreshold <= percentMinThreshold)
- // {
- // return 100f;
- // }
- //
- // return Mathf.InverseLerp(percentMinThreshold, breakStretchThreshold, stretchLength) * 100f;
- // }
- //
- // private void SetLimitState(bool isAtLimit)
- // {
- // IsAtLimit = isAtLimit;
- // }
- //
- // private void UpdateBreakCountdown(float deltaTime)
- // {
- // if (lineNodes.Count < 2)
- // {
- // SetLimitState(false);
- // ResetLimitState();
- // return;
- // }
- //
- //
- // var startNode = lineNodes[0];
- // var endNode = lineNodes[^1];
- // TotalLength = 0;
- // foreach (var node in lineNodes)
- // {
- // TotalLength += node.Lenght;
- // }
- //
- // var realLen = Vector3.Distance(startNode.transform.position, endNode.transform.position);
- // CurrentStretchLength = realLen - TotalLength;
- // if (CurrentStretchLength < 0f)
- // {
- // CurrentStretchLength = 0f;
- // }
- //
- // SetLimitState(CurrentStretchLength > lengthLimitTolerance);
- // if (LineMode != LineMode.Constraint) return;
- //
- // 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
-
#region Tension
private float GetLineDistance()
diff --git a/Assets/Scripts/Fishing/Item/FishingLine/FLineLogicNode.cs b/Assets/Scripts/Fishing/Item/FishingLine/FLineLogicNode.cs
index e0f1c1044..ffbe796a2 100644
--- a/Assets/Scripts/Fishing/Item/FishingLine/FLineLogicNode.cs
+++ b/Assets/Scripts/Fishing/Item/FishingLine/FLineLogicNode.cs
@@ -54,48 +54,20 @@ namespace NBF
}
}
- ///
- /// 切换约束模式
- ///
- ///
- public void ChangeMode(LineMode mode)
+ void FixedUpdate()
{
- if (mode == LineMode.Joint)
+ if (rope)
{
- if (_joint)
- {
- StartCoroutine(ReconnectedBody());
- }
- }
- else if (mode == LineMode.Constraint)
- {
- if (_joint) _joint.connectedBody = null;
- if (NodeType == FLineLogicNodeType.End)
- {
- Rigidbody.isKinematic = true;
- }
+ if(rope.startAnchor != _joint.connectedBody){}
+ rope.startAnchor = _joint.connectedBody;
}
}
- private IEnumerator ReconnectedBody()
+ public void SetConnectedBody(Rigidbody rig)
{
- _joint.connectedBody = preRigidbody;
- yield return 1;
- Rigidbody.position = preRigidbody.position;
- preRigidbody.isKinematic = true;
- preRigidbody.linearVelocity = Vector3.zero;
- preRigidbody.angularVelocity = Vector3.zero;
- if (NodeType != FLineLogicNodeType.Start)
+ if (_joint)
{
- preRigidbody.isKinematic = false;
- }
-
- yield return 1;
- preRigidbody.linearVelocity = Vector3.zero;
- preRigidbody.angularVelocity = Vector3.zero;
- if (NodeType == FLineLogicNodeType.End)
- {
- Rigidbody.isKinematic = false;
+ _joint.connectedBody = rig;
}
}
}
diff --git a/Assets/Scripts/Fishing/Item/FishingLine/FLineTest.cs b/Assets/Scripts/Fishing/Item/FishingLine/FLineTest.cs
index 12a15e182..f64531761 100644
--- a/Assets/Scripts/Fishing/Item/FishingLine/FLineTest.cs
+++ b/Assets/Scripts/Fishing/Item/FishingLine/FLineTest.cs
@@ -147,8 +147,8 @@ namespace NBF
if (Input.GetKeyDown(fixedKey))
{
- if (line.LineMode == LineMode.Joint) line.ChangeMode(LineMode.Constraint);
- else line.ChangeMode(LineMode.Joint);
+ // if (line.LineMode == LineMode.Joint) line.ChangeMode(LineMode.Constraint);
+ // else line.ChangeMode(LineMode.Joint);
}
if (Input.GetKeyDown(debugKey))
@@ -249,18 +249,18 @@ namespace NBF
GUI.color = Color.white;
- bool anyTransitioning = false;
- for (int i = 0; i < GetSegmentCount(); i++)
- {
- if (line.IsSegmentTransitioning(i))
- {
- anyTransitioning = true;
- break;
- }
- }
+ // bool anyTransitioning = false;
+ // for (int i = 0; i < GetSegmentCount(); i++)
+ // {
+ // if (line.IsSegmentTransitioning(i))
+ // {
+ // anyTransitioning = true;
+ // break;
+ // }
+ // }
- if (anyTransitioning)
- GUILayout.Label("状态: 过渡中...");
+ // if (anyTransitioning)
+ // GUILayout.Label("状态: 过渡中...");
GUILayout.EndArea();
}
diff --git a/Assets/Scripts/Fishing/Player/States/PlayerStageViewFight.cs b/Assets/Scripts/Fishing/Player/States/PlayerStageViewFight.cs
index 97ecffc37..11a752a42 100644
--- a/Assets/Scripts/Fishing/Player/States/PlayerStageViewFight.cs
+++ b/Assets/Scripts/Fishing/Player/States/PlayerStageViewFight.cs
@@ -1,4 +1,6 @@
-namespace NBF
+using UnityEngine;
+
+namespace NBF
{
public class PlayerStageViewFight : PlayerStageViewBase
{
@@ -8,6 +10,7 @@
if (Player.HandItem is FRod rod)
{
rod.Line.EndNode.Rigidbody.isKinematic = true;
+ rod.Line.SetFixed(true);
// rod.Line.ChangeMode(LineMode.Constraint);
}
}
@@ -17,10 +20,13 @@
if (Player.HandItem is FRod rod)
{
rod.Line.EndNode.Rigidbody.isKinematic = false;
+ rod.Line.SetFixed(false);
// rod.Line.ChangeMode(LineMode.Joint);
}
}
+ private bool _test;
+
protected override void OnUpdate()
{
PlayerState ret = PlayerState.None;
@@ -31,6 +37,15 @@
// ret = CheckTackFish();
}
+ if (Input.GetKeyDown(KeyCode.F))
+ {
+ if (Player.HandItem is FRod rod)
+ {
+ rod.Line.SetFixed(_test);
+ _test = !_test;
+ }
+ }
+
if (ret != PlayerState.None)
{
Player.ChangeState(ret);