using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using Unity.VisualScripting; using UnityEditor; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UIElements; using static UnityEngine.GraphicsBuffer; [ExecuteAlways] public class GameManager : MonoBehaviour { public Transform ConnectionParent; public Transform NodeParent; public GameObject NodePrefab; public static GameManager Instance { get; private set; } public bool regenerateOnChange = false; [HideInInspector] public float minConnectionLength = 6; [HideInInspector] public float maxConnectionLength = 6; [HideInInspector] public int nodeCount = 100; [HideInInspector] public int hoverRadiusCon = 50; [HideInInspector] public int hoverRadiusNode = 50; [HideInInspector] public int selectedLevel = -1; [SerializeField] [HideInInspector] public List connections = new List(); [SerializeField] [HideInInspector] public List nodes = new List(); [SerializeField] [HideInInspector] public List levels = new List(); [Serializable] public class Connection { public Node nodeA, nodeB; public bool allowed = true; public bool hovered = false; public LineRenderer lineRenderer; public void SetConnect() { if (!allowed) return; nodeA.connected.Add(nodeB); nodeB.connected.Add(nodeA); } public void DelConnect() { nodeA.connected.Remove(nodeB); nodeB.connected.Remove(nodeA); } } [Serializable] public class LevelData { [Serializable] public class NodeData { public Vector3 position; public int owner; } [Serializable] public class ConnectionData { public int nodeAIndex; public int nodeBIndex; public bool allowed = true; } public float minConnectionLength = 0; public float maxConnectionLength = 0; public List nodes = new List(); public List connections = new List(); } void Awake() { if (Instance != null && Instance != this) { if (Application.isPlaying) Destroy(gameObject); return; } Instance = this; if (Application.isPlaying) DontDestroyOnLoad(gameObject); connections.ForEach(obj => obj.DelConnect()); connections.ForEach(obj => obj.SetConnect()); } 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 = PrefabUtility.InstantiatePrefab(NodePrefab, NodeParent) as GameObject; auto.transform.localPosition = pos; nodes.Add(auto.GetComponent()); } } public void GenerateConnections() { connections.Clear(); foreach (LineRenderer line in ConnectionParent.GetComponentsInChildren()) DestroyImmediate(line.gameObject); foreach (Node nodeA in nodes) { if (nodeA == null) continue; foreach (Node nodeB in nodes) { if (nodeB == null) continue; bool conExists = false; float dist = Vector3.Distance(nodeA.transform.position, nodeB.transform.position); if (nodeA == nodeB || dist > 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) { AddConnection(nodeA, nodeB, dist < minConnectionLength); } } } } public void FetchAllNodes() { Node[] allNodes = NodeParent.GetComponentsInChildren(); nodes = allNodes.ToList(); nodeCount = allNodes.Length; } private void Update() { foreach (var con in connections) { if(Application.isPlaying && !con.allowed) { con.lineRenderer.enabled = false; continue; } float width = (con.hovered ? 0.6f : 0.3f) * (con.allowed ? 1f : 0.3f); con.lineRenderer.startColor = con.allowed ? con.nodeA.transform.GetChild(0).GetComponent().sharedMaterial.color : new Color(0.2f, 0.2f, 0.2f); con.lineRenderer.endColor = con.allowed ? con.nodeB.transform.GetChild(0).GetComponent().sharedMaterial.color : new Color(0.2f, 0.2f, 0.2f); con.lineRenderer.startWidth = width; con.lineRenderer.endWidth = width; con.lineRenderer.SetGreatCircleArc(con.nodeA.transform.position, con.nodeB.transform.position, 5, 20.5f); con.lineRenderer.enabled = true; } } public void AddConnection(Node nodeA, Node nodeB, bool allowed = true) { var dummy = new GameObject("dummy"); dummy.transform.SetParent(ConnectionParent); var newCon = new Connection { nodeA = nodeA, nodeB = nodeB, allowed = allowed, lineRenderer = dummy.AddComponent() }; newCon.lineRenderer.enabled = false; newCon.lineRenderer.material = new Material(Shader.Find("Sprites/Default")); newCon.lineRenderer.positionCount = 3; connections.Add(newCon); } public void LoadLevelData(int index) { if(index >= levels.Count) { Debug.LogWarning("LevelIndex out of range"); return; } connections.Clear(); nodes.Clear(); for (int i = NodeParent.childCount - 1; i >= 0; i--) DestroyImmediate(NodeParent.GetChild(i).gameObject); foreach (LineRenderer line in ConnectionParent.GetComponentsInChildren()) DestroyImmediate(line.gameObject); foreach(LevelData.NodeData nodeData in levels[index].nodes) { var auto = PrefabUtility.InstantiatePrefab(NodePrefab, NodeParent) as GameObject; auto.transform.localPosition = nodeData.position; nodes.Add(auto.GetComponent()); auto.GetComponent().Owner = nodeData.owner; } foreach (LevelData.ConnectionData conData in levels[index].connections) { AddConnection(nodes[conData.nodeAIndex], nodes[conData.nodeBIndex], conData.allowed); } selectedLevel = index; minConnectionLength = levels[index].minConnectionLength; maxConnectionLength = levels[index].maxConnectionLength; nodeCount = nodes.Count; } public void SaveLevelData(int index = -1) { LevelData data = new LevelData(); data.minConnectionLength = minConnectionLength; data.maxConnectionLength = maxConnectionLength; // Nodes speichern foreach (var node in nodes) { data.nodes.Add(new LevelData.NodeData { position = node.transform.localPosition, owner = node.Owner }); } // Connections speichern foreach (var con in connections) { int idxA = nodes.IndexOf(con.nodeA); int idxB = nodes.IndexOf(con.nodeB); if (idxA >= 0 && idxB >= 0) { data.connections.Add(new LevelData.ConnectionData { nodeAIndex = idxA, nodeBIndex = idxB, allowed = con.allowed }); } } if (index == -1 || index >= levels.Count) levels.Add(data); else levels[index] = data; int newIndex = index < 0 ? levels.Count - 1 : index; selectedLevel = newIndex; } }