Files
ichni_Creator_Studio/Assets/Scripts/Editor Tools/NodeScript/NodeObject.cs
2026-05-23 21:05:16 +08:00

136 lines
4.7 KiB
C#

using System;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace Ichni.NodeScript
{
public class NodeObject : MonoBehaviour, IDragHandler, IPointerClickHandler
{
public TMP_Text TitleText;
public NodeBase nodeBase;
public Image statusImage;
public Transform inputsRoot;
public Transform outputsRoot;
public Transform middleRoot;
public GameObject connectorSlotPrefabI;
public GameObject connectorSlotPrefabO;
public GameObject dropdownPrefab;
public GameObject inputPrefab;
bool _selected;
public bool Selected
{
get => _selected;
set
{
_selected = value;
if (_bg == null) _bg = GetComponent<Image>();
if (_bg != null) _bg.color = value ? new Color(0.3f, 0.5f, 0.9f, 0.4f) : new Color(0.15f, 0.15f, 0.15f, 0.3f);
}
}
Image _bg;
public void Init()
{
if (nodeBase == null) return;
TitleText.text = nodeBase.NodeName;
nodeBase.nodeObject = this;
_bg = GetComponent<Image>();
if (_bg == null) { _bg = gameObject.AddComponent<Image>(); _bg.color = new Color(0.15f, 0.15f, 0.15f, 0.3f); }
nodeBase.InitConnectors();
BuildConnectors();
nodeBase.BuildUI(new NodeUIBuilder(middleRoot, dropdownPrefab, inputPrefab));
NodeManager.Instance?.ComputeLValues();
UpdateLDisplay();
}
public void UpdateLDisplay()
{
if (TitleText != null && nodeBase != null)
TitleText.text = $"{nodeBase.NodeName} (L:{nodeBase.L})";
}
public void UpdateStatusDisplay()
{
if (statusImage == null || nodeBase == null) return;
statusImage.color = nodeBase.Status switch
{
NodeStatus.Ready => new Color(0.3f, 0.3f, 0.3f, 0.8f),
NodeStatus.Hang => new Color(0.8f, 0.6f, 0.1f, 0.9f),
NodeStatus.Complete => new Color(0.2f, 0.8f, 0.3f, 0.9f),
_ => Color.white,
};
}
// ========== 选中 / 拖拽 ==========
public void OnPointerClick(PointerEventData e)
{
if (e.button != PointerEventData.InputButton.Left) return;
NodeManager.Instance.SelectNode(this, e);
}
public void OnDrag(PointerEventData eventData)
{
if (eventData.button != PointerEventData.InputButton.Left) return;
var rt = GetComponent<RectTransform>();
rt.anchoredPosition += eventData.delta / GetComponentInParent<Canvas>().scaleFactor;
NodeManager.Instance.RefreshAllLines();
}
// ========== 插槽构建 ==========
void BuildConnectors()
{
foreach (var (name, connector, type) in nodeBase.GetInputs())
CreateSlot(name, connector, true);
foreach (var (name, connector, type) in nodeBase.GetOutputs())
CreateSlot(name, connector, false);
}
void CreateSlot(string name, object connector, bool isInput)
{
IInput inp = connector as IInput;
IOutput outp = connector as IOutput;
if (inp == null && outp == null) return;
var conName = inp?.Name ?? outp.Name;
if (inp != null) inp.Name = name;
if (outp != null) outp.Name = name;
var prefab = isInput ? connectorSlotPrefabI : connectorSlotPrefabO;
var parent = isInput ? inputsRoot : outputsRoot;
if (prefab == null || parent == null) return;
var go = Instantiate(prefab, parent);
var img = go.GetComponentInChildren<Image>();
if (img == null)
{
var imgGo = new GameObject("Dot", typeof(Image));
imgGo.transform.SetParent(go.transform, false);
img = imgGo.GetComponent<Image>();
}
img.color = (inp as IInput)?.ConnectorColor ?? (outp as IOutput)?.ConnectorColor ?? Color.white;
img.raycastTarget = true;
var text = go.GetComponentInChildren<TMP_Text>();
if (text != null) text.text = name;
var imgRt = img.GetComponent<RectTransform>();
if (imgRt.sizeDelta.sqrMagnitude < 1f) imgRt.sizeDelta = new Vector2(20, 20);
var slot = img.GetComponent<ConnectorSlot>();
if (slot == null) slot = img.gameObject.AddComponent<ConnectorSlot>();
slot.isInput = isInput;
slot.connectorIn = inp;
slot.connectorOut = outp;
slot.ownerNode = this;
}
}
}