Files
decay-grid/Assets/Scripts/Infrastructure/Unity/PlayerController.cs

141 lines
4.3 KiB
C#

using System;
using Core.Domain.Status;
using KBCore.Refs;
using UnityEngine;
using UnityEngine.InputSystem;
namespace Infrastructure.Unity
{
[RequireComponent(typeof(Rigidbody))]
public class PlayerController : MonoBehaviour
{
[Header("Movement Settings")]
[SerializeField]
private float moveSpeed = 8f;
[SerializeField] private float maxVelocityChange = 10f;
[SerializeField] private float snapForce = 15f;
[Header("Interaction")]
[SerializeField] private LayerMask tileLayer;
[SerializeField] private float groundCheckDistance = 1.5f;
[Self] [SerializeField] private Rigidbody rb;
private InputSystem_Actions _actions;
private Vector2 _moveInput;
public Rigidbody Rigidbody => rb;
public StatusManager Status { get; private set; }
private void OnEnable()
{
_actions.Player.Enable();
_actions.Player.Move.performed += OnMovePerformed;
_actions.Player.Move.canceled += OnMoveCanceled;
}
private void OnDisable()
{
_actions.Player.Move.performed -= OnMovePerformed;
_actions.Player.Move.canceled -= OnMoveCanceled;
_actions.Player.Disable();
}
private void Awake()
{
_actions = new InputSystem_Actions();
Status = new StatusManager();
rb.freezeRotation = true;
rb.useGravity = true;
}
private void Update()
{
Status.Tick(Time.deltaTime);
}
private void FixedUpdate()
{
HandleMovement();
DetectGround();
}
private void HandleMovement()
{
var currentSpeed = moveSpeed * Status.CurrentCapabilities.SpeedMultiplier;
var targetVelocity = Vector3.zero;
var snapAxis = Vector3.zero;
if (_moveInput.sqrMagnitude > 0.1f)
{
if (Mathf.Abs(_moveInput.x) > Mathf.Abs(_moveInput.y))
{
targetVelocity = new Vector3(_moveInput.x > 0 ? currentSpeed : -currentSpeed, 0, 0);
snapAxis = Vector3.forward;
}
else
{
targetVelocity = new Vector3(0, 0, _moveInput.y > 0 ? currentSpeed : -currentSpeed);
snapAxis = Vector3.right;
}
}
var velocity = rb.linearVelocity;
var velocityChange = (targetVelocity - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0f;
rb.AddForce(velocityChange, ForceMode.VelocityChange);
if (snapAxis != Vector3.zero)
{
ApplySnapping(snapAxis);
}
else
{
ApplySnapping(Vector3.right);
ApplySnapping(Vector3.forward);
}
}
private void ApplySnapping(Vector3 axis)
{
var currentPos = Vector3.Dot(transform.position, axis);
var targetPos = Mathf.Round(currentPos);
var diff = targetPos - currentPos;
var correction = axis * (diff * snapForce);
rb.AddForce(correction, ForceMode.Acceleration);
}
private void DetectGround()
{
if (!Status.CurrentCapabilities.CanTriggerDecay) return;
if (Physics.Raycast(transform.position, Vector3.down, out var hit, groundCheckDistance, tileLayer))
{
if (hit.collider.TryGetComponent<TileViewAdapter>(out var tileAdapter))
{
tileAdapter.OnPlayerStep();
}
}
}
private void OnMovePerformed(InputAction.CallbackContext ctx)
{
_moveInput = ctx.ReadValue<Vector2>();
}
private void OnMoveCanceled(InputAction.CallbackContext ctx)
{
_moveInput = Vector2.zero;
}
}
}