RiftMayhem/Assets/Scripts/Player/PlayerMovement.cs

390 lines
12 KiB
C#

using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
public enum MovementType
{
PointAndClick,
DirectionalInput
}
[RequireComponent(typeof(NavMeshAgent))]
public class PlayerMovement : MonoBehaviour
{
[Header("Movement Settings")]
[SerializeField] private float lookSpeed = 10f;
[SerializeField] private float gamepadRotationSpeed = 300f;
[SerializeField] private float minimumInputThreshold = 0.1f;
[SerializeField] private MovementType movementType = MovementType.DirectionalInput;
[SerializeField] private BoolSharedField directionalInputMode;
public BoolSharedField DirectionalInputMode => directionalInputMode;
[Header("Controller Settings")]
[SerializeField] private float gamepadDeadzone = 0.2f;
[Header("Debug Visualization")]
[SerializeField] private bool showDebugVisuals = false;
// Input System variables
private PlayerInput playerInput;
private Vector2 moveInput;
private Vector2 aimInput;
private bool isMouseAiming;
private Transform target;
private NavMeshAgent agent;
private Vector3 direction = Vector3.zero;
private Quaternion lookRotation = Quaternion.identity;
private Camera mainCamera;
private Plane groundPlane;
private Vector3 lastAimDirection;
private bool isUsingGamepad;
private Vector3 currentMoveDirection;
private bool isMoving;
private ProjectileSpawnLocationController aimController;
private Vector3 currentAimPoint;
public Vector2 currentMovementDirection = new Vector2();
public Vector2 currentAimDirection = new Vector2();
public Vector2 lastAimDirection2 = new Vector2();
public Vector2 relativeMovementDirection = new Vector2();
private Vector3 mouseAimPoint;
private bool hasMouseAimPoint;
private float startingAgentSpeed;
public float StartingAgentSpeed => startingAgentSpeed;
private float startingAgentAngularSpeed;
public float StartingAgentAngularSpeed => startingAgentAngularSpeed;
private float startingAgentAcceleration;
public float StartingAgentAcceleration => startingAgentAcceleration;
private void Awake()
{
agent = GetComponent<NavMeshAgent>();
mainCamera = Camera.main;
groundPlane = new Plane(Vector3.up, Vector3.zero);
aimController = GetComponentInChildren<ProjectileSpawnLocationController>();
lastAimDirection = transform.forward;
directionalInputMode.Value = true;
movementType = MovementType.DirectionalInput;
startingAgentSpeed = agent.speed;
startingAgentAngularSpeed = agent.angularSpeed;
startingAgentAcceleration = agent.acceleration;
// Initialize Input System
playerInput = GetComponent<PlayerInput>();
if (playerInput == null)
{
Debug.LogWarning("PlayerInput component not found. Add PlayerInput component to use Input System.");
}
}
void Start()
{
SetupAgentForDirectionalMovement();
}
// Input callbacks - these will be called by Unity's SendMessage system
public void OnMove(InputValue value)
{
moveInput = value.Get<Vector2>();
currentMovementDirection = moveInput;
}
public void OnStick(InputValue value)
{
aimInput = value.Get<Vector2>();
currentAimDirection = aimInput;
// Detect gamepad usage
if (aimInput.magnitude > gamepadDeadzone)
{
isUsingGamepad = true;
hasMouseAimPoint = false;
}
}
public void OnLook(InputValue value)
{
// This gets called when mouse moves, indicating mouse usage
isUsingGamepad = false;
}
private void Update()
{
SetMovementType(directionalInputMode.Value ? MovementType.DirectionalInput : MovementType.PointAndClick);
if (movementType == MovementType.DirectionalInput)
{
// Handle movement
HandleDirectionalMovement();
// Handle aiming based on input method
if (!isUsingGamepad)
{
HandleMouseAiming();
}
else
{
HandleGamepadAiming();
}
HandleRelativeForAnimation();
}
else if (target != null)
{
HandlePointAndClickMovement();
}
// Handle channeled ability rotation
if (CastBarHandler.Instance.currentAbility is ChanneledAbility &&
CastBarHandler.Instance.castBar.activeSelf)
{
var channelAbility = (ChanneledAbility)CastBarHandler.Instance.currentAbility;
if (channelAbility.allowAiming)
{
InstantFaceCast(aimController.GetLookat());
}
}
}
private void HandleDirectionalMovement()
{
if (agent.isStopped) return;
Vector3 cameraForward = mainCamera.transform.forward;
Vector3 cameraRight = mainCamera.transform.right;
cameraForward.y = 0f;
cameraRight.y = 0f;
cameraForward.Normalize();
cameraRight.Normalize();
currentMoveDirection = (cameraForward * currentMovementDirection.y +
cameraRight * currentMovementDirection.x).normalized;
isMoving = currentMoveDirection.magnitude >= minimumInputThreshold;
if (isMoving)
{
agent.SetDestination(transform.position + currentMoveDirection);
}
else
{
agent.velocity = Vector3.zero;
agent.SetDestination(transform.position);
}
// If we're using mouse aim, maintain character rotation even while moving
if (!isUsingGamepad && hasMouseAimPoint)
{
Vector3 aimDirection = (mouseAimPoint - transform.position).normalized;
if (aimDirection != Vector3.zero)
{
transform.rotation = Quaternion.LookRotation(aimDirection);
}
}
}
private void HandleGamepadAiming()
{
if (currentAimDirection.magnitude > gamepadDeadzone)
{
Vector3 cameraForward = mainCamera.transform.forward;
Vector3 cameraRight = mainCamera.transform.right;
cameraForward.y = 0f;
cameraRight.y = 0f;
Vector3 aimDirection = (cameraForward * currentAimDirection.y + cameraRight * currentAimDirection.x).normalized;
lastAimDirection = aimDirection;
lastAimDirection2.x = aimDirection.x;
lastAimDirection2.y = aimDirection.z;
Quaternion targetRotation = Quaternion.LookRotation(aimDirection);
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
targetRotation,
gamepadRotationSpeed * Time.deltaTime
);
}
else if (lastAimDirection != Vector3.zero)
{
Quaternion targetRotation = Quaternion.LookRotation(lastAimDirection);
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
targetRotation,
gamepadRotationSpeed * Time.deltaTime
);
}
}
private void HandleRelativeForAnimation()
{
// Calculate forward/backward movement relative to aim direction
relativeMovementDirection.y = Vector2.Dot(lastAimDirection2, currentMovementDirection);
// Calculate strafe movement relative to aim direction
relativeMovementDirection.x = lastAimDirection2.x * currentMovementDirection.y -
lastAimDirection2.y * currentMovementDirection.x;
}
private void HandleMouseAiming()
{
// Get the current mouse position directly from the Input System
Vector3 screenMousePosition = Mouse.current.position.ReadValue();
Ray ray = mainCamera.ScreenPointToRay(screenMousePosition);
if (groundPlane.Raycast(ray, out float distance))
{
mouseAimPoint = ray.GetPoint(distance);
mouseAimPoint.y = transform.position.y;
hasMouseAimPoint = true;
Vector3 aimDirection = (mouseAimPoint - transform.position).normalized;
if (aimDirection != Vector3.zero)
{
lastAimDirection = aimDirection;
lastAimDirection2.x = aimDirection.x;
lastAimDirection2.y = aimDirection.z;
transform.rotation = Quaternion.LookRotation(aimDirection);
}
}
}
private void HandlePointAndClickMovement()
{
agent.SetDestination(target.position);
FacePoint(agent.destination);
}
private void SetupAgentForDirectionalMovement()
{
agent.updateRotation = false;
agent.stoppingDistance = 0f;
agent.acceleration = startingAgentAcceleration;
agent.angularSpeed = startingAgentAngularSpeed;
}
#region Public Methods
public void SetMovementType(MovementType type)
{
movementType = type;
if (movementType == MovementType.DirectionalInput)
{
SetupAgentForDirectionalMovement();
}
else
{
agent.updateRotation = true;
agent.stoppingDistance = 0.25f;
agent.acceleration = startingAgentAcceleration;
agent.angularSpeed = startingAgentAngularSpeed;
}
}
public void ToggleAgentMoving(bool busy)
{
agent.isStopped = busy;
if (busy)
{
agent.SetDestination(transform.position);
}
}
public void MoveToPoint(Vector3 point)
{
agent.SetDestination(point);
FacePoint(point);
}
public void FollowTarget(Interactable newTarget)
{
agent.stoppingDistance = newTarget.radius * 0.8f;
agent.updateRotation = false;
target = newTarget.interactionTransform;
FaceTarget();
}
public void StopFollowingTarget()
{
agent.stoppingDistance = 0f;
agent.updateRotation = true;
target = null;
}
public void FaceAttack(int index)
{
if (target != null)
FaceTarget();
}
public void FacePoint(Vector3 point)
{
direction = (point - transform.position).normalized;
direction.y = 0f;
lookRotation = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * lookSpeed);
}
public void FaceTarget()
{
if (target == null) return;
direction = (target.position - transform.position).normalized;
direction.y = 0f;
lookRotation = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * lookSpeed);
}
public void InstantFaceTarget()
{
if (target != null)
{
direction = (target.position - transform.position).normalized;
direction.y = 0f;
lookRotation = Quaternion.LookRotation(direction);
transform.rotation = lookRotation;
}
}
public void InstantFaceCast(Vector3 lookat)
{
transform.forward = lookat;
}
public void StopLocomotion(int index)
{
StopFollowingTarget();
agent.SetDestination(transform.position);
}
#endregion
#region Debug
private void OnDrawGizmos()
{
if (!showDebugVisuals) return;
// Draw movement direction
Gizmos.color = Color.blue;
Gizmos.DrawRay(transform.position, currentMoveDirection * 2f);
// Draw aim direction
Gizmos.color = Color.red;
Gizmos.DrawRay(transform.position, lastAimDirection * 2f);
// Draw aim point if using mouse
if (!isUsingGamepad)
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(currentAimPoint, 0.2f);
}
}
#endregion
}