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