2026-02-12 15:23:25 +00:00
|
|
|
|
using UnityEngine; // 유니티 엔진의 기본 기능을 불러올거에요 -> UnityEngine을
|
|
|
|
|
|
using System.Collections; // 코루틴 기능을 사용할거에요 -> System.Collections를
|
2026-01-29 06:58:38 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
[RequireComponent(typeof(CharacterController))] // 컴포넌트를 강제로 추가할거에요 -> CharacterController를
|
|
|
|
|
|
public class PlayerMovement : MonoBehaviour // 클래스를 선언할거에요 -> PlayerMovement를
|
2026-01-29 06:58:38 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
[Header("=== 참조 ===")] // 인스펙터 창에 제목을 표시할거에요 -> 참조를
|
|
|
|
|
|
[SerializeField] private Stats stats; // 변수를 선언할거에요 -> 이동 속도 Stats를
|
|
|
|
|
|
[SerializeField] private PlayerHealth health; // 변수를 선언할거에요 -> 체력/피격 상태 PlayerHealth를
|
|
|
|
|
|
[SerializeField] private PlayerAnimator pAnim; // 변수를 선언할거에요 -> 애니메이션 제어 PlayerAnimator를
|
|
|
|
|
|
[SerializeField] private PlayerAttack attackScript; // 변수를 선언할거에요 -> 공격 상태 PlayerAttack를
|
|
|
|
|
|
[SerializeField] private PlayerSoundFX soundFX; // 변수를 선언할거에요 -> 사운드 스크립트를
|
2026-02-12 15:23:25 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
[Header("=== CharacterController ===")] // 인스펙터 창에 제목을 표시할거에요
|
|
|
|
|
|
private CharacterController _controller; // 변수를 선언할거에요 -> 이동 담당 CharacterController를
|
2026-02-12 15:23:25 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
[Header("=== 대시 설정 ===")] // 인스펙터 창에 제목을 표시할거에요
|
|
|
|
|
|
[SerializeField] private float dashDistance = 3f; // 변수를 선언할거에요 -> 대시 거리를
|
|
|
|
|
|
[SerializeField] private float dashDuration = 0.08f; // 변수를 선언할거에요 -> 대시 지속 시간을
|
|
|
|
|
|
[SerializeField] private float dashCooldown = 1.5f; // 변수를 선언할거에요 -> 대시 쿨타임을
|
2026-02-12 15:23:25 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
[Header("=== 차징 감속 설정 ===")] // 인스펙터 창에 제목을 표시할거에요
|
|
|
|
|
|
[Range(0.1f, 1f)]
|
|
|
|
|
|
[SerializeField] private float minSpeedMultiplier = 0.3f; // 변수를 선언할거에요 -> 차징 중 최소 속도 배율을
|
2026-02-12 15:23:25 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
[Header("=== 중력 설정 ===")] // 인스펙터 창에 제목을 표시할거에요
|
|
|
|
|
|
[SerializeField] private float gravity = -20f; // 변수를 선언할거에요 -> 중력 가속도를
|
2026-02-12 15:23:25 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
[Header("=== 충돌 설정 ===")] // 인스펙터 창에 제목을 표시할거에요
|
|
|
|
|
|
[Tooltip("무기 레이어 (이 레이어와는 충돌하지 않음)")]
|
|
|
|
|
|
[SerializeField] private LayerMask weaponLayer; // 변수를 선언할거에요 -> 충돌 무시할 무기 레이어를
|
2026-02-12 15:23:25 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
// ⭐ 경직 시스템
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
2026-02-02 10:48:45 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
[Header("=== 경직 설정 ===")] // 인스펙터 창에 제목을 표시할거에요 -> 경직 설정을
|
|
|
|
|
|
[Tooltip("돌진 몬스터 피격 시 경직 지속 시간 (초)")]
|
|
|
|
|
|
[SerializeField] private float staggerDuration = 0.8f; // 변수를 선언할거에요 -> 경직 지속 시간을 (Inspector에서 조절 가능)
|
2026-02-02 10:48:45 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private bool _isStaggered = false; // 변수를 선언할거에요 -> 현재 경직 상태인지 여부를
|
|
|
|
|
|
private Coroutine _staggerCoroutine = null; // 변수를 선언할거에요 -> 경직 코루틴 핸들을 (중복 방지용)
|
|
|
|
|
|
|
|
|
|
|
|
public bool IsStaggered => _isStaggered; // 프로퍼티를 선언할거에요 -> 경직 상태를 외부에서 읽을 수 있도록
|
|
|
|
|
|
public float StaggerDuration => staggerDuration; // 프로퍼티를 선언할거에요 -> 경직 지속 시간을 외부에서 읽을 수 있도록
|
|
|
|
|
|
|
|
|
|
|
|
[SerializeField] private StaggerIndicator staggerIndicator; // 변수를 선언할거에요 -> 경직 UI 연동용을
|
|
|
|
|
|
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
private Vector3 _moveDir; // 변수를 선언할거에요 -> 입력 이동 방향을
|
|
|
|
|
|
private bool _isSprinting; // 변수를 선언할거에요 -> 달리기 여부를
|
|
|
|
|
|
private bool _isDashing; // 변수를 선언할거에요 -> 대시 여부를
|
|
|
|
|
|
private float _lastDashTime; // 변수를 선언할거에요 -> 마지막 대시 시간을
|
|
|
|
|
|
private float _verticalVelocity; // 변수를 선언할거에요 -> 수직 낙하 속도를
|
|
|
|
|
|
|
|
|
|
|
|
[Header("=== 애니메이션 보간 ===")] // 인스펙터 창에 제목을 표시할거에요
|
2026-02-22 13:37:34 +00:00
|
|
|
|
[SerializeField] private float animSmoothSpeed = 8f; // 변수를 선언할거에요 -> 애니메이션 보간 속도를
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private float _currentAnimVal = 0f; // 변수를 초기화할거에요 -> 현재 보간 애니메이션 값을
|
2026-02-22 13:37:34 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private float _initialYPosition; // 변수를 선언할거에요 -> 시작 높이를
|
2026-02-02 15:02:12 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private void Awake() // 함수를 실행할거에요 -> 초기화를
|
2026-02-02 10:48:45 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
_controller = GetComponent<CharacterController>(); // 가져올거에요 -> CharacterController를
|
|
|
|
|
|
if (_controller == null) // 조건이 맞으면 실행할거에요 -> 없으면
|
|
|
|
|
|
Debug.LogError("[PlayerMovement] CharacterController가 필요합니다!"); // 에러를 출력할거에요
|
|
|
|
|
|
_initialYPosition = transform.position.y; // 저장할거에요 -> 초기 Y 위치를
|
|
|
|
|
|
}
|
2026-02-02 15:02:12 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private void Start() // 함수를 실행할거에요 -> 시작 시
|
|
|
|
|
|
{
|
|
|
|
|
|
SetupLayerCollision(); // 실행할거에요 -> 레이어 충돌 설정을
|
2026-02-02 15:02:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
// ⭐ 경직 적용 함수 — ChargeMonster 무기에서 호출
|
|
|
|
|
|
//
|
|
|
|
|
|
// 사용법:
|
|
|
|
|
|
// hit.GetComponent<PlayerMovement>()?.ApplyStagger();
|
|
|
|
|
|
// 또는 duration 직접 지정:
|
|
|
|
|
|
// hit.GetComponent<PlayerMovement>()?.ApplyStagger(1.2f);
|
|
|
|
|
|
// ─────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
public void ApplyStagger(float duration = -1f) // 함수를 선언할거에요 -> 외부에서 경직을 걸 때 호출할
|
2026-02-02 15:02:12 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
float actualDuration = duration > 0f ? duration : staggerDuration; // 결정할거에요 -> 인자가 있으면 그 값, 없으면 Inspector 기본값을
|
|
|
|
|
|
|
|
|
|
|
|
if (_staggerCoroutine != null) // 조건이 맞으면 실행할거에요 -> 이미 경직 중이면
|
|
|
|
|
|
StopCoroutine(_staggerCoroutine); // 멈출거에요 -> 이전 경직 코루틴을 (덮어쓰기)
|
|
|
|
|
|
|
|
|
|
|
|
_staggerCoroutine = StartCoroutine(StaggerRoutine(actualDuration)); // 시작할거에요 -> 새 경직 코루틴을
|
|
|
|
|
|
|
|
|
|
|
|
if (staggerIndicator != null) staggerIndicator.NotifyStagger(actualDuration); // 알릴거에요 -> UI에 경직 시작을
|
2026-02-02 15:02:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private IEnumerator StaggerRoutine(float duration) // 코루틴을 정의할거에요 -> 경직 지속 로직을
|
2026-02-02 15:02:12 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
_isStaggered = true; // 설정할거에요 -> 경직 상태를 true로
|
2026-02-02 15:02:12 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (pAnim != null) pAnim.UpdateMove(0f); // 멈출거에요 -> 이동 애니메이션을
|
|
|
|
|
|
|
|
|
|
|
|
yield return new WaitForSeconds(duration); // 기다릴거에요 -> 경직 시간만큼
|
|
|
|
|
|
|
|
|
|
|
|
_isStaggered = false; // 해제할거에요 -> 경직 상태를
|
|
|
|
|
|
_staggerCoroutine = null; // 초기화할거에요 -> 코루틴 핸들을
|
|
|
|
|
|
}
|
2026-02-03 14:41:49 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private void SetupLayerCollision() // 함수를 선언할거에요 -> 레이어 충돌 설정을
|
|
|
|
|
|
{
|
|
|
|
|
|
int playerLayer = gameObject.layer; // 가져올거에요 -> 내 레이어 번호를
|
|
|
|
|
|
if (weaponLayer != 0) // 조건이 맞으면 실행할거에요 -> 무기 레이어가 설정됐으면
|
|
|
|
|
|
{
|
|
|
|
|
|
int weaponLayerIndex = GetLayerFromMask(weaponLayer); // 변환할거에요 -> 마스크를 인덱스로
|
|
|
|
|
|
if (weaponLayerIndex >= 0) // 조건이 맞으면 실행할거에요 -> 유효한 인덱스면
|
2026-02-02 15:02:12 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
Physics.IgnoreLayerCollision(playerLayer, weaponLayerIndex, true); // 무시할거에요 -> 플레이어-무기 충돌을
|
|
|
|
|
|
Debug.Log($"[PlayerMovement] {LayerMask.LayerToName(playerLayer)}와 {LayerMask.LayerToName(weaponLayerIndex)} 간 충돌 무시 설정 완료"); // 출력할거에요
|
2026-02-02 15:02:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private int GetLayerFromMask(LayerMask mask) // 함수를 선언할거에요 -> 비트마스크를 인덱스로 변환할
|
2026-02-02 15:02:12 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
int layerNumber = 0; // 초기화할거에요 -> 레이어 번호를 0으로
|
|
|
|
|
|
int layer = mask.value; // 가져올거에요 -> 마스크 정수값을
|
|
|
|
|
|
while (layer > 1) // 반복할거에요 -> 1보다 클 동안
|
2026-02-02 15:02:12 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
layer = layer >> 1; // 밀거에요 -> 비트를 오른쪽으로
|
|
|
|
|
|
layerNumber++; // 증가할거에요 -> 레이어 번호를
|
2026-02-02 15:02:12 +00:00
|
|
|
|
}
|
2026-02-25 10:39:20 +00:00
|
|
|
|
return layerNumber; // 반환할거에요 -> 계산된 레이어 번호를
|
2026-02-02 10:48:45 +00:00
|
|
|
|
}
|
2026-01-29 06:58:38 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
public void SetMoveInput(Vector3 dir, bool sprint) // 함수를 선언할거에요 -> 이동 입력을 받을
|
2026-02-02 10:48:45 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
_moveDir = dir; // 저장할거에요 -> 이동 방향을
|
|
|
|
|
|
_isSprinting = sprint; // 저장할거에요 -> 달리기 여부를
|
2026-02-02 10:48:45 +00:00
|
|
|
|
}
|
2026-01-29 06:58:38 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
public void AttemptDash() // 함수를 선언할거에요 -> 대시를 시도할
|
2026-02-01 15:49:12 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (CanDash()) StartCoroutine(DashRoutine()); // 실행할거에요 -> 가능하면 대시 코루틴을
|
2026-02-01 15:49:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private bool CanDash() // 함수를 선언할거에요 -> 대시 가능 여부를 반환할
|
2026-02-01 15:49:12 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
bool isCooldownOver = Time.time >= _lastDashTime + dashCooldown; // 확인할거에요 -> 쿨타임이 지났는지를
|
|
|
|
|
|
bool isAlive = health != null && !health.IsDead; // 확인할거에요 -> 살아있는지를
|
|
|
|
|
|
return isCooldownOver && !_isDashing && isAlive; // 반환할거에요 -> 모두 만족할 때만 true를
|
2026-02-01 15:49:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private void Update() // 함수를 실행할거에요 -> 매 프레임마다
|
2026-01-29 06:58:38 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
// 1. 행동 불가 상태 체크
|
|
|
|
|
|
// ⭐ _isStaggered 추가 — 경직 중에도 이동 차단
|
|
|
|
|
|
if (health != null && (health.IsDead || health.isHit || _isDashing || _isStaggered)) // 조건이 맞으면 실행할거에요 -> 죽었거나, 피격이거나, 대시 중이거나, 경직 중이면
|
2026-01-29 06:58:38 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
// ⭐ 경직 중 공격 강제 취소 — 차징 포함
|
|
|
|
|
|
if (_isStaggered && attackScript != null) // 조건이 맞으면 실행할거에요 -> 경직 상태이고 공격 스크립트가 있으면
|
|
|
|
|
|
{
|
|
|
|
|
|
attackScript.CancelCharging(); // 취소할거에요 -> 차징을
|
|
|
|
|
|
attackScript.IsAttacking = false; // 해제할거에요 -> 공격 상태를
|
|
|
|
|
|
}
|
|
|
|
|
|
if (pAnim != null && !health.IsDead) pAnim.UpdateMove(0f); // 멈출거에요 -> 이동 애니메이션을
|
|
|
|
|
|
ApplyGravityOnly(); // 적용할거에요 -> 중력만
|
|
|
|
|
|
return; // 중단할거에요 -> 이동 코드를
|
2026-01-29 06:58:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-02 10:48:45 +00:00
|
|
|
|
// 2. 공격 중 이동 차단
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (attackScript != null && attackScript.IsAttacking) // 조건이 맞으면 실행할거에요 -> 공격 중이면
|
2026-01-30 07:45:11 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (pAnim != null) pAnim.UpdateMove(0f); // 멈출거에요 -> 이동 애니메이션을
|
|
|
|
|
|
ApplyGravityOnly(); // 적용할거에요 -> 중력만
|
|
|
|
|
|
return; // 중단할거에요 -> 이동 코드를
|
2026-01-30 07:45:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-02 10:48:45 +00:00
|
|
|
|
// 3. 이동 속도 계산
|
2026-02-25 10:39:20 +00:00
|
|
|
|
float speed = _isSprinting ? stats.CurrentRunSpeed : stats.CurrentMoveSpeed; // 결정할거에요 -> 달리기/걷기 속도를
|
2026-01-29 16:11:10 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (attackScript != null && attackScript.IsCharging) // 조건이 맞으면 실행할거에요 -> 차징 중이면
|
2026-01-29 16:11:10 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
float speedReduction = Mathf.Lerp(1.0f, minSpeedMultiplier, attackScript.ChargeProgress); // 계산할거에요 -> 차징 진행도에 따른 감속 배율을
|
|
|
|
|
|
speed *= speedReduction; // 적용할거에요 -> 감속을
|
2026-01-29 16:11:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-03 14:41:49 +00:00
|
|
|
|
// 4. 최종 이동 벡터 계산
|
2026-02-25 10:39:20 +00:00
|
|
|
|
Vector3 motion = _moveDir * speed * Time.deltaTime; // 계산할거에요 -> 이번 프레임 이동량을
|
2026-01-29 06:58:38 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
ApplyGravity(); // 계산할거에요 -> 수직 속도를
|
|
|
|
|
|
motion.y = _verticalVelocity * Time.deltaTime; // 넣을거에요 -> 수직 이동량을
|
2026-02-02 10:48:45 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
_controller.Move(motion); // 이동할거에요 -> 캐릭터 컨트롤러를
|
2026-02-02 15:02:12 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
UpdateAnimation(); // 갱신할거에요 -> 이동 애니메이션을
|
2026-02-02 10:48:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private void ApplyGravity() // 함수를 선언할거에요 -> 중력을 계산할
|
2026-02-02 10:48:45 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (_controller.isGrounded) // 조건이 맞으면 실행할거에요 -> 땅에 닿아있으면
|
|
|
|
|
|
_verticalVelocity = -2f; // 설정할거에요 -> 바닥 고정 속도를
|
|
|
|
|
|
else // 조건이 틀리면 실행할거에요 -> 공중이면
|
|
|
|
|
|
_verticalVelocity += gravity * Time.deltaTime; // 더할거에요 -> 중력 가속도를
|
2026-02-02 10:48:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private void ApplyGravityOnly() // 함수를 선언할거에요 -> 중력만 적용할
|
2026-02-02 10:48:45 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
ApplyGravity(); // 계산할거에요 -> 수직 속도를
|
|
|
|
|
|
_controller.Move(new Vector3(0, _verticalVelocity * Time.deltaTime, 0)); // 이동할거에요 -> 수직 방향만
|
2026-02-02 15:02:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private void UpdateAnimation() // 함수를 선언할거에요 -> 이동 애니메이션을 갱신할
|
2026-02-02 10:48:45 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (pAnim == null || stats == null) return; // 중단할거에요 -> 필수 참조 없으면
|
2026-02-22 13:37:34 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
Vector3 horizontalVel = _controller.velocity; // 가져올거에요 -> 현재 속도를
|
|
|
|
|
|
horizontalVel.y = 0f; // 무시할거에요 -> 수직 속도를
|
|
|
|
|
|
float actualSpeed = horizontalVel.magnitude; // 계산할거에요 -> 수평 속도 크기를
|
2026-02-22 13:37:34 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
float walkSpeed = stats.CurrentMoveSpeed; // 가져올거에요 -> 걷기 속도를
|
|
|
|
|
|
float runSpeed = stats.CurrentRunSpeed; // 가져올거에요 -> 달리기 속도를
|
2026-02-22 13:37:34 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
float targetAnimVal = 0f; // 초기화할거에요 -> 목표 애니메이션 값을
|
|
|
|
|
|
if (actualSpeed > 0.1f) // 조건이 맞으면 실행할거에요 -> 움직이고 있으면
|
2026-02-22 13:37:34 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (actualSpeed <= walkSpeed) // 조건이 맞으면 실행할거에요 -> 걷기 이하면
|
|
|
|
|
|
targetAnimVal = Mathf.Lerp(0f, 0.5f, actualSpeed / walkSpeed); // 보간할거에요 -> 0~0.5로
|
|
|
|
|
|
else // 조건이 틀리면 실행할거에요 -> 달리기면
|
|
|
|
|
|
targetAnimVal = Mathf.Lerp(0.5f, 1.0f, (actualSpeed - walkSpeed) / (runSpeed - walkSpeed)); // 보간할거에요 -> 0.5~1.0으로
|
2026-02-22 13:37:34 +00:00
|
|
|
|
}
|
2026-02-12 15:23:25 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (attackScript != null && attackScript.IsCharging) // 조건이 맞으면 실행할거에요 -> 차징 중이면
|
|
|
|
|
|
targetAnimVal *= 0.5f; // 줄일거에요 -> 절반으로
|
2026-02-12 15:23:25 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
_currentAnimVal = Mathf.Lerp(_currentAnimVal, targetAnimVal, Time.deltaTime * animSmoothSpeed); // 보간할거에요 -> 부드럽게
|
2026-02-12 15:23:25 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
pAnim.UpdateMove(_currentAnimVal); // 전달할거에요 -> 보간된 애니메이션 값을
|
2026-01-29 06:58:38 +00:00
|
|
|
|
}
|
2026-02-01 15:49:12 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
private IEnumerator DashRoutine() // 코루틴을 정의할거에요 -> 대시 로직을
|
2026-02-01 15:49:12 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
_isDashing = true; // 설정할거에요 -> 대시 상태를
|
|
|
|
|
|
_lastDashTime = Time.time; // 저장할거에요 -> 대시 시작 시간을
|
2026-02-01 15:49:12 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (soundFX != null) soundFX.PlayDash(); // 재생할거에요 -> 대시 소리를
|
2026-02-13 09:11:54 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (PlayerBehaviorTracker.Instance != null) // 조건이 맞으면 실행할거에요 -> 트래커가 있으면
|
|
|
|
|
|
PlayerBehaviorTracker.Instance.RecordDodge(); // 기록할거에요 -> 회피를
|
2026-02-01 15:49:12 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
Vector3 dashDir = _moveDir.sqrMagnitude > 0.001f ? _moveDir : -transform.forward; // 결정할거에요 -> 대시 방향을
|
2026-02-12 15:23:25 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (health != null) health.isInvincible = true; // 켤거에요 -> 무적을
|
2026-02-01 15:49:12 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
float startTime = Time.time; // 저장할거에요 -> 대시 시작 시간을
|
|
|
|
|
|
while (Time.time < startTime + dashDuration) // 반복할거에요 -> 대시 시간 동안
|
2026-02-01 15:49:12 +00:00
|
|
|
|
{
|
2026-02-25 10:39:20 +00:00
|
|
|
|
float speed = dashDistance / dashDuration; // 계산할거에요 -> 대시 속도를
|
|
|
|
|
|
Vector3 dashMotion = dashDir * speed * Time.deltaTime; // 계산할거에요 -> 이동량을
|
|
|
|
|
|
_controller.Move(dashMotion); // 이동할거에요 -> 대시 방향으로
|
|
|
|
|
|
yield return null; // 대기할거에요 -> 다음 프레임까지
|
2026-02-01 15:49:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
if (health != null) health.isInvincible = false; // 끌거에요 -> 무적을
|
|
|
|
|
|
_isDashing = false; // 해제할거에요 -> 대시 상태를
|
2026-02-01 15:49:12 +00:00
|
|
|
|
}
|
2026-02-02 10:48:45 +00:00
|
|
|
|
|
2026-02-25 10:39:20 +00:00
|
|
|
|
public bool IsGrounded() => _controller.isGrounded; // 반환할거에요 -> 땅 접지 여부를
|
|
|
|
|
|
public bool IsDashing() => _isDashing; // 반환할거에요 -> 대시 여부를
|
|
|
|
|
|
public float GetCurrentSpeed() => _controller.velocity.magnitude; // 반환할거에요 -> 현재 이동 속도를
|
2026-01-29 06:58:38 +00:00
|
|
|
|
}
|