2025-09-16 01:16:02 +02:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using Unity.VisualScripting;
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.Rendering;
|
|
|
|
|
using static UnityEngine.GraphicsBuffer;
|
|
|
|
|
|
|
|
|
|
[ExecuteAlways]
|
|
|
|
|
public class GameManager : MonoBehaviour
|
|
|
|
|
{
|
|
|
|
|
[HideInInspector]
|
|
|
|
|
public static GameManager instance;
|
|
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
private Transform NodeParent;
|
|
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
private 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;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public List<Connection> connections = new List<Connection>();
|
2025-09-16 00:08:50 +02:00
|
|
|
private List<Node> nodes = new List<Node>();
|
|
|
|
|
|
2025-09-16 01:16:02 +02:00
|
|
|
public struct Connection
|
2025-09-16 00:08:50 +02:00
|
|
|
{
|
2025-09-16 01:16:02 +02:00
|
|
|
public Node nodeA, nodeB;
|
|
|
|
|
public bool allowed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void GenerateAlongSphere()
|
2025-09-16 00:08:50 +02:00
|
|
|
{
|
|
|
|
|
connections.Clear();
|
|
|
|
|
nodes.Clear();
|
|
|
|
|
|
2025-09-16 01:16:02 +02:00
|
|
|
for (int i = NodeParent.childCount - 1; i >= 0; i--)
|
|
|
|
|
DestroyImmediate(NodeParent.GetChild(i).gameObject);
|
2025-09-16 00:08:50 +02:00
|
|
|
|
|
|
|
|
float radius = 20f;
|
|
|
|
|
|
|
|
|
|
float goldenRatio = (1f + Mathf.Sqrt(5f)) / 2f;
|
|
|
|
|
float angleIncrement = 2f * Mathf.PI * goldenRatio;
|
|
|
|
|
|
2025-09-16 01:16:02 +02:00
|
|
|
for (int i = 0; i < nodeCount; i++)
|
2025-09-16 00:08:50 +02:00
|
|
|
{
|
2025-09-16 01:16:02 +02:00
|
|
|
float t = (float)i / nodeCount; // von 0 bis 1
|
2025-09-16 00:08:50 +02:00
|
|
|
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<Node>());
|
|
|
|
|
}
|
2025-09-16 01:16:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void GenerateConnections()
|
2025-09-16 00:08:50 +02:00
|
|
|
{
|
|
|
|
|
connections.Clear();
|
|
|
|
|
|
2025-09-16 01:16:02 +02:00
|
|
|
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 });
|
|
|
|
|
}
|
2025-09-16 00:08:50 +02:00
|
|
|
}
|
2025-09-16 01:16:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
|
|
|
|
void Start()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if UNITY_EDITOR
|
2025-09-16 00:08:50 +02:00
|
|
|
void OnDrawGizmos()
|
|
|
|
|
{
|
2025-09-16 01:16:02 +02:00
|
|
|
if (connections == null || SceneView.lastActiveSceneView?.camera == null) return;
|
|
|
|
|
|
|
|
|
|
Camera cam = SceneView.lastActiveSceneView.camera;
|
2025-09-16 00:08:50 +02:00
|
|
|
|
2025-09-16 01:16:02 +02:00
|
|
|
// Maus Screen-Koordinaten
|
|
|
|
|
Vector2 guiPos = Event.current.mousePosition;
|
|
|
|
|
guiPos.y = cam.pixelHeight - guiPos.y;
|
|
|
|
|
Vector3 mousePos = new Vector3(guiPos.x, guiPos.y, 0);
|
2025-09-16 00:08:50 +02:00
|
|
|
|
2025-09-16 01:16:02 +02:00
|
|
|
int closestIndex = -1;
|
|
|
|
|
float closestDist = float.MaxValue;
|
|
|
|
|
|
|
|
|
|
// Erster Durchlauf: kleinste Distanz merken
|
|
|
|
|
for (int i = 0; i < connections.Count; i++)
|
2025-09-16 00:08:50 +02:00
|
|
|
{
|
2025-09-16 01:16:02 +02:00
|
|
|
var con = connections[i];
|
|
|
|
|
Vector3 a = cam.WorldToScreenPoint(con.nodeA.transform.position);
|
|
|
|
|
Vector3 b = cam.WorldToScreenPoint(con.nodeB.transform.position);
|
|
|
|
|
|
|
|
|
|
// Punkt-zu-Segment Abstand statt Dreiecksformel
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
closestDist = dist;
|
|
|
|
|
closestIndex = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Zweiter Durchlauf: zeichnen
|
|
|
|
|
for (int i = 0; i < connections.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var con = connections[i];
|
2025-09-16 00:08:50 +02:00
|
|
|
Handles.color = con.allowed ? Color.green : Color.red;
|
2025-09-16 01:16:02 +02:00
|
|
|
float thickness = (i == closestIndex && closestDist < hoverRadius) ? 5f : 1f;
|
|
|
|
|
Handles.DrawLine(con.nodeA.transform.position, con.nodeB.transform.position, thickness);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
|
|
|
|
|
[CustomEditor(typeof(GameManager))]
|
|
|
|
|
public class GameManagerEditor : Editor
|
|
|
|
|
{
|
|
|
|
|
public override void OnInspectorGUI()
|
|
|
|
|
{
|
|
|
|
|
// Standard-Inspector zeichnen
|
|
|
|
|
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();
|
2025-09-16 00:08:50 +02:00
|
|
|
}
|
|
|
|
|
}
|
2025-09-16 01:16:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[InitializeOnLoad]
|
|
|
|
|
public static class SceneViewUpdater
|
|
|
|
|
{
|
|
|
|
|
static SceneViewUpdater()
|
|
|
|
|
{
|
|
|
|
|
EditorApplication.update += () =>
|
|
|
|
|
{
|
|
|
|
|
if (SceneView.lastActiveSceneView != null)
|
|
|
|
|
SceneView.lastActiveSceneView.Repaint();
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|