ProjectDDD/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantPlayerMovement.cs

252 lines
8.5 KiB
C#

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem;
using Vector2 = UnityEngine.Vector2;
using Vector3 = UnityEngine.Vector3;
namespace DDD
{
public class RestaurantPlayerMovement : RestaurantCharacterMovement
{
private Rigidbody _rigidbody;
private BoxCollider _boxCollider;
private RestaurantPlayerDataSo _playerDataSo;
private LineRenderer _inputLineRenderer;
private LineRenderer _velocityLineRenderer;
private Vector3 _inputDirection;
private Vector3 _currentDirection;
private Vector3 _currentVelocity;
private bool _isMoving;
private bool _isDashing;
private bool _isDashCooldown;
private bool _isInitialized;
public Action<bool> OnMoving;
public Action<float> OnDashing;
private void Awake()
{
_rigidbody = GetComponent<Rigidbody>();
_boxCollider = GetComponent<BoxCollider>();
}
private async void Start()
{
try
{
_playerDataSo = await AssetManager.LoadAsset<RestaurantPlayerDataSo>(DataConstants.RestaurantPlayerDataSo);
_playerDataSo.MoveActionReference.action.performed += OnMove;
_playerDataSo.MoveActionReference.action.canceled += OnMove;
_playerDataSo.DashActionReference.action.performed += OnDash;
_isInitialized = true;
}
catch (Exception e)
{
Debug.LogError($"_playerData load failed\n{e}");
}
}
private void FixedUpdate()
{
if (_isInitialized == false) return;
if (CanMove())
{
Move();
}
if (_playerDataSo.IsDrawLineDebug)
{
DrawLineDebug();
}
}
private void OnDestroy()
{
if (_playerDataSo)
{
_playerDataSo.MoveActionReference.action.performed -= OnMove;
_playerDataSo.MoveActionReference.action.canceled -= OnMove;
_playerDataSo.DashActionReference.action.performed -= OnDash;
}
}
private void DrawLineDebug()
{
Vector3 origin = transform.position;
if (_inputDirection != Vector3.zero)
{
Vector3 target = origin + _inputDirection.normalized * 1.5f;
if (_inputLineRenderer == null)
{
_inputLineRenderer = CreateOrGetDebugLineRenderer("DebugLine_Input", 10, 0.1f, Color.blue);
}
UpdateLineRenderer(_inputLineRenderer, origin, target);
_inputLineRenderer.enabled = true;
}
else if (_inputLineRenderer != null)
{
_inputLineRenderer.enabled = false;
}
float speed = _currentVelocity.magnitude;
if (speed > 0.01f)
{
Vector3 target = origin + _currentVelocity.normalized * (speed * 0.5f);
if (_velocityLineRenderer == null)
{
_velocityLineRenderer = CreateOrGetDebugLineRenderer("DebugLine_Velocity", 9, 0.2f, Color.red);
}
UpdateLineRenderer(_velocityLineRenderer, origin, target);
_velocityLineRenderer.enabled = true;
}
else if (_velocityLineRenderer != null)
{
_velocityLineRenderer.enabled = false;
}
}
private LineRenderer CreateOrGetDebugLineRenderer(string name, int sortingIndex, float width, Color color)
{
Transform existing = transform.Find(name);
if (existing != null)
{
var lr = existing.GetComponent<LineRenderer>();
if (lr != null)
{
lr.startColor = lr.endColor = color;
return lr;
}
}
var newGameObject = new GameObject(name);
newGameObject.transform.SetParent(transform);
newGameObject.transform.localPosition = Vector3.zero;
var lineRenderer = newGameObject.AddComponent<LineRenderer>();
lineRenderer.positionCount = 2;
lineRenderer.material = new Material(Shader.Find("Sprites/Default")); // URP 호환
lineRenderer.sortingOrder = sortingIndex;
lineRenderer.startWidth = lineRenderer.endWidth = width;
lineRenderer.startColor = lineRenderer.endColor = color;
lineRenderer.useWorldSpace = true;
return lineRenderer;
}
private void UpdateLineRenderer(LineRenderer lr, Vector3 start, Vector3 end)
{
lr.SetPosition(0, start);
lr.SetPosition(1, end);
}
public void SetCurrentDirection(Vector3 normalDirection)
{
if (_inputDirection == Vector3.zero) return;
_currentDirection = normalDirection;
}
private void OnMove(InputAction.CallbackContext context)
{
Vector2 movementInput = context.ReadValue<Vector2>();
_inputDirection = new Vector3(movementInput.x, 0f, movementInput.y);
}
private bool CanMove()
{
return _playerDataSo.IsMoveEnabled && _isDashing == false;
}
private void Move()
{
SetCurrentDirection(_inputDirection);
_isMoving = _inputDirection != Vector3.zero;
OnMoving?.Invoke(_isMoving);
if (_isMoving)
{
Vector3 slideDirection = GetSlideAdjustedDirection(_inputDirection.normalized);
Vector3 targetVelocity = slideDirection * _playerDataSo.MoveSpeed;
_currentVelocity = Vector3.MoveTowards(_currentVelocity, targetVelocity, _playerDataSo.Acceleration * Time.fixedDeltaTime);
}
else
{
_currentVelocity = Vector3.MoveTowards(_currentVelocity, Vector3.zero, _playerDataSo.Deceleration * Time.fixedDeltaTime);
}
_rigidbody.linearVelocity = _currentVelocity;
}
private Vector3 GetSlideAdjustedDirection(Vector3 inputDirection)
{
Vector3 origin = _boxCollider.bounds.center;
Vector3 halfExtents = _boxCollider.bounds.extents;
Quaternion rotation = transform.rotation;
float distance = _boxCollider.bounds.size.x <= _boxCollider.bounds.size.z
? _boxCollider.bounds.size.x
: _boxCollider.bounds.size.z;
int layerMask = ~_playerDataSo.IgnoreSlidingLayerMask;
if (Physics.BoxCast(origin, halfExtents * 0.95f, inputDirection, out RaycastHit hit, rotation, distance, layerMask))
{
Vector3 slide = Vector3.ProjectOnPlane(inputDirection, hit.normal).normalized;
float dot = Vector3.Dot(inputDirection.normalized, hit.normal);
float slideFactor = Mathf.Pow(1f - Mathf.Abs(dot), _playerDataSo.SlidingThreshold);
if (slideFactor < 0.05f) return Vector3.zero;
return slide * slideFactor;
}
return inputDirection;
}
private void OnDash(InputAction.CallbackContext context)
{
if (CanDash())
{
StartCoroutine(DashCoroutine());
}
}
private bool CanDash()
{
return _playerDataSo.IsDashEnabled && _isDashing == false && _isDashCooldown == false;
}
private IEnumerator DashCoroutine()
{
_isDashing = true;
_isDashCooldown = true;
OnDashing?.Invoke(_playerDataSo.DashTime);
Vector3 currentDirection = _currentDirection.normalized;
Vector3 slideDashDirection = GetSlideAdjustedDirection(currentDirection);
Vector3 dashVelocity = slideDashDirection * _playerDataSo.DashSpeed;
_rigidbody.linearVelocity = dashVelocity;
yield return new WaitForSeconds(_playerDataSo.DashTime);
_isDashing = false;
yield return new WaitForSeconds(_playerDataSo.DashCooldown);
_isDashCooldown = false;
}
public Vector3 GetCurrentDirection() => _currentDirection;
}
}