2026-02-20 16:39:14 +00:00
|
|
|
|
using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을
|
2026-02-13 09:11:54 +00:00
|
|
|
|
using System.Collections; // 코루틴을 사용할거에요 -> System.Collections를
|
2026-02-04 14:06:25 +00:00
|
|
|
|
|
2026-02-13 09:11:54 +00:00
|
|
|
|
public class ChargeMonster : MonsterClass // 클래스를 선언할거에요 -> 돌진 몬스터를
|
2026-02-04 14:06:25 +00:00
|
|
|
|
{
|
2026-02-13 09:11:54 +00:00
|
|
|
|
[Header("=== 돌진 설정 ===")] // 인스펙터 제목을 달거에요 -> 돌진 설정을
|
2026-02-19 18:14:55 +00:00
|
|
|
|
[SerializeField] private float chargeSpeed = 15f; // 변수를 선언할거에요 -> 돌진 속도를
|
|
|
|
|
|
[SerializeField] private float chargeRange = 10f; // 변수를 선언할거에요 -> 돌진 감지 거리를
|
|
|
|
|
|
[SerializeField] private float chargeDuration = 2f; // 변수를 선언할거에요 -> 돌진 지속 시간을
|
|
|
|
|
|
[SerializeField] private float chargeDelay = 3f; // 변수를 선언할거에요 -> 돌진 쿨타임을
|
|
|
|
|
|
[SerializeField] private float prepareTime = 0.5f; // 변수를 선언할거에요 -> 돌진 준비 시간을
|
2026-02-25 10:39:20 +00:00
|
|
|
|
[Tooltip("돌진 중 플레이어 추적 회전 속도 (낮을수록 둔하게 추적, 높을수록 예리하게 추적)")]
|
|
|
|
|
|
[SerializeField] private float chargeTrackingSpeed = 5f; // 변수를 선언할거에요 -> 돌진 중 실시간 추적 회전 속도를
|
2026-02-13 09:11:54 +00:00
|
|
|
|
|
2026-02-19 18:14:55 +00:00
|
|
|
|
[Header("애니메이션")] // 인스펙터 제목을 달거에요 -> 애니메이션 State 이름을
|
|
|
|
|
|
[SerializeField] private string chargeAnim = "Run-run"; // 변수를 선언할거에요 -> 돌진 State 이름을
|
|
|
|
|
|
[SerializeField] private string prepareAnim = "Run-wait"; // 변수를 선언할거에요 -> 준비 State 이름을
|
|
|
|
|
|
[SerializeField] private string walkAnim = "Run-walk"; // 변수를 선언할거에요 -> 걷기 State 이름을
|
2026-02-13 09:11:54 +00:00
|
|
|
|
|
2026-02-19 18:14:55 +00:00
|
|
|
|
private float lastChargeTime; // 변수를 선언할거에요 -> 마지막 돌진 시간을
|
|
|
|
|
|
private bool isCharging; // 변수를 선언할거에요 -> 돌진 중 여부를
|
|
|
|
|
|
private bool isPreparing; // 변수를 선언할거에요 -> 돌진 준비 중 여부를
|
|
|
|
|
|
private Rigidbody _rb; // 변수를 선언할거에요 -> 리지드바디를
|
|
|
|
|
|
private string _lastLoggedState = ""; // 변수를 선언할거에요 -> 직전 로그 State 이름을
|
|
|
|
|
|
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
// 초기화
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
2026-02-13 09:11:54 +00:00
|
|
|
|
|
|
|
|
|
|
protected override void Awake() // 함수를 실행할거에요 -> 초기화 Awake를
|
2026-02-04 14:06:25 +00:00
|
|
|
|
{
|
2026-02-19 18:14:55 +00:00
|
|
|
|
base.Awake(); // 실행할거에요 -> 부모 Awake를
|
2026-02-13 09:11:54 +00:00
|
|
|
|
_rb = GetComponent<Rigidbody>(); // 가져올거에요 -> 리지드바디를
|
|
|
|
|
|
if (_rb == null) _rb = gameObject.AddComponent<Rigidbody>(); // 추가할거에요 -> 없으면 새로
|
|
|
|
|
|
_rb.isKinematic = true; // 끌거에요 -> 물리 연산을
|
2026-02-04 14:06:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-19 18:14:55 +00:00
|
|
|
|
protected override void Init() // 함수를 실행할거에요 -> 추가 초기화를
|
|
|
|
|
|
{
|
|
|
|
|
|
if (agent != null) agent.stoppingDistance = 1f; // 설정할거에요 -> 정지 거리를
|
|
|
|
|
|
isCharging = false; // 초기화할거에요 -> 돌진 상태를
|
|
|
|
|
|
isPreparing = false; // 초기화할거에요 -> 준비 상태를
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
// 디버그 State 감시
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
public override void OnManagedUpdate() // 함수를 정의할거에요 -> 매 프레임 상태 감시를
|
|
|
|
|
|
{
|
|
|
|
|
|
base.OnManagedUpdate(); // 실행할거에요 -> 부모 업데이트를
|
|
|
|
|
|
|
|
|
|
|
|
if (!showChargeDebugLog || animator == null) return; // 중단할거에요 -> 디버그 꺼져있으면
|
|
|
|
|
|
|
|
|
|
|
|
AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(0); // 가져올거에요 -> 현재 State 정보를
|
|
|
|
|
|
string cur;
|
|
|
|
|
|
if (info.IsName(prepareAnim)) cur = prepareAnim;
|
|
|
|
|
|
else if (info.IsName(chargeAnim)) cur = chargeAnim;
|
|
|
|
|
|
else if (info.IsName(walkAnim)) cur = walkAnim;
|
|
|
|
|
|
else if (info.IsName(Monster_Idle)) cur = Monster_Idle;
|
|
|
|
|
|
else if (info.IsName(Monster_GetDamage)) cur = Monster_GetDamage;
|
|
|
|
|
|
else if (info.IsName(Monster_Die)) cur = Monster_Die;
|
|
|
|
|
|
else cur = $"UNKNOWN({info.fullPathHash})";
|
|
|
|
|
|
|
|
|
|
|
|
if (cur == _lastLoggedState) return; // 중단할거에요 -> 같은 State면 중복 출력 안 함
|
|
|
|
|
|
_lastLoggedState = cur; // 저장할거에요 -> 현재 State를
|
|
|
|
|
|
|
|
|
|
|
|
Debug.Log(
|
|
|
|
|
|
$"[ChargeMonster] 🎬 {cur}\n" +
|
|
|
|
|
|
$" isHit={isHit} | isPreparing={isPreparing} | isCharging={isCharging} | isAttacking={isAttacking} | isResting={isResting}\n" +
|
|
|
|
|
|
$" agent.enabled={agent?.enabled} | rb.isKinematic={_rb?.isKinematic}"
|
|
|
|
|
|
); // 출력할거에요 -> State + 상태 변수들을
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
// ⭐ 피격 처리 오버라이드
|
|
|
|
|
|
//
|
|
|
|
|
|
// 돌진 준비(isPreparing) 중 피격
|
|
|
|
|
|
// → StopChargingRoutine()으로 코루틴 종료 + 상태 정리
|
|
|
|
|
|
// → base.TakeDamage()로 체력 감소 + 히트 애니 처리
|
|
|
|
|
|
//
|
|
|
|
|
|
// 돌진 중(isCharging) 피격 (슈퍼아머)
|
|
|
|
|
|
// → ApplyDamageOnly()로 체력 감소 + UI만
|
|
|
|
|
|
// → 히트 애니/멈춤 없음
|
|
|
|
|
|
//
|
|
|
|
|
|
// 일반 상태 피격
|
|
|
|
|
|
// → base.TakeDamage() 그대로
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
public override void TakeDamage(float amount) // 함수를 정의할거에요 -> 피격 처리 오버라이드를
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isDead) return; // 중단할거에요 -> 이미 죽었으면
|
|
|
|
|
|
|
|
|
|
|
|
// ── 돌진 중 슈퍼아머 ──────────────────────────────────
|
|
|
|
|
|
if (isCharging) // 조건이 맞으면 실행할거에요 -> 돌진 중이면
|
|
|
|
|
|
{
|
|
|
|
|
|
if (showChargeDebugLog)
|
|
|
|
|
|
Debug.Log($"[ChargeMonster] 🛡️ 슈퍼아머 — 데미지만 ({amount})"); // 출력할거에요
|
|
|
|
|
|
|
|
|
|
|
|
// ⭐ ApplyDamageOnly: 체력 감소 + UI만, StartHit() 호출 없음
|
|
|
|
|
|
ApplyDamageOnly(amount); // 실행할거에요 -> 체력 감소와 UI만 처리를
|
|
|
|
|
|
|
|
|
|
|
|
if (currentHP <= 0) // 조건이 맞으면 실행할거에요 -> 사망했으면
|
|
|
|
|
|
{
|
|
|
|
|
|
StopChargingRoutine(); // 실행할거에요 -> 돌진 정리를
|
|
|
|
|
|
Die(); // 실행할거에요 -> 사망 처리를
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 이펙트/소리만 (애니/상태 변화 없음)
|
|
|
|
|
|
if (hitEffect != null) hitEffect.Play(); // 재생할거에요 -> 피격 이펙트를
|
|
|
|
|
|
if (hitSound != null && audioSource != null) audioSource.PlayOneShot(hitSound); // 재생할거에요 -> 소리를
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ── 돌진 준비 중 피격 → 돌진 취소 + 일반 히트 ─────────
|
|
|
|
|
|
if (isPreparing) // 조건이 맞으면 실행할거에요 -> 준비 중이면
|
|
|
|
|
|
{
|
|
|
|
|
|
if (showChargeDebugLog)
|
|
|
|
|
|
Debug.Log($"[ChargeMonster] ⛔ 준비 중 피격 — 돌진 취소"); // 출력할거에요
|
|
|
|
|
|
|
|
|
|
|
|
StopChargingRoutine(); // 실행할거에요 -> 준비 코루틴 종료 + 상태 정리를
|
|
|
|
|
|
// 이후 base.TakeDamage()로 일반 피격 처리
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ── 일반 피격 ─────────────────────────────────────────
|
|
|
|
|
|
base.TakeDamage(amount); // 실행할거에요 -> 체력 감소 + StartHit() 호출을
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
// 돌진 코루틴만 종료 (StopAllCoroutines 사용 안 함)
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
private Coroutine _chargeCoroutine; // 변수를 선언할거에요 -> 돌진 코루틴 핸들을
|
|
|
|
|
|
|
2026-02-20 16:39:14 +00:00
|
|
|
|
[Header("=== 디버그 ===")] // 인스펙터 제목을 달거에요 -> 디버그 설정을
|
|
|
|
|
|
[SerializeField] private bool showChargeDebugLog = true; // 변수를 선언할거에요 -> 디버그 로그 on/off를
|
|
|
|
|
|
|
2026-02-19 18:14:55 +00:00
|
|
|
|
private void StopChargingRoutine() // 함수를 선언할거에요 -> 돌진 코루틴만 종료를
|
|
|
|
|
|
{
|
|
|
|
|
|
// ⭐ StopAllCoroutines() 사용 안 함
|
|
|
|
|
|
// HitRoutine 등 다른 코루틴은 건드리지 않음
|
|
|
|
|
|
if (_chargeCoroutine != null) // 조건이 맞으면 실행할거에요 -> 돌진 코루틴이 있으면
|
|
|
|
|
|
{
|
|
|
|
|
|
StopCoroutine(_chargeCoroutine); // 취소할거에요 -> 돌진 코루틴만
|
|
|
|
|
|
_chargeCoroutine = null; // 초기화할거에요 -> 핸들을
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (_rb != null) // 조건이 맞으면 실행할거에요 -> 리지드바디가 있으면
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_rb.isKinematic) _rb.velocity = Vector3.zero; // 멈출거에요 -> 돌진 중일 때만 속도를
|
|
|
|
|
|
_rb.isKinematic = true; // 끌거에요 -> 물리 연산을
|
|
|
|
|
|
}
|
|
|
|
|
|
if (agent != null && !agent.enabled) // 조건이 맞으면 실행할거에요 -> 에이전트가 꺼져있으면
|
|
|
|
|
|
agent.enabled = true; // 켤거에요 -> 에이전트를
|
|
|
|
|
|
|
|
|
|
|
|
isPreparing = false; // 해제할거에요 -> 준비 상태를
|
|
|
|
|
|
isCharging = false; // 해제할거에요 -> 돌진 상태를
|
|
|
|
|
|
isAttacking = false; // 해제할거에요 -> 공격 상태를
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
// AI 로직
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
2026-02-04 14:06:25 +00:00
|
|
|
|
|
2026-02-13 09:11:54 +00:00
|
|
|
|
protected override void ExecuteAILogic() // 함수를 실행할거에요 -> AI 로직을
|
2026-02-04 14:06:25 +00:00
|
|
|
|
{
|
2026-02-19 18:14:55 +00:00
|
|
|
|
if (isHit || isCharging || isPreparing || isAttacking || isResting) return; // 중단할거에요 -> 행동 불가 상태면
|
|
|
|
|
|
|
2026-02-13 09:11:54 +00:00
|
|
|
|
float dist = Vector3.Distance(transform.position, playerTransform.position); // 계산할거에요 -> 거리를
|
2026-02-19 18:14:55 +00:00
|
|
|
|
|
|
|
|
|
|
if (dist <= chargeRange && Time.time >= lastChargeTime + chargeDelay) // 조건이 맞으면 실행할거에요 -> 돌진 가능하면
|
|
|
|
|
|
{
|
|
|
|
|
|
_chargeCoroutine = StartCoroutine(ChargeRoutine()); // 실행할거에요 -> 돌진 코루틴을 (핸들 저장)
|
|
|
|
|
|
}
|
|
|
|
|
|
else // 조건이 틀리면 실행할거에요 -> 일반 추격
|
|
|
|
|
|
{
|
|
|
|
|
|
ChasePlayer(); // 실행할거에요 -> 추격을
|
|
|
|
|
|
}
|
2026-02-04 14:06:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-13 09:11:54 +00:00
|
|
|
|
private void ChasePlayer() // 함수를 선언할거에요 -> 추격 로직을
|
2026-02-04 14:06:25 +00:00
|
|
|
|
{
|
2026-02-19 18:14:55 +00:00
|
|
|
|
if (agent != null && agent.isOnNavMesh) // 조건이 맞으면 실행할거에요 -> 에이전트가 정상이면
|
|
|
|
|
|
{
|
|
|
|
|
|
agent.isStopped = false; // 켤거에요 -> 이동을
|
|
|
|
|
|
agent.SetDestination(playerTransform.position); // 설정할거에요 -> 목적지를
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!animator.GetCurrentAnimatorStateInfo(0).IsName(walkAnim)) // 조건이 맞으면 실행할거에요 -> 걷기 아니면
|
|
|
|
|
|
animator.Play(walkAnim, 0, 0f); // 재생할거에요 -> 걷기 애니를
|
2026-02-04 14:06:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-19 18:14:55 +00:00
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
// 돌진 코루틴
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
private IEnumerator ChargeRoutine() // 코루틴을 정의할거에요 -> 돌진 전체 과정을
|
2026-02-04 14:06:25 +00:00
|
|
|
|
{
|
2026-02-19 18:14:55 +00:00
|
|
|
|
// ── 준비 단계 ──────────────────────────────────────────
|
|
|
|
|
|
isPreparing = true; // 설정할거에요 -> 준비 중으로
|
|
|
|
|
|
isAttacking = true; // 설정할거에요 -> 공격 중으로
|
|
|
|
|
|
agent.isStopped = true; // 멈출거에요 -> 이동을
|
|
|
|
|
|
|
|
|
|
|
|
Vector3 dir = (playerTransform.position - transform.position).normalized; // 계산할거에요 -> 방향을
|
|
|
|
|
|
dir.y = 0f; // 무시할거에요 -> 수직 성분을
|
|
|
|
|
|
transform.rotation = Quaternion.LookRotation(dir); // 회전할거에요 -> 플레이어 방향으로
|
|
|
|
|
|
|
|
|
|
|
|
if (showChargeDebugLog) Debug.Log($"[ChargeMonster] ⏳ 돌진 준비 시작"); // 출력할거에요
|
2026-02-04 14:06:25 +00:00
|
|
|
|
|
2026-02-19 18:14:55 +00:00
|
|
|
|
animator.Play(prepareAnim, 0, 0f); // 재생할거에요 -> 준비 애니를
|
2026-02-12 15:23:25 +00:00
|
|
|
|
yield return new WaitForSeconds(prepareTime); // 기다릴거에요 -> 준비 시간만큼
|
2026-02-04 14:06:25 +00:00
|
|
|
|
|
2026-02-19 18:14:55 +00:00
|
|
|
|
// 준비 중 피격으로 isPreparing이 false가 됐으면 종료
|
|
|
|
|
|
// (TakeDamage → StopChargingRoutine에서 이미 상태 정리됨)
|
|
|
|
|
|
if (!isPreparing) // 조건이 맞으면 실행할거에요 -> 준비가 취소됐으면
|
|
|
|
|
|
{
|
|
|
|
|
|
if (showChargeDebugLog) Debug.Log($"[ChargeMonster] ⛔ 준비 취소 감지 — 코루틴 종료"); // 출력할거에요
|
|
|
|
|
|
_chargeCoroutine = null; // 초기화할거에요 -> 핸들을
|
|
|
|
|
|
yield break; // 중단할거에요
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ── 돌진 단계 ──────────────────────────────────────────
|
|
|
|
|
|
isPreparing = false; // 해제할거에요 -> 준비 상태를
|
|
|
|
|
|
isCharging = true; // 설정할거에요 -> 돌진 중으로
|
|
|
|
|
|
lastChargeTime = Time.time; // 기록할거에요 -> 마지막 돌진 시간을
|
|
|
|
|
|
agent.enabled = false; // 끌거에요 -> NavMesh를 (물리 이동 위해)
|
|
|
|
|
|
_rb.isKinematic = false; // 켤거에요 -> 물리 연산을
|
|
|
|
|
|
|
|
|
|
|
|
if (showChargeDebugLog) Debug.Log($"[ChargeMonster] ⚡ 돌진 시작"); // 출력할거에요
|
|
|
|
|
|
|
|
|
|
|
|
animator.Play(chargeAnim, 0, 0f); // 재생할거에요 -> 돌진 애니를
|
2026-02-05 15:42:48 +00:00
|
|
|
|
|
2026-02-13 09:11:54 +00:00
|
|
|
|
float elapsed = 0f; // 초기화할거에요 -> 경과 시간을
|
|
|
|
|
|
while (elapsed < chargeDuration) // 반복할거에요 -> 지속 시간 동안
|
2026-02-04 14:06:25 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
// ⭐ 실시간 추적 — 매 프레임 플레이어 방향으로 재계산
|
|
|
|
|
|
if (playerTransform != null) // 조건이 맞으면 실행할거에요 -> 플레이어가 존재하면
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3 toPlayer = (playerTransform.position - transform.position); // 계산할거에요 -> 플레이어 방향 벡터를
|
|
|
|
|
|
toPlayer.y = 0f; // 무시할거에요 -> 수직 성분을
|
|
|
|
|
|
|
|
|
|
|
|
if (toPlayer.sqrMagnitude > 0.01f) // 조건이 맞으면 실행할거에요 -> 방향이 유효하면 (0벡터 방지)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 방향 부드럽게 회전 (너무 급격한 방향 전환 방지)
|
|
|
|
|
|
Quaternion targetRot = Quaternion.LookRotation(toPlayer.normalized); // 계산할거에요 -> 목표 회전을
|
|
|
|
|
|
transform.rotation = Quaternion.Slerp( // 보간할거에요 -> 현재 회전에서 목표 회전으로 부드럽게
|
|
|
|
|
|
transform.rotation,
|
|
|
|
|
|
targetRot,
|
|
|
|
|
|
chargeTrackingSpeed * Time.deltaTime // 추적 속도 (Inspector에서 조절)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_rb.velocity = transform.forward * chargeSpeed; // 적용할거에요 -> 현재 방향으로 돌진 속도를
|
2026-02-19 18:14:55 +00:00
|
|
|
|
elapsed += Time.deltaTime; // 더할거에요 -> 경과 시간을
|
2026-02-12 15:23:25 +00:00
|
|
|
|
yield return null; // 대기할거에요 -> 다음 프레임까지
|
2026-02-04 14:06:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-19 18:14:55 +00:00
|
|
|
|
// ── 정상 종료 ──────────────────────────────────────────
|
|
|
|
|
|
if (!_rb.isKinematic) _rb.velocity = Vector3.zero; // 멈출거에요 -> 속도를
|
|
|
|
|
|
_rb.isKinematic = true; // 끌거에요 -> 물리 연산을
|
|
|
|
|
|
agent.enabled = true; // 켤거에요 -> NavMesh를
|
|
|
|
|
|
isCharging = false; // 해제할거에요 -> 돌진 상태를
|
|
|
|
|
|
_chargeCoroutine = null; // 초기화할거에요 -> 핸들을
|
|
|
|
|
|
|
|
|
|
|
|
if (showChargeDebugLog) Debug.Log($"[ChargeMonster] 🏁 돌진 정상 종료"); // 출력할거에요
|
|
|
|
|
|
|
|
|
|
|
|
OnAttackEnd(); // 실행할거에요 -> 공격 종료 처리를 (isAttacking=false + 휴식)
|
2026-02-04 14:06:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-19 18:14:55 +00:00
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
// 충돌 판정
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
|
2026-02-13 09:11:54 +00:00
|
|
|
|
private void OnCollisionEnter(Collision col) // 함수를 실행할거에요 -> 충돌 시
|
2026-02-04 14:06:25 +00:00
|
|
|
|
{
|
2026-02-19 18:14:55 +00:00
|
|
|
|
if (!isCharging) return; // 중단할거에요 -> 돌진 중이 아니면
|
|
|
|
|
|
if (!col.gameObject.CompareTag("Player")) return; // 중단할거에요 -> 플레이어가 아니면
|
|
|
|
|
|
|
|
|
|
|
|
IDamageable t = col.gameObject.GetComponent<IDamageable>(); // 가져올거에요 -> 데미지 인터페이스를
|
|
|
|
|
|
if (t != null) t.TakeDamage(attackDamage); // 입힐거에요 -> 데미지를
|
2026-02-25 10:39:20 +00:00
|
|
|
|
|
|
|
|
|
|
// ⭐ 경직 적용 — 돌진 충돌 시 플레이어를 n초 동안 움직이지 못하게
|
|
|
|
|
|
PlayerMovement pm = col.gameObject.GetComponent<PlayerMovement>(); // 가져올거에요 -> 플레이어 이동 스크립트를
|
|
|
|
|
|
if (pm != null) pm.ApplyStagger(); // 적용할거에요 -> 경직을 (PlayerMovement.staggerDuration 값 사용)
|
|
|
|
|
|
}
|
2026-02-19 18:14:55 +00:00
|
|
|
|
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
// 디버그 기즈모
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
protected override void OnDrawGizmosSelected() // 함수를 선언할거에요 -> 기즈모 오버라이드를
|
|
|
|
|
|
{
|
|
|
|
|
|
base.OnDrawGizmosSelected(); // 실행할거에요 -> 부모 기즈모를 먼저
|
|
|
|
|
|
|
|
|
|
|
|
if (!showDebugGizmos) return; // 중단할거에요 -> 기즈모 꺼져있으면
|
|
|
|
|
|
|
|
|
|
|
|
Gizmos.color = new Color(1f, 0.5f, 0f, 0.12f); // 설정할거에요 -> 주황 반투명을
|
|
|
|
|
|
Gizmos.DrawSphere(transform.position, chargeRange); // 그릴거에요 -> 돌진 범위 채우기를
|
|
|
|
|
|
Gizmos.color = new Color(1f, 0.5f, 0f, 1f); // 설정할거에요 -> 주황 외곽선을
|
|
|
|
|
|
Gizmos.DrawWireSphere(transform.position, chargeRange); // 그릴거에요 -> 돌진 범위 외곽선을
|
|
|
|
|
|
|
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
|
if (Application.isPlaying) // 조건이 맞으면 실행할거에요 -> 플레이 중이면
|
2026-02-06 09:27:08 +00:00
|
|
|
|
{
|
2026-02-19 18:14:55 +00:00
|
|
|
|
string label = isCharging ? "⚡ 돌진! (슈퍼아머)" : (isPreparing ? "⏳ 준비..." : ""); // 결정할거에요
|
|
|
|
|
|
if (!string.IsNullOrEmpty(label))
|
|
|
|
|
|
UnityEditor.Handles.Label(transform.position + Vector3.up * 0.5f, label); // 표시할거에요 -> 씬 뷰에
|
2026-02-04 14:06:25 +00:00
|
|
|
|
}
|
2026-02-19 18:14:55 +00:00
|
|
|
|
#endif
|
2026-02-04 14:06:25 +00:00
|
|
|
|
}
|
2026-02-05 15:42:48 +00:00
|
|
|
|
}
|