using UnityEngine; // 유니티 엔진의 기본 기능을 불러올거에요 -> UnityEngine을 [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))] // 컴포넌트를 강제로 추가할거에요 -> MeshFilter와 MeshRenderer를 public class ArrowRangeUI : MonoBehaviour // 클래스를 선언할거에요 -> MonoBehaviour를 상속받는 ArrowRangeUI를 { [Header("--- 참조 ---")] // 인스펙터 창에 제목을 표시할거에요 -> --- 참조 --- 를 [SerializeField] private PlayerAttack attackScript; // 변수를 선언할거에요 -> 플레이어 공격 스크립트를 연결할 attackScript를 [Header("--- UI 설정 ---")] // 인스펙터 창에 제목을 표시할거에요 -> --- UI 설정 --- 을 [Tooltip("사거리 표시기의 색상")] // 마우스를 올리면 설명을 보여줄거에요 -> 툴팁 내용을 [SerializeField] private Color uiColor = new Color(1f, 1f, 0f, 0.5f); // 변수를 선언할거에요 -> UI 색상(노란색 반투명)을 uiColor에 [Tooltip("화살표 UI의 폭 (두께)")] // 마우스를 올리면 설명을 보여줄거에요 -> 툴팁 내용을 [SerializeField] private float lineWidth = 1.0f; // 변수를 선언할거에요 -> 선 두께(1.0)를 lineWidth에 [Header("--- 길이 설정 ---")] // 인스펙터 창에 제목을 표시할거에요 -> --- 길이 설정 --- 을 [Tooltip("차징 0%일 때의 최소 길이 (기본 사거리)")] // 마우스를 올리면 설명을 보여줄거에요 -> 툴팁 내용을 [SerializeField] private float minLength = 5f; // 변수를 선언할거에요 -> 최소 길이(5.0)를 minLength에 [Tooltip("풀차징일 때의 최대 길이 (최대 사거리)")] // 마우스를 올리면 설명을 보여줄거에요 -> 툴팁 내용을 [SerializeField] private float maxLength = 20f; // 변수를 선언할거에요 -> 최대 길이(20.0)를 maxLength에 private Mesh _mesh; // 변수를 선언할거에요 -> UI를 그릴 메쉬를 _mesh에 private MeshFilter _meshFilter; // 변수를 선언할거에요 -> 메쉬 필터 컴포넌트를 _meshFilter에 private MeshRenderer _meshRenderer; // 변수를 선언할거에요 -> 메쉬 렌더러 컴포넌트를 _meshRenderer에 private void Awake() // 함수를 실행할거에요 -> 스크립트 시작 시 Awake를 { // 메쉬 초기화 _mesh = new Mesh(); // 생성할거에요 -> 빈 메쉬 객체를 _meshFilter = GetComponent(); // 컴포넌트를 가져올거에요 -> 메쉬 필터를 _meshRenderer = GetComponent(); // 컴포넌트를 가져올거에요 -> 메쉬 렌더러를 _meshFilter.mesh = _mesh; // 할당할거에요 -> 생성한 메쉬를 필터에 // 재질(Material)이 없다면 임시로 생성 if (_meshRenderer.material == null) // 조건이 맞으면 실행할거에요 -> 렌더러에 재질이 없다면 { _meshRenderer.material = new Material(Shader.Find("Sprites/Default")); // 생성할거에요 -> 기본 스프라이트 쉐이더로 새 재질을 } _meshRenderer.material.color = uiColor; // 색상을 설정할거에요 -> 지정한 UI 색상으로 } private void Update() // 함수를 실행할거에요 -> 매 프레임마다 Update를 { // 1. 공격 스크립트가 없거나 차징 중이 아니면 끄기 if (attackScript == null || !attackScript.IsCharging) // 조건이 맞으면 실행할거에요 -> 공격 스크립트가 없거나 차징 중이 아니라면 { _meshRenderer.enabled = false; // 기능을 끌거에요 -> 렌더러를 (안 보이게) return; // 중단할거에요 -> 업데이트를 } _meshRenderer.enabled = true; // 기능을 켤거에요 -> 렌더러를 (보이게) // 2. 차징 진행도(0.0 ~ 1.0) 가져오기 float progress = attackScript.ChargeProgress; // 값을 가져올거에요 -> 차징 진행률을 progress에 // 3. 진행도에 따라 길이 계산 (Lerp로 부드럽게 늘어남) float currentLength = Mathf.Lerp(minLength, maxLength, progress); // 값을 계산할거에요 -> 최소~최대 사이에서 진행도에 맞는 길이를 // 4. 직사각형 메쉬 그리기 CreateRectangleMesh(currentLength, lineWidth); // 함수를 실행할거에요 -> 계산된 길이와 두께로 메쉬를 그리는 CreateRectangleMesh를 } // 직사각형 메쉬 생성 함수 private void CreateRectangleMesh(float length, float width) // 함수를 선언할거에요 -> 사각형 메쉬를 만드는 CreateRectangleMesh를 { Vector3[] vertices = new Vector3[4]; // 배열을 생성할거에요 -> 정점 4개를 담을 vertices를 int[] triangles = new int[6]; // 배열을 생성할거에요 -> 삼각형 인덱스 6개를 담을 triangles를 Vector2[] uvs = new Vector2[4]; // 배열을 생성할거에요 -> UV 좌표 4개를 담을 uvs를 float halfWidth = width / 2f; // 값을 계산할거에요 -> 폭의 절반을 halfWidth에 // 정점 4개 정의 (플레이어 발밑 기준 앞으로 뻗어나감) vertices[0] = new Vector3(-halfWidth, 0.1f, 0); // 값을 넣을거에요 -> 왼쪽 아래 정점을 (시작점) vertices[1] = new Vector3(halfWidth, 0.1f, 0); // 값을 넣을거에요 -> 오른쪽 아래 정점을 (시작점) vertices[2] = new Vector3(-halfWidth, 0.1f, length); // 값을 넣을거에요 -> 왼쪽 위 정점을 (끝점) vertices[3] = new Vector3(halfWidth, 0.1f, length); // 값을 넣을거에요 -> 오른쪽 위 정점을 (끝점) // 삼각형 연결 triangles[0] = 0; // 값을 넣을거에요 -> 첫 번째 삼각형의 1번 점 인덱스를 triangles[1] = 2; // 값을 넣을거에요 -> 첫 번째 삼각형의 2번 점 인덱스를 triangles[2] = 1; // 값을 넣을거에요 -> 첫 번째 삼각형의 3번 점 인덱스를 triangles[3] = 2; // 값을 넣을거에요 -> 두 번째 삼각형의 1번 점 인덱스를 triangles[4] = 3; // 값을 넣을거에요 -> 두 번째 삼각형의 2번 점 인덱스를 triangles[5] = 1; // 값을 넣을거에요 -> 두 번째 삼각형의 3번 점 인덱스를 // UV 매핑 uvs[0] = new Vector2(0, 0); // 값을 넣을거에요 -> 0번 정점의 텍스처 좌표를 uvs[1] = new Vector2(1, 0); // 값을 넣을거에요 -> 1번 정점의 텍스처 좌표를 uvs[2] = new Vector2(0, 1); // 값을 넣을거에요 -> 2번 정점의 텍스처 좌표를 uvs[3] = new Vector2(1, 1); // 값을 넣을거에요 -> 3번 정점의 텍스처 좌표를 // 메쉬 적용 _mesh.Clear(); // 비울거에요 -> 기존 메쉬 데이터를 _mesh.vertices = vertices; // 값을 넣을거에요 -> 새로 만든 정점들을 _mesh.triangles = triangles; // 값을 넣을거에요 -> 새로 만든 삼각형들을 _mesh.uv = uvs; // 값을 넣을거에요 -> 새로 만든 UV를 _mesh.RecalculateNormals(); // 계산할거에요 -> 조명을 위한 법선 벡터를 _mesh.RecalculateBounds(); // 계산할거에요 -> 메쉬의 경계 영역을 } }