Files
2026-03-17 13:40:09 +02:00

197 lines
5.1 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Constellation : MonoBehaviour
{
[Header("Режим малювання")]
public bool editMode = false;
[Header("Максимальна кількіссть зірок")]
public int maxStars = 10;
[Header("Матеріали")]
[SerializeField] private GameObject starPrefab;
[SerializeField] private Material lineMaterial;
[Header("Відстань")]
[SerializeField] private float planeDistance = 8f;
[Header("Розміри")]
[SerializeField] private float starScaleMin = 0.06f;
[SerializeField] private float starScaleMax = 0.14f;
[SerializeField] private float lineWidth = 0.02f;
private readonly List<Transform> _stars = new List<Transform>();
private readonly List<LineRenderer> _lines = new List<LineRenderer>();
private Transform _root;
private Camera _cam;
private void Awake()
{
EnsureCameraAndRoot();
}
private void Update()
{
if (!editMode) return;
EnsureCameraAndRoot();
if (_cam == null)
{
return;
}
if (Input.GetMouseButtonDown(0))
{
TryAddStarByClick(Input.mousePosition);
}
UpdateAllLines();
}
private void EnsureCameraAndRoot()
{
if (_cam == null || !_cam.enabled)
{
_cam = FindEnabledCamera();
}
if (_cam != null && (_root == null || _root.parent != _cam.transform))
{
if (_root == null)
{
GameObject go = new GameObject("ConstellationRoot");
_root = go.transform;
}
_root.SetParent(_cam.transform);
_root.localPosition = new Vector3(0f, 0f, planeDistance);
_root.localRotation = Quaternion.identity;
_root.localScale = Vector3.one;
}
}
private Camera FindEnabledCamera()
{
Camera[] cams = Camera.allCameras;
for (int i = 0; i < cams.Length; i++)
{
if (cams[i] != null && cams[i].enabled && cams[i].gameObject.activeInHierarchy)
return cams[i];
}
if (Camera.main != null && Camera.main.enabled)
return Camera.main;
return null;
}
private void TryAddStarByClick(Vector3 screenPos)
{
Ray ray = _cam.ScreenPointToRay(screenPos);
Plane plane = new Plane(_cam.transform.forward, _cam.transform.position + _cam.transform.forward * planeDistance);
if (!plane.Raycast(ray, out float enter))
{
return;
}
Vector3 worldHit = ray.GetPoint(enter);
Vector3 localHit = _root.InverseTransformPoint(worldHit);
GameObject starGo = Instantiate(starPrefab, _root);
starGo.name = "Star_" + _stars.Count;
Transform starT = starGo.transform;
starT.localPosition = localHit;
float rndScale = Random.Range(starScaleMin, starScaleMax);
starT.localScale = Vector3.one * rndScale;
_stars.Add(starT);
if (_stars.Count >= 2)
{
CreateLine(_stars[_stars.Count - 2], _stars[_stars.Count - 1]);
}
}
private void CreateLine(Transform a, Transform b)
{
if (a == null || b == null) return;
GameObject lineGo = new GameObject("Line_" + _lines.Count);
lineGo.transform.SetParent(_root);
lineGo.transform.localPosition = Vector3.zero;
lineGo.transform.localRotation = Quaternion.identity;
lineGo.transform.localScale = Vector3.one;
LineRenderer lr = lineGo.AddComponent<LineRenderer>();
if (lineMaterial != null)
{
lr.material = lineMaterial;
}
else
{
Material fallback = new Material(Shader.Find("Unlit/Color"));
fallback.color = new Color(0.7f, 0.85f, 1f, 1f);
lr.material = fallback;
}
lr.useWorldSpace = false;
lr.positionCount = 2;
lr.startWidth = lineWidth;
lr.endWidth = lineWidth;
lr.numCapVertices = 6;
lr.numCornerVertices = 6;
_lines.Add(lr);
lr.SetPosition(0, a.localPosition);
lr.SetPosition(1, b.localPosition);
}
private void UpdateAllLines()
{
int needed = Mathf.Max(0, _stars.Count - 1);
if (_lines.Count < needed) return;
for (int i = 0; i < needed; i++)
{
LineRenderer lr = _lines[i];
if (lr == null) continue;
Transform a = _stars[i];
Transform b = _stars[i + 1];
if (a == null || b == null) continue;
lr.SetPosition(0, a.localPosition);
lr.SetPosition(1, b.localPosition);
}
}
public void ClearAll()
{
for (int i = 0; i < _lines.Count; i++)
{
if (_lines[i] != null) Destroy(_lines[i].gameObject);
}
for (int i = 0; i < _stars.Count; i++)
{
if (_stars[i] != null) Destroy(_stars[i].gameObject);
}
_lines.Clear();
_stars.Clear();
}
}