using System; using System.Collections.Generic; using System.Dynamic; using Unity.VisualScripting; using UnityEditor; using UnityEngine; using UnityEngine.Rendering; using static UnityEngine.GraphicsBuffer; [ExecuteAlways] public class GameManager : MonoBehaviour { [HideInInspector] public static GameManager instance; public Transform NodeParent; public GameObject NodePrefab; [Header("Node Generation")] [Range(0, 20)] public float maxConnectionLength = 6; [Range(0, 1000)] public int nodeCount = 100; [Range(0, 100)] public float hoverRadius = 50; [Space] [Range(0,10)] public int editorConnectionAllowedWidth = 3; public Color editorConnectionAllowedColor = Color.white; [Space] [Range(0, 10)] public int editorConnectionHoveredWidth = 2; public Color editorConnectionHoveredColor = Color.gray; [Space] [Range(0,10)] public int editorConnectionForbiddenWidth = 1; public Color editorConnectionForbiddenColor = Color.black; private List nodes = new List(); [SerializeField] public List connections = new List(); [Serializable] public class Connection { public Node nodeA, nodeB; public bool allowed; } public void GenerateAlongSphere() { connections.Clear(); nodes.Clear(); for (int i = NodeParent.childCount - 1; i >= 0; i--) DestroyImmediate(NodeParent.GetChild(i).gameObject); float radius = 20f; float goldenRatio = (1f + Mathf.Sqrt(5f)) / 2f; float angleIncrement = 2f * Mathf.PI * goldenRatio; for (int i = 0; i < nodeCount; i++) { float t = (float)i / nodeCount; // von 0 bis 1 float inclination = Mathf.Acos(1f - 2f * t); float azimuth = angleIncrement * i; float x = Mathf.Sin(inclination) * Mathf.Cos(azimuth); float y = Mathf.Sin(inclination) * Mathf.Sin(azimuth); float z = Mathf.Cos(inclination); Vector3 pos = new Vector3(x, y, z) * radius; var auto = Instantiate(NodePrefab, NodeParent); auto.transform.localPosition = pos; nodes.Add(auto.GetComponent()); } } public void GenerateConnections() { connections.Clear(); foreach (Node nodeA in nodes) { if (nodeA == null) continue; foreach (Node nodeB in nodes) { if (nodeB == null) continue; bool conExists = false; if (nodeA == nodeB || Math.Abs(Vector3.Distance(nodeA.transform.position, nodeB.transform.position)) > maxConnectionLength) continue; foreach (Connection con in connections) { if ((con.nodeA == nodeA && con.nodeB == nodeB) || (con.nodeA == nodeB && con.nodeB == nodeA)) { conExists = true; break; } } if (!conExists) connections.Add(new Connection { nodeA = nodeA, nodeB = nodeB }); } } } #if UNITY_EDITOR void OnDrawGizmos() { if (connections == null) return; // Linien respektieren den Z-Buffer Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual; foreach (var con in connections) { if(!con.allowed) continue; Handles.color = Color.red; Handles.DrawLine(con.nodeA.transform.position, con.nodeB.transform.position); } } #endif } #if UNITY_EDITOR [CustomEditor(typeof(GameManager))] public class GameManagerEditor : Editor { int clickedConIdx = -1; public override void OnInspectorGUI() { DrawDefaultInspector(); GameManager gm = (GameManager)target; GUILayout.BeginHorizontal(); if (GUILayout.Button("Generate Sphere")) gm.GenerateAlongSphere(); if (GUILayout.Button("Generate Connections")) gm.GenerateConnections(); GUILayout.EndHorizontal(); if (GUILayout.Button("Generate")) { gm.GenerateAlongSphere(); gm.GenerateConnections(); } } private void OnSceneGUI() { Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual; GameManager gm = (GameManager)target; if (gm.connections == null || gm.connections.Count == 0) return; Camera cam = SceneView.lastActiveSceneView.camera; if (cam == null) return; Vector2 mouse = Event.current.mousePosition; mouse.y = cam.pixelHeight - mouse.y; Vector3 mousePos = new Vector3(mouse.x, mouse.y, 0); int closestIdx = -1; float closestDist = float.MaxValue; // Hover-Ermittlung for (int i = 0; i < gm.connections.Count; i++) { var con = gm.connections[i]; Vector3 a = cam.WorldToScreenPoint(con.nodeA.transform.position); Vector3 b = cam.WorldToScreenPoint(con.nodeB.transform.position); Vector3 ab = b - a; Vector3 am = mousePos - a; float t = Mathf.Clamp01(Vector3.Dot(am, ab) / ab.sqrMagnitude); Vector3 proj = a + t * ab; float dist = Vector3.Distance(mousePos, proj); if (dist < closestDist && dist < gm.hoverRadius) { closestDist = dist; closestIdx = i; } } // Klick-Behandlung Event e = Event.current; if (e.type == EventType.MouseDown && e.button == 0 && closestIdx >= 0) { clickedConIdx = closestIdx; } if (e.type == EventType.MouseUp && e.button == 0) { if (closestIdx == clickedConIdx && closestIdx != -1) { gm.connections[closestIdx].allowed = !gm.connections[closestIdx].allowed; e.Use(); // Event als verarbeitet markieren } clickedConIdx = -1; } // Zeichnen for (int i = 0; i < gm.connections.Count; i++) { var con = gm.connections[i]; Handles.color = (i == closestIdx && !con.allowed) ? gm.editorConnectionHoveredColor : con.allowed ? gm.editorConnectionAllowedColor : gm.editorConnectionForbiddenColor; float thickness = (i == closestIdx) ? gm.editorConnectionHoveredWidth : con.allowed ? gm.editorConnectionAllowedWidth : gm.editorConnectionForbiddenWidth; Handles.DrawLine(con.nodeA.transform.position, con.nodeB.transform.position, thickness); } // SceneView kontinuierlich aktualisieren SceneView.RepaintAll(); } } #endif