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; using static UnityEngine.UI.GridLayoutGroup; [ExecuteAlways] public class GameManager : MonoBehaviour { public Transform ConnectionParent; public GameObject ConnectionPrefab; public Transform NodeParent; public GameObject NodePrefab; public List players; public int currentPlayer = -1; public Node pressedNode = null; 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 levels = new List(); public enum ActionType { MOVE_UNITS, DESTRUCT_CON, EXPLODE_CON }; public struct Action { public ActionType type; public int nodeFromId; public int nodeToId; public int amount; public int player; } [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); GetConnections().ForEach(obj => obj.DelConnect()); GetConnections().ForEach(obj => obj.SetConnect()); } private void Update() { if (Input.GetMouseButtonDown(0)) { pressedNode = GetNodes().Find(n => n.hovered && n.Owner == currentPlayer); } if (Input.GetMouseButtonUp(0)) { if (pressedNode != null) { Node toNode = GetNodes().Find(n => n.hovered && pressedNode != n); if (toNode) { Connection con = Instance.GetConnections().Find(c => (c.nodeA == pressedNode && c.nodeB == toNode) || (c.nodeB == pressedNode && c.nodeA == toNode)); if (con) { var action = new Action { nodeFromId = pressedNode.id, nodeToId = toNode.id, type = ActionType.MOVE_UNITS, player = Instance.currentPlayer }; Instance.ExecuteAction(action); } } } } } public List GetNodes() => NodeParent.GetComponentsInChildren().ToList(); public List GetConnections() => ConnectionParent != null ? ConnectionParent.GetComponentsInChildren()?.ToList() ?? new() : new(); public void ExecuteRoundEnd() { foreach(Connection con in GetConnections()) { if (con.state == Connection.BuildState.CONSTRUCTING) con.state = Connection.BuildState.BUILT; else if (con.state == Connection.BuildState.DECONSTRUCTING) con.state = Connection.BuildState.EMPTY; } } public void ExecuteAction(Action action) { Node nodeTo = GetNodes().Find(n => n.id == action.nodeToId); Node nodeFrom = GetNodes().Find(n => n.id == action.nodeFromId); Connection con = GetConnections().Find(c => (c.nodeA == nodeTo && c.nodeB == nodeFrom) || (c.nodeA == nodeFrom && c.nodeB == nodeTo)); Player p = players.Find(p => (p.id == action.player)); bool hostile = nodeTo.Owner != action.player; switch (action.type) { case ActionType.MOVE_UNITS: if (p.energy < 1) { Debug.Log("Not enough energy"); return; } p.energy -= 1; switch (con.state) { case Connection.BuildState.EMPTY: // Build Connection con.state = Connection.BuildState.CONSTRUCTING; Debug.Log("Starting construction from " + nodeTo.id + " to " + nodeFrom.id); return; case Connection.BuildState.CONSTRUCTING: if (hostile) { Debug.Log("Attacking hostile construction from " + nodeTo.id + " to " + nodeFrom.id); } else { Debug.Log("This should not be possible O_o"); } return; case Connection.BuildState.DECONSTRUCTING: if (hostile) { Debug.Log("Attacking hostile construction from " + nodeTo.id + " to " + nodeFrom.id); } else { Debug.Log("This should not be possible O_o"); } return; case Connection.BuildState.BUILT: if (hostile) { Debug.Log("Attacking hostile units at " + nodeFrom.id); int actualAmount = action.amount + Math.Min(0, nodeFrom.Units - action.amount); nodeFrom.Units -= actualAmount; var unitDiff = actualAmount - nodeFrom.Units; nodeTo.Units -= actualAmount; if (unitDiff == 0) { nodeTo.Owner = -1; } else if (unitDiff > 0) { nodeTo.Owner = p.id; } } else { Debug.Log("Moving units from " + nodeTo.id + " to " + nodeFrom.id); int actualAmount = action.amount + Math.Min(0, nodeFrom.Units - action.amount); nodeFrom.Units -= actualAmount; nodeTo.Units += actualAmount; } return; default: return; } case ActionType.DESTRUCT_CON: if (!hostile) { if (p.energy < 1) { Debug.Log("Not enough energy"); return; } p.energy -= 1; Debug.Log("Starten deconstruction from " + nodeTo.id + " to " + nodeFrom.id); con.state = Connection.BuildState.DECONSTRUCTING; } else { Debug.Log("This should not be possible O_o"); } return; case ActionType.EXPLODE_CON: if (p.energy < 2) { Debug.Log("Not enough energy"); return; } p.energy -= 2; Debug.Log("Exploding connection from " + nodeTo.id + " to " + nodeFrom.id); con.state = Connection.BuildState.EMPTY; return; } } public void GenerateAlongSphere() { 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.GetComponent().id = i; auto.transform.localPosition = pos; } } public void GenerateConnections() { for (int i = ConnectionParent.childCount - 1; i >= 0; i--) DestroyImmediate(ConnectionParent.GetChild(i).gameObject); var nodes = GetNodes(); 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 GetConnections()) { 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 AddConnection(Node nodeA, Node nodeB, bool allowed = true) { var newCon = PrefabUtility.InstantiatePrefab(ConnectionPrefab, ConnectionParent).GetComponent(); newCon.nodeA = nodeA; newCon.nodeB = nodeB; newCon.allowed = allowed; } public void LoadLevelData(int index) { if(index >= levels.Count) { Debug.LogWarning("LevelIndex out of range"); return; } for (int i = NodeParent.childCount - 1; i >= 0; i--) DestroyImmediate(NodeParent.GetChild(i).gameObject); foreach (LineRenderer line in ConnectionParent.GetComponentsInChildren()) DestroyImmediate(line.gameObject); for(int i = 0; i < levels[index].nodes.Count; i++) { var nodeData = levels[index].nodes[i]; var auto = PrefabUtility.InstantiatePrefab(NodePrefab, NodeParent) as GameObject; auto.transform.localPosition = nodeData.position; auto.GetComponent().Owner = nodeData.owner; auto.GetComponent().id = i; } var currentNodes = GetNodes(); int idx = 0; foreach (Node node in currentNodes) node.id = idx++; currentNodes = GetNodes(); foreach (LevelData.ConnectionData conData in levels[index].connections) { AddConnection(currentNodes[conData.nodeAIndex], currentNodes[conData.nodeBIndex], conData.allowed); Debug.Log(conData.nodeAIndex + " - " + conData.nodeBIndex); } selectedLevel = index; minConnectionLength = levels[index].minConnectionLength; maxConnectionLength = levels[index].maxConnectionLength; nodeCount = currentNodes.Count; } public void SaveLevelData(int index = -1) { LevelData data = new LevelData(); data.minConnectionLength = minConnectionLength; data.maxConnectionLength = maxConnectionLength; // Nodes speichern foreach (var node in GetNodes()) { data.nodes.Add(new LevelData.NodeData { position = node.transform.localPosition, owner = node.Owner }); } // Connections speichern foreach (var con in GetConnections()) { if (con.nodeA.id >= 0 && con.nodeB.id >= 0) { data.connections.Add(new LevelData.ConnectionData { nodeAIndex = con.nodeA.id, nodeBIndex = con.nodeB.id, 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; } }