Projext/Assets/02_Scripts/Player/Controller/PlayerInput.cs
hydrozen e989d20668 카툰 쉐이더 추가 + 중복 스크립트 수정 + 전체 업데이트
- ToonPostProcess.shader: 횃불 고딕 스타일 후처리 쉐이더 (Built-in RP)
- ToonCameraEffect.cs: 카메라 자동 부착 후처리 스크립트
- 중복 UI 스크립트 제거 (MenuIntroController, ToggleCustom)
- 씬, 프리팹, 애니메이션 등 전체 업데이트

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 12:31:16 +09:00

131 lines
8.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine; // 유니티 엔진의 기본 기능을 불러올거에요 -> UnityEngine을
public class PlayerInput : MonoBehaviour // 클래스를 선언할거에요 -> MonoBehaviour를 상속받는 PlayerInput을
{
// 다른 스크립트에게 명령을 내려야 하니, 미리 참조 시킴
[SerializeField] private PlayerHealth health; // 변수를 선언할거에요 -> 죽었는지 확인할 health를
[SerializeField] private PlayerMovement movement; // 변수를 선언할거에요 -> 이동 명령을 내릴 movement를
[SerializeField] private PlayerAim aim; // 변수를 선언할거에요 -> 회전 명령을 내릴 aim을
[SerializeField] private PlayerInteraction interaction; // 변수를 선언할거에요 -> 상호작용 명령을 내릴 interaction을
[SerializeField] private PlayerAttack attack; // 변수를 선언할거에요 -> 공격 명령을 내릴 attack을
[SerializeField] private PlayerStatsUI statsUI; // 변수를 선언할거에요 -> UI 토글을 위한 statsUI를
// ── 입력 잠금 (보스 연출, 컷씬 등에서 사용) ──────────────────
private bool _isInputLocked = false; // 변수를 선언할거에요 -> 입력 잠금 여부를 (true면 모든 입력 차단)
/// <summary>
/// 플레이어 입력을 잠가요. 보스 연출, 컷씬 등에서 호출하세요.
/// 잠금 중에는 이동, 공격, 상호작용 등 모든 입력이 무시돼요.
/// </summary>
public void LockInput() // 함수를 선언할거에요 -> 입력을 잠그는 (외부에서 호출 가능)
{
_isInputLocked = true; // 설정할거에요 -> 입력 잠금 켜기
// 잠금 즉시 이동 입력을 0으로 초기화 (관성으로 미끄러지는 것 방지)
if (movement != null) movement.SetMoveInput(Vector3.zero, false); // 실행할거에요 -> 이동 정지를
Debug.Log("[PlayerInput] 입력 잠금 ON"); // 로그를 찍을거에요
}
/// <summary>
/// 플레이어 입력 잠금을 해제해요. 연출 종료 후 호출하세요.
/// </summary>
public void UnlockInput() // 함수를 선언할거에요 -> 입력 잠금을 해제하는 (외부에서 호출 가능)
{
_isInputLocked = false; // 설정할거에요 -> 입력 잠금 끄기
Debug.Log("[PlayerInput] 입력 잠금 OFF"); // 로그를 찍을거에요
}
/// <summary> 현재 입력이 잠겨있는지 확인 (읽기 전용) </summary>
public bool IsInputLocked => _isInputLocked; // 프로퍼티를 선언할거에요 -> 잠금 상태 조회용
private void Update() // 함수를 실행할거에요 -> 매 프레임마다 Update를
{
// 0. 입력 잠금 체크
// 보스 연출, 컷씬 등에서 입력이 잠겨있으면 모든 입력을 차단해요
if (_isInputLocked) return; // 조건이 맞으면 중단할거에요 -> 입력이 잠겨있다면
// 1. 사망 체크
// 죽었는데 키보드 눌린다고 시체가 움직이면 안 되니까 아예 입력을 차단(return)함
if (health != null && health.IsDead) return; // 조건이 맞으면 중단할거에요 -> 플레이어가 죽었다면
// 2. UI 토글 (C키)
// 스탯 창을 껐다 켰다 함
if (Input.GetKeyDown(KeyCode.C) && statsUI != null) statsUI.ToggleWindow(); // 조건이 맞으면 실행할거에요 -> C키를 눌렀다면 스탯창 토글을
// 3. 이동 입력 감지
// GetAxisRaw를 쓴 이유: 0에서 1로 부드럽게 변하는 게 아니라,
// 키를 누르면 즉시 1, 떼면 0이 되어서 빠릿빠릿한 조작감을 줌
float h = Input.GetAxisRaw("Horizontal"); // 값을 가져올거에요 -> 좌우 입력값(-1, 0, 1)을 h에
float v = Input.GetAxisRaw("Vertical"); // 값을 가져올거에요 -> 상하 입력값(-1, 0, 1)을 v에
bool sprint = Input.GetKey(KeyCode.LeftShift); // 값을 가져올거에요 -> 쉬프트 키 입력 여부를 sprint에
// 4. 이동 명령 하달 (★ 카메라 방향 기준 이동)
if (movement != null) // 조건이 맞으면 실행할거에요 -> 이동 스크립트가 있다면
{
// 카메라의 앞/오른쪽 방향을 기준으로 이동 방향을 계산해요
// 이렇게 하면 W키가 항상 "화면 기준 앞"으로 이동합니다
Vector3 inputDir = new Vector3(h, 0, v); // 만들거에요 -> 원시 입력 벡터를
Vector3 cameraRelativeDir = ConvertToCameraRelative(inputDir); // 변환할거에요 -> 카메라 기준 방향으로
movement.SetMoveInput(cameraRelativeDir, sprint); // 실행할거에요 -> 카메라 기준 이동 입력 전달을
// ⭐ [추가] 스페이스바 누르면 대시 명령!
if (Input.GetKeyDown(KeyCode.Space)) movement.AttemptDash(); // 조건이 맞으면 실행할거에요 -> 스페이스바 누르면 대시 시도를
}
// 5. 마우스 회전 명령
// 캐릭터가 마우스 커서를 바라보게 합니다.
if (aim != null) aim.RotateTowardsMouse(); // 조건이 맞으면 실행할거에요 -> 마우스 방향 회전 함수를
// 6. 상호작용 (F키)
// 바닥에 떨어진 무기를 줍기
if (Input.GetKeyDown(KeyCode.F) && interaction != null) interaction.TryInteract(); // 조건이 맞으면 실행할거에요 -> F키 누르면 상호작용 시도를
// 7. 공격 입력 (좌클릭/우클릭)
if (attack != null) // 조건이 맞으면 실행할거에요 -> 공격 스크립트가 있다면
{
// 우클릭 꾹: 차징(모으기) 시작
if (Input.GetMouseButtonDown(1)) attack.StartCharging(); // 조건이 맞으면 실행할거에요 -> 우클릭 누르면 차징 시작을
// 우클릭 뗌: 차징된 단계로 부채꼴 발사! (기존: 취소 → 변경: 발사)
if (Input.GetMouseButtonUp(1)) attack.ReleaseAttack(); // 조건이 맞으면 실행할거에요 -> 우클릭 떼면 차징 발사를
// 좌클릭: 차징 중이 아닐 때만 일반 공격
if (Input.GetMouseButtonDown(0)) // 조건이 맞으면 실행할거에요 -> 좌클릭을 눌렀다면
{
if (!attack.IsCharging) // 조건이 맞으면 실행할거에요 -> 차징 중이 아니라면
attack.PerformNormalAttack(); // 실행할거에요 -> 일반 공격을
// 차징 중 좌클릭은 무시 (우클릭 떼기로만 발사)
}
}
}
// ─────────────────────────────────────────────────────────────
// 카메라 기준 이동 방향 변환
// ─────────────────────────────────────────────────────────────
/// <summary>
/// WASD 입력을 카메라가 바라보는 방향 기준으로 변환합니다.
/// W = 카메라 앞, A = 카메라 왼쪽, S = 카메라 뒤, D = 카메라 오른쪽
/// Y축(높이)은 무시하고 수평 방향만 사용합니다.
/// </summary>
private Vector3 ConvertToCameraRelative(Vector3 rawInput) // 함수를 정의할거에요 -> 카메라 기준 방향 변환을
{
if (rawInput.sqrMagnitude < 0.001f) return Vector3.zero; // 방어할거에요 -> 입력이 없으면 제로 벡터 반환
Camera cam = Camera.main; // 가져올거에요 -> 메인 카메라를
if (cam == null) return rawInput.normalized; // 방어할거에요 -> 카메라 없으면 월드 좌표 그대로 사용
// 카메라의 앞/오른쪽 방향에서 Y 성분을 제거 (수평면만 사용)
Vector3 camForward = cam.transform.forward; // 가져올거에요 -> 카메라의 앞 방향을
camForward.y = 0f; // 제거할거에요 -> 높이 성분을 (수평면에 투영)
camForward.Normalize(); // 정규화할거에요 -> 단위 벡터로
Vector3 camRight = cam.transform.right; // 가져올거에요 -> 카메라의 오른쪽 방향을
camRight.y = 0f; // 제거할거에요 -> 높이 성분을 (수평면에 투영)
camRight.Normalize(); // 정규화할거에요 -> 단위 벡터로
// 입력 × 카메라 방향 = 최종 이동 방향
// W(v=1) → 카메라 앞, D(h=1) → 카메라 오른쪽
Vector3 result = camForward * rawInput.z + camRight * rawInput.x; // 계산할거에요 -> 카메라 기준 최종 방향을
return result.normalized; // 반환할거에요 -> 정규화된 방향을 (대각선 속도 보정)
}
}