using System; using System.Collections.Generic; using UnityEngine; namespace NBF { public class FishingLineNode : MonoBehaviour { public enum NodeType { Start, Float, Weight, Tail } [SerializeField] private FLine _solver; [Header("Node")] [SerializeField] private NodeType nodeType = NodeType.Tail; [SerializeField] public Rigidbody body; public Rope Rope; [SerializeField] private MonoBehaviour interaction; [SerializeField] private ConfigurableJoint _joint; [Header("Segment To Next Logical Node")] [Min(0f)] [SerializeField] private float segmentLengthToNext = 0.5f; [SerializeField] private int runtimeChainIndex = -1; [SerializeField] private List features = new(); [SerializeField] private List motionFeatures = new(); private bool featureCacheReady; [SerializeField] private FishingLineNodeMotionFeature activeMotionFeature; /// /// 当前正在接管节点运动的组件。 /// public FishingLineNodeMotionFeature ActiveMotionFeature => activeMotionFeature; public NodeType Type { get => nodeType; set => nodeType = value; } public float Lenght { get; private set; } /// /// 真实实际长度 /// public float RealLength { get; private set; } /// /// 当前逻辑链总长度超出配置总长度的部分,小于等于零时记为 0。 /// public float StretchLength { get; private set; } public Rigidbody Body => body; public MonoBehaviour Interaction => interaction; public ConfigurableJoint Joint => _joint; public int RuntimeChainIndex => runtimeChainIndex; public Vector3 Position => transform.position; private void Reset() { TryGetComponent(out body); } private void Awake() { if (!_solver) _solver = GetComponentInParent(); if (!_joint) _joint = GetComponent(); EnsureFeatureCache(); } private void Start() { BindFeatures(_solver); } private void FixedUpdate() { EnsureFeatureCache(); UpdateMotionControl(Time.fixedDeltaTime); UpdateLenght(); } private void OnValidate() { if (body == null) { TryGetComponent(out body); } 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 public void SetLenght(float lenght) { if (!_joint) return; if (!Mathf.Approximately(lenght, _joint.linearLimit.limit)) { _joint.linearLimit = new SoftJointLimit() { limit = lenght }; Rope.SetTargetLength(lenght - 0.1f); } } #endregion #region Feature /// /// 获取节点上的第一个指定类型功能组件。 /// public T GetFeature() where T : FishingLineNodeFeature { EnsureFeatureCache(); for (var i = 0; i < features.Count; i++) { if (features[i] is T result) { return result; } } return null; } /// /// 尝试获取节点上的指定类型功能组件。 /// public bool TryGetFeature(out T feature) where T : FishingLineNodeFeature { feature = GetFeature(); return feature != null; } /// /// 刷新并重新绑定当前节点上的功能组件。 /// public void BindFeatures(FLine solver) { EnsureFeatureCache(); foreach (var t in features) { t.Bind(this, solver); } ResolveMotionFeature(forceRefresh: true); } /// /// 通知当前节点上的所有功能组件,鱼线已重建完成。 /// public void NotifyLineBuilt() { EnsureFeatureCache(); foreach (var t in features) { t.OnLineBuilt(); } ResolveMotionFeature(forceRefresh: true); } /// /// 通知当前节点上的所有功能组件,鱼线已经达到断线条件。 /// public void NotifyLineBreakRequested() { EnsureFeatureCache(); foreach (var t in features) { t.OnLineBreakRequested(); } } private void EnsureFeatureCache() { if (!featureCacheReady) { RefreshFeatures(); } } private void RefreshFeatures() { features.Clear(); motionFeatures.Clear(); GetComponents(features); for (var i = 0; i < features.Count; i++) { if (features[i] is FishingLineNodeMotionFeature motionFeature) { motionFeatures.Add(motionFeature); } } activeMotionFeature = null; featureCacheReady = true; } private void UpdateMotionControl(float deltaTime) { var motionFeature = ResolveMotionFeature(forceRefresh: false); if (motionFeature == null) { return; } motionFeature.TickMotion(deltaTime); } private FishingLineNodeMotionFeature ResolveMotionFeature(bool forceRefresh) { EnsureFeatureCache(); var bestMotionFeature = default(FishingLineNodeMotionFeature); var bestPriority = int.MinValue; foreach (var motionFeature in motionFeatures) { var r = !motionFeature.IsSupportedNode(this); var n = !motionFeature.CanControl(); if (motionFeature == null || !motionFeature.IsSupportedNode(this) || !motionFeature.CanControl()) { continue; } if (bestMotionFeature != null && motionFeature.Priority <= bestPriority) { continue; } bestMotionFeature = motionFeature; bestPriority = motionFeature.Priority; } if (!forceRefresh && ReferenceEquals(activeMotionFeature, bestMotionFeature)) { return activeMotionFeature; } if (activeMotionFeature != null && !ReferenceEquals(activeMotionFeature, bestMotionFeature)) { activeMotionFeature.OnMotionDeactivated(); } activeMotionFeature = bestMotionFeature; if (activeMotionFeature != null) { activeMotionFeature.OnMotionActivated(); } return activeMotionFeature; } #endregion private void OnDrawGizmos() { } } }