using System; using System.Collections.Generic; using UnityEngine; namespace NBF { public class FishingLineNode : MonoBehaviour { public enum NodeType { Start, Float, Weight, Tail } private FishingLineSolver _solver; [Header("Node")] [SerializeField] private NodeType nodeType = NodeType.Tail; [SerializeField] public Rigidbody body; [SerializeField] private MonoBehaviour interaction; 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 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() { _solver = GetComponentInParent(); _joint = GetComponent(); EnsureFeatureCache(); } private void Start() { BindFeatures(_solver); } private void FixedUpdate() { EnsureFeatureCache(); UpdateMotionControl(Time.fixedDeltaTime); } private void OnValidate() { if (body == null) { TryGetComponent(out body); } segmentLengthToNext = Mathf.Max(0f, segmentLengthToNext); } #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(FishingLineSolver 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() { } } }