기본 애니메이션 및 컨트롤러 추가
kaykit 애셋 일부 적용
This commit is contained in:
40
Assets/Scripts/Player/PlayerAnimationController.cs
Normal file
40
Assets/Scripts/Player/PlayerAnimationController.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class PlayerAnimationController : MonoBehaviour
|
||||
{
|
||||
private Animator animator;
|
||||
private CharacterController controller;
|
||||
|
||||
void Start()
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
controller = GetComponent<CharacterController>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// 1. 이동 속도 제어 (수평 속도만 계산)
|
||||
// Y축(중력/점프)을 제외한 X, Z축의 속도만 추출하여 MoveSpeed에 전달합니다.
|
||||
Vector3 horizontalVelocity = new Vector3(controller.velocity.x, 0, controller.velocity.z);
|
||||
float currentSpeed = horizontalVelocity.magnitude;
|
||||
|
||||
// 애니메이터의 MoveSpeed 파라미터 업데이트 (0.1은 보정값)
|
||||
animator.SetFloat("MoveSpeed", currentSpeed > 0.1f ? currentSpeed : 0f);
|
||||
|
||||
// 2. 점프 및 공중 상태 (isGrounded 활용)
|
||||
// CharacterController가 바닥에 닿아있는지 여부를 직접 전달합니다.
|
||||
animator.SetBool("isGrounded", controller.isGrounded);
|
||||
|
||||
// 3. 공격 (트리거)
|
||||
if (Input.GetMouseButtonDown(0))
|
||||
{
|
||||
animator.SetTrigger("Attack");
|
||||
}
|
||||
|
||||
// 4. 인터랙션 (트리거)
|
||||
if (Input.GetKeyDown(KeyCode.E))
|
||||
{
|
||||
animator.SetTrigger("Interact");
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Player/PlayerAnimationController.cs.meta
Normal file
2
Assets/Scripts/Player/PlayerAnimationController.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6806aa8897e01a418df919c13b31c0b
|
||||
@@ -1,58 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class PlayerBuildInteract : MonoBehaviour
|
||||
{
|
||||
[Header("Interaction Settings")]
|
||||
[SerializeField] private float interactRange = 3f; // 건설 가능 거리
|
||||
[SerializeField] private float buildSpeedMultiplier = 1f; // 건설 속도 배율
|
||||
[SerializeField] private LayerMask constructionLayer; // 토대 레이어 (선택 사항)
|
||||
|
||||
private PlayerInputActions _inputActions;
|
||||
private bool _isInteracting = false;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_inputActions = new PlayerInputActions();
|
||||
|
||||
// Interact 액션 연결 (Hold 방식)
|
||||
_inputActions.Player.Interact.started += ctx => _isInteracting = true;
|
||||
_inputActions.Player.Interact.canceled += ctx => _isInteracting = false;
|
||||
}
|
||||
|
||||
void OnEnable() => _inputActions.Enable();
|
||||
void OnDisable() => _inputActions.Disable();
|
||||
|
||||
void Update()
|
||||
{
|
||||
// 키를 누르고 있을 때만 실행
|
||||
if (_isInteracting)
|
||||
{
|
||||
PerformConstruction();
|
||||
}
|
||||
}
|
||||
|
||||
void PerformConstruction()
|
||||
{
|
||||
// 주변의 모든 콜라이더 검사
|
||||
Collider[] targets = Physics.OverlapSphere(transform.position, interactRange, constructionLayer);
|
||||
|
||||
foreach (var col in targets)
|
||||
{
|
||||
// 토대 컴포넌트가 있는지 확인
|
||||
ConstructionSite site = col.GetComponent<ConstructionSite>();
|
||||
if (site != null)
|
||||
{
|
||||
// 드디어 여기서 호출합니다!
|
||||
site.AdvanceConstruction(Time.deltaTime * buildSpeedMultiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 에디터에서 상호작용 범위를 확인하기 위함
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawWireSphere(transform.position, interactRange);
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 29785216765776848b0c3cc745d761a7
|
||||
@@ -1,79 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem; // New Input System 네임스페이스
|
||||
|
||||
public class PlayerInteraction : MonoBehaviour
|
||||
{
|
||||
[Header("Detection Settings")]
|
||||
[SerializeField] private float interactionRadius = 2.5f;
|
||||
[SerializeField] private LayerMask interactableLayer;
|
||||
|
||||
private PlayerInputActions _inputActions;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_inputActions = new PlayerInputActions();
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
// Interact 액션이 수행되었을 때(버튼을 눌렀을 때) 실행될 함수 연결
|
||||
_inputActions.Player.Interact.performed += OnInteractPerformed;
|
||||
_inputActions.Enable();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
// 이벤트 연결 해제 및 비활성화
|
||||
_inputActions.Player.Interact.performed -= OnInteractPerformed;
|
||||
_inputActions.Disable();
|
||||
}
|
||||
|
||||
// Input Action 콜백 함수
|
||||
private void OnInteractPerformed(InputAction.CallbackContext context)
|
||||
{
|
||||
Debug.Log("E 키 눌림!"); // <-- 이게 콘솔에 찍히나요?
|
||||
|
||||
// 건설 모드 중일 때는 상호작용을 막고 싶다면 아래 조건 추가
|
||||
if (BuildManager.Instance.IsBuildMode) return;
|
||||
|
||||
CheckAndInteract();
|
||||
}
|
||||
|
||||
private void CheckAndInteract()
|
||||
{
|
||||
Collider[] colliders = Physics.OverlapSphere(transform.position, interactionRadius, interactableLayer);
|
||||
Debug.Log($"주변에서 {colliders.Length}개의 물체 감지됨"); // 0이 나오면 레이어나 콜라이더 문제
|
||||
|
||||
IInteractable nearestInteractable = null;
|
||||
float minDistance = Mathf.Infinity;
|
||||
|
||||
foreach (var col in colliders)
|
||||
{
|
||||
// 부모까지 포함하여 IInteractable 인터페이스를 찾음
|
||||
IInteractable interactable = col.GetComponentInParent<IInteractable>();
|
||||
|
||||
if (interactable != null)
|
||||
{
|
||||
Debug.Log($"{col.name}에서 인터페이스 발견!");
|
||||
float distance = Vector3.Distance(transform.position, col.transform.position);
|
||||
if (distance < minDistance)
|
||||
{
|
||||
minDistance = distance;
|
||||
nearestInteractable = interactable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nearestInteractable != null)
|
||||
{
|
||||
nearestInteractable.Interact(gameObject);
|
||||
Debug.Log($"[Interaction] {nearestInteractable.GetInteractionText()} 실행");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawWireSphere(transform.position, interactionRadius);
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 059b81ebcbce23f4b88e7c52021fa869
|
||||
@@ -5,23 +5,34 @@ public class PlayerMovement : MonoBehaviour
|
||||
{
|
||||
[Header("Movement Settings")]
|
||||
public float moveSpeed = 5f;
|
||||
public float jumpHeight = 1.5f; // 점프 높이
|
||||
public float gravity = -19.62f; // 기본 중력보다 약간 무거운 값 추천
|
||||
public float rotationSpeed = 10f;
|
||||
public float jumpHeight = 1.5f;
|
||||
public float gravity = -19.62f;
|
||||
|
||||
[Header("Interaction Settings")]
|
||||
[SerializeField] private float interactRange = 3f;
|
||||
[SerializeField] private LayerMask interactableLayer; // 터널 노드 레이어
|
||||
|
||||
private CharacterController _controller;
|
||||
private PlayerInputActions _inputActions;
|
||||
private Animator _animator;
|
||||
private TunnelTraveler _traveler; // 터널 이동 컴포넌트 참조
|
||||
|
||||
private Vector2 _moveInput;
|
||||
private Vector3 _velocity; // 수직 속도 (중력용)
|
||||
private Vector3 _velocity;
|
||||
private Vector3 _currentMoveDir;
|
||||
private bool _isGrounded;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_controller = GetComponent<CharacterController>();
|
||||
_animator = GetComponent<Animator>();
|
||||
_traveler = GetComponent<TunnelTraveler>(); // 컴포넌트 캐싱
|
||||
_inputActions = new PlayerInputActions();
|
||||
|
||||
// 점프 액션 연결
|
||||
_inputActions.Player.Jump.performed += ctx => OnJump();
|
||||
_inputActions.Player.Attack.performed += ctx => OnAttack();
|
||||
_inputActions.Player.Interact.performed += ctx => OnInteract();
|
||||
}
|
||||
|
||||
void OnEnable() => _inputActions.Enable();
|
||||
@@ -29,46 +40,103 @@ public class PlayerMovement : MonoBehaviour
|
||||
|
||||
void Update()
|
||||
{
|
||||
// [해결책] 터널 이동 중이라면 일반 이동/중력 로직을 모두 중단합니다.
|
||||
if (GetComponent<TunnelTraveler>().IsTraveling)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// [중요] 터널 이동 중에는 모든 이동/중력 로직을 중단합니다.
|
||||
if (_traveler != null && _traveler.IsTraveling) return;
|
||||
|
||||
// 1. 바닥 체크 (CharacterController의 기능 활용)
|
||||
_isGrounded = _controller.isGrounded;
|
||||
_animator.SetBool("isGrounded", _isGrounded);
|
||||
|
||||
bool isAttacking = _animator.GetCurrentAnimatorStateInfo(0).IsTag("Attack");
|
||||
|
||||
if (_isGrounded && _velocity.y < 0)
|
||||
{
|
||||
// 바닥에 닿아있을 때는 아주 작은 하방 힘만 유지 (안정성)
|
||||
_velocity.y = -2f;
|
||||
}
|
||||
|
||||
// 2. 이동 로직
|
||||
_moveInput = _inputActions.Player.Move.ReadValue<Vector2>();
|
||||
Vector3 move = transform.right * _moveInput.x + transform.forward * _moveInput.y;
|
||||
_controller.Move(move * moveSpeed * Time.deltaTime);
|
||||
Vector3 move = Vector3.zero;
|
||||
|
||||
if (_isGrounded)
|
||||
{
|
||||
if (isAttacking)
|
||||
{
|
||||
move = Vector3.zero;
|
||||
_currentMoveDir = Vector3.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
_moveInput = _inputActions.Player.Move.ReadValue<Vector2>();
|
||||
move = new Vector3(_moveInput.x, 0, _moveInput.y).normalized;
|
||||
_currentMoveDir = move;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isAttacking)
|
||||
{
|
||||
move = _currentMoveDir;
|
||||
}
|
||||
else
|
||||
{
|
||||
_moveInput = _inputActions.Player.Move.ReadValue<Vector2>();
|
||||
move = new Vector3(_moveInput.x, 0, _moveInput.y).normalized;
|
||||
if (move.magnitude > 0.1f) _currentMoveDir = move;
|
||||
}
|
||||
}
|
||||
|
||||
if (move.magnitude >= 0.1f)
|
||||
{
|
||||
Quaternion targetRotation = Quaternion.LookRotation(move);
|
||||
if (!isAttacking)
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
|
||||
|
||||
_controller.Move(move * moveSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
_animator.SetFloat("MoveSpeed", isAttacking && _isGrounded ? 0 : move.magnitude);
|
||||
|
||||
// 3. 중력 적용
|
||||
_velocity.y += gravity * Time.deltaTime;
|
||||
|
||||
// 4. 최종 수직 이동 적용 (중력/점프 속도)
|
||||
_controller.Move(_velocity * Time.deltaTime);
|
||||
}
|
||||
|
||||
private void OnJump()
|
||||
{
|
||||
// TunnelTraveler가 이동 중인지 체크 (상태 변수 활용)
|
||||
if (GetComponent<TunnelTraveler>().IsTraveling) return;
|
||||
if (_traveler != null && _traveler.IsTraveling) return;
|
||||
if (_isGrounded) _velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
|
||||
}
|
||||
|
||||
if (_isGrounded)
|
||||
private void OnAttack()
|
||||
{
|
||||
if (_traveler != null && _traveler.IsTraveling) return;
|
||||
_animator.SetTrigger("Attack");
|
||||
}
|
||||
|
||||
private void OnInteract()
|
||||
{
|
||||
// 터널 이동 중에는 상호작용 금지
|
||||
if (_traveler != null && _traveler.IsTraveling) return;
|
||||
|
||||
// 상호작용 애니메이션 실행
|
||||
_animator.SetTrigger("Interact");
|
||||
|
||||
// [핵심 추가] 주변 상호작용 대상(터널 노드 등) 검색
|
||||
Collider[] colliders = Physics.OverlapSphere(transform.position, interactRange, interactableLayer);
|
||||
|
||||
foreach (var col in colliders)
|
||||
{
|
||||
_velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
|
||||
// 터널 노드(IInteractable)를 찾아 Interact 호출
|
||||
IInteractable interactable = col.GetComponentInParent<IInteractable>();
|
||||
if (interactable != null)
|
||||
{
|
||||
interactable.Interact(gameObject);
|
||||
break; // 하나만 발견하면 중단
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 터널 이동 등 외부에서 중력을 초기화해야 할 때 사용
|
||||
public void ResetVelocity()
|
||||
// 범위 확인용 기즈모
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
_velocity.y = 0;
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawWireSphere(transform.position, interactRange);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user