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 _stars = new List(); private readonly List _lines = new List(); 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(); 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(); } }