using UnityEngine; // 유니티 엔진의 기본 기능을 불러올거에요 -> UnityEngine을 using System.Collections; // 코루틴 기능을 사용할거에요 -> System.Collections를 /// /// 발사된 화살 발사체 (파티클 프리팹에 부착됨) /// SphereCast 기반 정밀 충돌 감지 (기존 100% 유지) /// [UPGRADED] 속성 데미지를 인스펙터에서 속성별로 개별 조정 가능 /// public class PlayerArrow : MonoBehaviour // 클래스를 선언할거에요 -> MonoBehaviour를 상속받는 PlayerArrow를 { [Header("--- 정밀 피격 판정 설정 ---")] // 인스펙터 창에 제목을 표시할거에요 -> --- 정밀 피격 판정 설정 --- 을 [SerializeField] private float raycastDistance = 0.8f; // 변수를 선언할거에요 -> 레이캐스트 거리인 raycastDistance를 [SerializeField] private float raycastRadius = 0.08f; // 변수를 선언할거에요 -> 레이캐스트 반지름인 raycastRadius를 [SerializeField] private LayerMask hitLayers; // 변수를 선언할거에요 -> 충돌 레이어인 hitLayers를 [SerializeField] private Transform arrowTip; // 변수를 선언할거에요 -> 화살 끝부분 위치인 arrowTip을 [Header("--- 기본 화살 데미지 ---")] // 인스펙터 창에 제목을 표시할거에요 -> --- 기본 화살 데미지 --- 를 [Tooltip("기본 화살 데미지 (속성과 무관한 물리 데미지)")] [SerializeField] private float baseDamage = 10f; // 변수를 선언할거에요 -> 기본 물리 데미지인 baseDamage를 [Header("--- 🔥 불 속성 설정 ---")] // 인스펙터 창에 제목을 표시할거에요 -> 불 속성 섹션을 [SerializeField] private ElementEffectData fireEffect = new ElementEffectData // 변수를 선언할거에요 -> 불 속성 데이터인 fireEffect를 { bonusDamage = 5f, // 기본값을 설정할거에요 -> 즉발 추가 데미지를 5로 dotDamagePerTick = 3f, // 기본값을 설정할거에요 -> 틱당 화상 데미지를 3으로 dotDuration = 4f, // 기본값을 설정할거에요 -> 화상 지속시간을 4초로 dotTickInterval = 0.5f, // 기본값을 설정할거에요 -> 틱 간격을 0.5초로 effectStrength = 1f // 기본값을 설정할거에요 -> 효과 강도를 1로 (불은 순수 데미지라 참고용) }; [Header("--- ❄️ 얼음 속성 설정 ---")] // 인스펙터 창에 제목을 표시할거에요 -> 얼음 속성 섹션을 [SerializeField] private ElementEffectData iceEffect = new ElementEffectData // 변수를 선언할거에요 -> 얼음 속성 데이터인 iceEffect를 { bonusDamage = 2f, // 기본값을 설정할거에요 -> 즉발 추가 데미지를 2로 dotDamagePerTick = 0f, // 기본값을 설정할거에요 -> 틱 데미지를 0으로 (얼음은 슬로우 위주) dotDuration = 3f, // 기본값을 설정할거에요 -> 슬로우 지속시간을 3초로 dotTickInterval = 1f, // 기본값을 설정할거에요 -> 틱 간격을 1초로 effectStrength = 0.5f // 기본값을 설정할거에요 -> 슬로우 비율을 0.5 (50% 감속)로 }; [Header("--- ☠️ 독 속성 설정 ---")] // 인스펙터 창에 제목을 표시할거에요 -> 독 속성 섹션을 [SerializeField] private ElementEffectData poisonEffect = new ElementEffectData // 변수를 선언할거에요 -> 독 속성 데이터인 poisonEffect를 { bonusDamage = 1f, // 기본값을 설정할거에요 -> 즉발 추가 데미지를 1로 dotDamagePerTick = 2f, // 기본값을 설정할거에요 -> 틱당 독 데미지를 2로 dotDuration = 6f, // 기본값을 설정할거에요 -> 독 지속시간을 6초로 dotTickInterval = 1f, // 기본값을 설정할거에요 -> 틱 간격을 1초로 effectStrength = 1f // 기본값을 설정할거에요 -> 효과 강도를 1로 }; [Header("--- ⚡ 전기 속성 설정 ---")] // 인스펙터 창에 제목을 표시할거에요 -> 전기 속성 섹션을 [SerializeField] private ElementEffectData lightningEffect = new ElementEffectData // 변수를 선언할거에요 -> 전기 속성 데이터인 lightningEffect를 { bonusDamage = 8f, // 기본값을 설정할거에요 -> 즉발 추가 데미지를 8로 dotDamagePerTick = 0f, // 기본값을 설정할거에요 -> 틱 데미지를 0으로 (전기는 스턴 위주) dotDuration = 1.5f, // 기본값을 설정할거에요 -> 스턴 지속시간을 1.5초로 dotTickInterval = 1f, // 기본값을 설정할거에요 -> 틱 간격을 1초로 effectStrength = 1.5f // 기본값을 설정할거에요 -> 스턴 지속시간을 1.5초로 }; [Header("--- 디버그 시각화 ---")] // 인스펙터 창에 제목을 표시할거에요 -> --- 디버그 시각화 --- 를 [SerializeField] private bool showDebugRay = true; // 변수를 선언할거에요 -> 디버그 레이 표시 여부인 showDebugRay를 // 화살 런타임 스탯 (Initialize에서 설정됨) private float damage; // 변수를 선언할거에요 -> 최종 데미지 damage를 private float speed; // 변수를 선언할거에요 -> 속도 speed를 private float range; // 변수를 선언할거에요 -> 사거리 range를 private Vector3 startPos; // 변수를 선언할거에요 -> 시작 위치 startPos를 private Vector3 shootDirection; // 변수를 선언할거에요 -> 발사 방향 shootDirection을 private bool isFired = false; // 변수를 초기화할거에요 -> 발사 여부 isFired를 거짓으로 private bool hasHit = false; // 변수를 초기화할거에요 -> 충돌 여부 hasHit을 거짓으로 // 현재 적용 중인 속성 (Initialize에서 설정됨) private ArrowElementType currentElement = ArrowElementType.None; // 변수를 초기화할거에요 -> 현재 속성을 없음으로 // Raycast 추적용 private Vector3 previousPosition; // 변수를 선언할거에요 -> 이전 위치 previousPosition을 private Rigidbody rb; // 변수를 선언할거에요 -> 물리 컴포넌트 rb를 private void Awake() // 함수를 실행할거에요 -> 스크립트 시작 시 Awake를 { rb = GetComponent(); // 컴포넌트를 가져올거에요 -> 리지드바디를 } private void Start() // 함수를 실행할거에요 -> 활성화 시 Start를 { if (arrowTip == null) // 조건이 맞으면 실행할거에요 -> 화살 팁이 설정되지 않았다면 { Transform tip = transform.Find("ArrowTip"); // 찾을거에요 -> 자식 중 ArrowTip을 if (tip == null) tip = transform.Find("Tip"); // 못 찾으면 찾을거에요 -> Tip을 arrowTip = tip ?? transform; // 그래도 없으면 할당할거에요 -> 자기 자신의 위치를 } if (hitLayers.value == 0) // 조건이 맞으면 실행할거에요 -> 충돌 레이어가 설정되지 않았다면 { hitLayers = LayerMask.GetMask("Enemy", "EnemyHitBox", "Wall", "Ground", "Default"); // 값을 넣을거에요 -> 기본 충돌 레이어들을 } } /// /// [UPGRADED] 초기화 — 속성 타입만 받고, 세부 수치는 인스펙터 설정값 사용 /// PlayerAttack.OnShootArrow()에서 호출됩니다. /// public void Initialize( float dmg, float arrowSpeed, float maxRange, Vector3 direction, ArrowElementType element) // 함수를 선언할거에요 -> 화살을 초기화하는 Initialize를 (5개 파라미터) { this.speed = arrowSpeed; // 값을 저장할거에요 -> 속도를 this.range = maxRange; // 값을 저장할거에요 -> 사거리를 this.shootDirection = direction.normalized; // 값을 저장할거에요 -> 정규화된 발사 방향을 this.startPos = transform.position; // 값을 저장할거에요 -> 시작 위치를 this.previousPosition = transform.position; // 값을 저장할거에요 -> 이전 위치를 (레이캐스트용) this.isFired = true; // 상태를 바꿀거에요 -> 발사됨 상태로 this.currentElement = element; // 값을 저장할거에요 -> 현재 속성 타입을 // [UPGRADED] 기본 데미지 = 외부에서 받은 dmg + 속성 즉발 보너스 데미지 ElementEffectData effectData = GetElementData(element); // 데이터를 가져올거에요 -> 현재 속성에 맞는 설정값을 float bonusDmg = (effectData != null && effectData.enabled) ? effectData.bonusDamage : 0f; // 값을 계산할거에요 -> 속성 추가 즉발 데미지를 this.damage = dmg + bonusDmg; // 값을 저장할거에요 -> 기본 데미지 + 속성 보너스를 최종 데미지로 Debug.Log($"[Arrow] 초기화 — 기본:{dmg} + 속성보너스:{bonusDmg} = 최종:{this.damage} | 속성:{element}"); // 로그를 출력할거에요 -> 데미지 계산 내역을 // 발사 방향으로 회전 if (shootDirection != Vector3.zero) // 조건이 맞으면 실행할거에요 -> 방향이 유효하다면 { transform.rotation = Quaternion.LookRotation(shootDirection); // 회전시킬거에요 -> 발사 방향을 보도록 } // Rigidbody 설정 if (rb == null) rb = GetComponent(); // 컴포넌트를 가져올거에요 -> 없다면 리지드바디를 if (rb != null) // 조건이 맞으면 실행할거에요 -> 리지드바디가 있다면 { rb.useGravity = false; // 설정을 바꿀거에요 -> 중력을 끄기로 rb.isKinematic = false; // 설정을 바꿀거에요 -> 물리 연산을 켜기로 rb.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic; // 설정을 바꿀거에요 -> 연속 충돌 감지로 rb.velocity = shootDirection * speed; // 값을 넣을거에요 -> 방향과 속도를 곱해 물리 속도로 } Destroy(gameObject, 5f); // 파괴할거에요 -> 5초 뒤에 안전장치로 } /// /// [하위 호환성] 기존 7-파라미터 버전도 유지 (외부에서 직접 수치를 넘기는 경우) /// public void Initialize( float dmg, float arrowSpeed, float maxRange, Vector3 direction, ArrowElementType element, float elemDmg, float elemDur) // 함수를 선언할거에요 -> 구버전 호환용 7-파라미터 초기화 함수를 { Initialize(dmg, arrowSpeed, maxRange, direction, element); // 실행할거에요 -> 새 5-파라미터 초기화를 (인스펙터 값 사용) } /// /// [하위 호환성] 방향 없는 3-파라미터 버전 /// public void Initialize(float dmg, float arrowSpeed, float maxRange) // 함수를 선언할거에요 -> 구버전 호환용 3-파라미터 초기화 함수를 { Initialize(dmg, arrowSpeed, maxRange, transform.forward, ArrowElementType.None); // 실행할거에요 -> 신버전 초기화를 기본값으로 } /// /// [NEW] 속성 타입에 맞는 인스펙터 설정 데이터를 반환 /// private ElementEffectData GetElementData(ArrowElementType element) // 함수를 선언할거에요 -> 속성 데이터를 가져오는 GetElementData를 { switch (element) // 분기할거에요 -> 속성 타입에 따라 { case ArrowElementType.Fire: return fireEffect; // 반환할거에요 -> 불 속성 설정값을 case ArrowElementType.Ice: return iceEffect; // 반환할거에요 -> 얼음 속성 설정값을 case ArrowElementType.Poison: return poisonEffect; // 반환할거에요 -> 독 속성 설정값을 case ArrowElementType.Lightning: return lightningEffect; // 반환할거에요 -> 전기 속성 설정값을 default: return null; // 반환할거에요 -> 없음 (일반 화살) } } private void Update() // 함수를 실행할거에요 -> 매 프레임마다 Update를 { if (!isFired || hasHit) return; // 조건이 맞으면 중단할거에요 -> 발사되지 않았거나 이미 맞았다면 // 사거리 체크 float traveledDistance = Vector3.Distance(startPos, transform.position); // 거리를 계산할거에요 -> 이동 거리를 if (traveledDistance >= range) // 조건이 맞으면 실행할거에요 -> 사거리를 넘었다면 { Destroy(gameObject); // 파괴할거에요 -> 화살을 return; // 중단할거에요 -> 함수를 } // 정밀 충돌 감지 CheckPrecisionCollision(); // 함수를 실행할거에요 -> 정밀 충돌 감지 함수를 previousPosition = transform.position; // 값을 저장할거에요 -> 현재 위치를 이전 위치로 } /// /// SphereCast 기반 정밀 충돌 (기존 로직 100% 유지) /// private void CheckPrecisionCollision() // 함수를 선언할거에요 -> 정밀 충돌을 체크하는 CheckPrecisionCollision을 { Vector3 tipPosition = arrowTip != null ? arrowTip.position : transform.position; // 위치를 결정할거에요 -> 팁 위치 혹은 내 위치를 Vector3 direction = rb != null && rb.velocity.magnitude > 0.1f ? rb.velocity.normalized : transform.forward; // 방향을 결정할거에요 -> 물리 속도 방향 혹은 정면을 float frameDistance = Vector3.Distance(previousPosition, transform.position); // 거리를 계산할거에요 -> 프레임 간 이동 거리를 float checkDistance = Mathf.Max(frameDistance, raycastDistance); // 값을 결정할거에요 -> 이동 거리와 최소 거리 중 큰 값을 RaycastHit hit; // 변수를 선언할거에요 -> 충돌 정보를 담을 hit을 bool didHit = Physics.SphereCast( tipPosition, raycastRadius, direction, out hit, checkDistance, hitLayers ); // 실행할거에요 -> 구체 캐스트를 쏴서 충돌 여부를 확인하는 것을 if (showDebugRay) // 조건이 맞으면 실행할거에요 -> 디버그 모드라면 { Debug.DrawRay(tipPosition, direction * checkDistance, didHit ? Color.red : Color.green, 0.1f); // 선을 그릴거에요 -> 충돌 시 빨강, 아니면 초록으로 } if (didHit) // 조건이 맞으면 실행할거에요 -> 충돌했다면 { HandleHit(hit.collider, hit.point); // 실행할거에요 -> 충돌 처리 함수 HandleHit을 } } /// /// [UPGRADED] 충돌 처리 — 인스펙터 설정값 기반 속성 데미지 적용 /// private void HandleHit(Collider hitCollider, Vector3 hitPoint) // 함수를 선언할거에요 -> 충돌 결과를 처리하는 HandleHit을 { if (hasHit) return; // 조건이 맞으면 중단할거에요 -> 이미 충돌 처리되었다면 hasHit = true; // 상태를 바꿀거에요 -> 충돌 처리됨으로 // 적 감지 (Tag 또는 Layer) bool isEnemy = hitCollider.CompareTag("Enemy"); // 조건을 확인할거에요 -> 적 태그인지 // EnemyHitBox 레이어 체크 (레이어가 존재하는 경우에만) int enemyHitBoxLayerIndex = LayerMask.NameToLayer("EnemyHitBox"); // 값을 가져올거에요 -> 레이어 인덱스를 if (!isEnemy && enemyHitBoxLayerIndex != -1) // 조건이 맞으면 실행할거에요 -> 적 태그가 아니고 레이어가 유효하다면 { isEnemy = hitCollider.gameObject.layer == enemyHitBoxLayerIndex; // 조건을 갱신할거에요 -> 해당 레이어인지 확인해서 } if (isEnemy) // 조건이 맞으면 실행할거에요 -> 적이라면 { // MonsterClass를 찾아 데미지 적용 MonsterClass monster = hitCollider.GetComponentInParent(); // 컴포넌트를 찾을거에요 -> 부모의 몬스터 클래스를 if (monster == null) monster = hitCollider.GetComponent(); // 없으면 찾을거에요 -> 자신의 몬스터 클래스를 if (monster != null) // 조건이 맞으면 실행할거에요 -> 몬스터 스크립트가 있다면 { // 1. 최종 데미지 적용 (기본 + 속성 보너스가 이미 합산됨) monster.TakeDamage(damage); // 실행할거에요 -> 최종 데미지를 입히는 함수를 Debug.Log($"[Arrow] 적 명중! 최종 데미지: {damage} | 속성: {currentElement}"); // 로그를 출력할거에요 -> 명중 메시지를 // 2. [UPGRADED] 속성 지속 효과(DoT) 적용 — 인스펙터 설정값 사용 ApplyElementEffect(monster); // 실행할거에요 -> 속성 효과 적용 함수를 } Destroy(gameObject, 0.05f); // 파괴할거에요 -> 화살을 잠시 뒤 } else if (hitCollider.CompareTag("Wall") || hitCollider.CompareTag("Ground")) // 조건이 틀리면 실행할거에요 -> 벽이나 땅이라면 { Debug.Log($"벽/바닥 충돌! 위치: {hitPoint}"); // 로그를 출력할거에요 -> 충돌 위치를 Destroy(gameObject, 0.05f); // 파괴할거에요 -> 화살을 } else // 조건이 틀리면 실행할거에요 -> 그 외의 충돌이라면 { Destroy(gameObject, 0.05f); // 파괴할거에요 -> 화살을 } } /// /// [UPGRADED] 속성 효과 적용 — 인스펙터에서 설정한 값을 직접 사용 /// MonsterClass에 ApplyStatusEffect(StatusEffectType, float dotDmg, float duration, float tickInterval, float strength) /// 오버로드가 필요합니다. /// private void ApplyElementEffect(MonsterClass monster) // 함수를 선언할거에요 -> 속성 효과를 적용하는 ApplyElementEffect를 { if (currentElement == ArrowElementType.None) return; // 조건이 맞으면 중단할거에요 -> 일반 화살이라면 ElementEffectData data = GetElementData(currentElement); // 데이터를 가져올거에요 -> 현재 속성의 인스펙터 설정값을 if (data == null || !data.enabled) return; // 조건이 맞으면 중단할거에요 -> 설정이 없거나 비활성이라면 switch (currentElement) // 분기할거에요 -> 속성 타입에 따라 { case ArrowElementType.Fire: // 조건이 맞으면 실행할거에요 -> 불 속성이라면 monster.ApplyStatusEffect( // 실행할거에요 -> 화상 상태이상을 적용하는 함수를 StatusEffectType.Burn, // 인자를 전달할거에요 -> 화상 타입을 data.dotDamagePerTick, // 인자를 전달할거에요 -> 틱당 데미지를 (인스펙터 값) data.dotDuration, // 인자를 전달할거에요 -> 지속 시간을 (인스펙터 값) data.dotTickInterval, // 인자를 전달할거에요 -> 틱 간격을 (인스펙터 값) data.effectStrength // 인자를 전달할거에요 -> 효과 강도를 (인스펙터 값) ); Debug.Log($"[Arrow] 🔥 화염! 틱당:{data.dotDamagePerTick} x {data.dotDuration}초 (간격:{data.dotTickInterval}초)"); // 로그를 출력할거에요 -> 화상 효과 내역을 break; // 분기를 종료할거에요 case ArrowElementType.Ice: // 조건이 맞으면 실행할거에요 -> 얼음 속성이라면 monster.ApplyStatusEffect( // 실행할거에요 -> 슬로우 상태이상을 적용하는 함수를 StatusEffectType.Slow, // 인자를 전달할거에요 -> 슬로우 타입을 data.dotDamagePerTick, // 인자를 전달할거에요 -> 틱당 데미지를 (얼음은 보통 0) data.dotDuration, // 인자를 전달할거에요 -> 슬로우 지속 시간을 data.dotTickInterval, // 인자를 전달할거에요 -> 틱 간격을 data.effectStrength // 인자를 전달할거에요 -> 슬로우 비율을 (0.5면 50% 감속) ); Debug.Log($"[Arrow] ❄️ 빙결! 슬로우:{data.effectStrength * 100}% x {data.dotDuration}초"); // 로그를 출력할거에요 -> 빙결 효과 내역을 break; // 분기를 종료할거에요 case ArrowElementType.Poison: // 조건이 맞으면 실행할거에요 -> 독 속성이라면 monster.ApplyStatusEffect( // 실행할거에요 -> 독 상태이상을 적용하는 함수를 StatusEffectType.Poison, // 인자를 전달할거에요 -> 독 타입을 data.dotDamagePerTick, // 인자를 전달할거에요 -> 틱당 독 데미지를 data.dotDuration, // 인자를 전달할거에요 -> 독 지속 시간을 data.dotTickInterval, // 인자를 전달할거에요 -> 틱 간격을 data.effectStrength // 인자를 전달할거에요 -> 효과 강도를 ); Debug.Log($"[Arrow] ☠️ 독! 틱당:{data.dotDamagePerTick} x {data.dotDuration}초 (간격:{data.dotTickInterval}초)"); // 로그를 출력할거에요 -> 독 효과 내역을 break; // 분기를 종료할거에요 case ArrowElementType.Lightning: // 조건이 맞으면 실행할거에요 -> 전기 속성이라면 monster.ApplyStatusEffect( // 실행할거에요 -> 감전(스턴) 상태이상을 적용하는 함수를 StatusEffectType.Shock, // 인자를 전달할거에요 -> 감전 타입을 data.dotDamagePerTick, // 인자를 전달할거에요 -> 틱당 데미지를 (전기는 보통 0) data.dotDuration, // 인자를 전달할거에요 -> 스턴 지속 시간을 data.dotTickInterval, // 인자를 전달할거에요 -> 틱 간격을 data.effectStrength // 인자를 전달할거에요 -> 스턴 시간을 ); Debug.Log($"[Arrow] ⚡ 감전! 스턴:{data.effectStrength}초 | 추가데미지:{data.bonusDamage}"); // 로그를 출력할거에요 -> 감전 효과 내역을 break; // 분기를 종료할거에요 } } /// /// 백업 충돌 감지 (OnTriggerEnter) — 기존 로직 유지 /// private void OnTriggerEnter(Collider other) // 함수를 실행할거에요 -> 트리거 충돌 시 OnTriggerEnter를 { if (hasHit) return; // 조건이 맞으면 중단할거에요 -> 이미 맞았다면 bool isEnemy = other.CompareTag("Enemy"); // 조건을 확인할거에요 -> 적 태그인지 int enemyHitBoxLayerIndex = LayerMask.NameToLayer("EnemyHitBox"); // 값을 가져올거에요 -> 히트박스 레이어 인덱스를 if (!isEnemy && enemyHitBoxLayerIndex != -1) // 조건이 맞으면 실행할거에요 -> 적 태그가 아니고 레이어가 유효하다면 { isEnemy = other.gameObject.layer == enemyHitBoxLayerIndex; // 조건을 갱신할거에요 -> 레이어 확인으로 } if (isEnemy) // 조건이 맞으면 실행할거에요 -> 적이라면 { HandleHit(other, other.ClosestPoint(transform.position)); // 실행할거에요 -> 충돌 처리 함수를 } else if (other.CompareTag("Wall") || other.CompareTag("Ground")) // 조건이 틀리면 실행할거에요 -> 벽이나 땅이라면 { hasHit = true; // 상태를 바꿀거에요 -> 충돌 처리됨으로 Destroy(gameObject, 0.05f); // 파괴할거에요 -> 화살을 } } /// /// [PUBLIC] 외부에서 인스펙터 속성 데이터를 읽을 수 있는 접근자 /// UI 등에서 속성 정보를 표시할 때 사용 /// public ElementEffectData GetCurrentElementData() // 함수를 선언할거에요 -> 현재 속성 데이터를 반환하는 접근자를 { return GetElementData(currentElement); // 반환할거에요 -> 현재 속성의 설정 데이터를 } /// /// [PUBLIC] 현재 속성 타입 반환 /// public ArrowElementType GetCurrentElement() // 함수를 선언할거에요 -> 현재 속성 타입을 반환하는 접근자를 { return currentElement; // 반환할거에요 -> 현재 속성 타입을 } /// /// Gizmo 디버그 시각화 — 기존 로직 유지 + 속성 색상 추가 /// private void OnDrawGizmos() // 함수를 실행할거에요 -> 기즈모를 그리는 OnDrawGizmos를 { if (!Application.isPlaying || !isFired || !showDebugRay) return; // 조건이 맞으면 중단할거에요 -> 실행 중이 아니거나 발사 전이거나 디버그가 꺼졌다면 Vector3 tipPosition = arrowTip != null ? arrowTip.position : transform.position; // 위치를 결정할거에요 -> 팁 위치 혹은 내 위치로 Vector3 direction = rb != null && rb.velocity.magnitude > 0.1f ? rb.velocity.normalized : transform.forward; // 방향을 결정할거에요 -> 물리 속도 방향 혹은 정면으로 Gizmos.color = hasHit ? Color.red : Color.green; // 색상을 설정할거에요 -> 맞았으면 빨강, 아니면 초록으로 Gizmos.DrawWireSphere(tipPosition, raycastRadius); // 그림을 그릴거에요 -> 팁 위치에 구체를 Gizmos.DrawWireSphere(tipPosition + direction * raycastDistance, raycastRadius); // 그림을 그릴거에요 -> 예상 도달 위치에 구체를 Gizmos.color = Color.yellow; // 색상을 설정할거에요 -> 노란색으로 Gizmos.DrawLine(tipPosition, tipPosition + direction * raycastDistance); // 선을 그릴거에요 -> 궤적을 표시하는 // 속성별 색상 표시 switch (currentElement) // 분기할거에요 -> 속성 타입에 따라 { case ArrowElementType.Fire: Gizmos.color = Color.red; break; // 색상을 바꿀거에요 -> 빨강으로 case ArrowElementType.Ice: Gizmos.color = Color.cyan; break; // 색상을 바꿀거에요 -> 청록으로 case ArrowElementType.Poison: Gizmos.color = Color.green; break; // 색상을 바꿀거에요 -> 초록으로 case ArrowElementType.Lightning: Gizmos.color = Color.yellow; break; // 색상을 바꿀거에요 -> 노랑으로 } if (currentElement != ArrowElementType.None) // 조건이 맞으면 실행할거에요 -> 속성이 있다면 { Gizmos.DrawWireSphere(transform.position, 0.5f); // 그림을 그릴거에요 -> 속성 표시용 구체를 } } }