384 lines
11 KiB
C#
384 lines
11 KiB
C#
using Photon.Pun;
|
|
using UnityEngine;
|
|
using UnityEngine.AI;
|
|
|
|
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;
|
|
|
|
[Header("Controller Settings")]
|
|
[SerializeField] private float gamepadDeadzone = 0.2f;
|
|
[SerializeField] private AnimationCurve gamepadInputCurve = AnimationCurve.Linear(0, 0, 1, 1);
|
|
|
|
[Header("Debug Visualization")]
|
|
[SerializeField] private bool showDebugVisuals = false;
|
|
|
|
private Transform target;
|
|
private NavMeshAgent agent;
|
|
private Vector3 direction = Vector3.zero;
|
|
private Quaternion lookRotation = Quaternion.identity;
|
|
private Camera mainCamera;
|
|
private Plane groundPlane;
|
|
private Vector2 lastGamepadAimInput;
|
|
private Vector3 lastAimDirection;
|
|
private bool isUsingGamepad;
|
|
private Vector3 currentMoveDirection;
|
|
private bool isMoving;
|
|
private PhotonView photonView;
|
|
private ProjectileSpawnLocationController aimController;
|
|
private Vector3 currentAimPoint;
|
|
private bool isAiming;
|
|
|
|
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 void Awake()
|
|
{
|
|
agent = GetComponent<NavMeshAgent>();
|
|
photonView = GetComponent<PhotonView>();
|
|
mainCamera = Camera.main;
|
|
groundPlane = new Plane(Vector3.up, Vector3.zero);
|
|
aimController = GetComponentInChildren<ProjectileSpawnLocationController>();
|
|
lastAimDirection = transform.forward;
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
if (!photonView.IsMine)
|
|
{
|
|
this.enabled = false;
|
|
return;
|
|
}
|
|
|
|
SetupAgentForDirectionalMovement();
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (movementType == MovementType.DirectionalInput)
|
|
{
|
|
DetectInputMethod();
|
|
|
|
// Handle movement first
|
|
HandleDirectionalMovement();
|
|
|
|
// Then handle aiming, with mouse taking priority
|
|
if (!isUsingGamepad)
|
|
{
|
|
HandleMouseAiming();
|
|
}
|
|
else
|
|
{
|
|
HandleGamepadAiming();
|
|
hasMouseAimPoint = false; // Reset mouse aim when using gamepad
|
|
}
|
|
|
|
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 DetectInputMethod()
|
|
{
|
|
Vector2 gamepadMove = new Vector2(
|
|
Input.GetAxisRaw(GameConstants.Input.HorizontalAxis),
|
|
Input.GetAxisRaw(GameConstants.Input.VerticalAxis));
|
|
Vector2 gamepadLook = new Vector2(
|
|
Input.GetAxisRaw(GameConstants.Input.AimHorizontalAxis),
|
|
Input.GetAxisRaw(GameConstants.Input.AimVerticalAxis));
|
|
|
|
// Check for mouse movement
|
|
if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0)
|
|
{
|
|
isUsingGamepad = false;
|
|
return;
|
|
}
|
|
|
|
// Check for gamepad input
|
|
if (gamepadMove.magnitude > gamepadDeadzone || gamepadLook.magnitude > gamepadDeadzone)
|
|
{
|
|
isUsingGamepad = true;
|
|
hasMouseAimPoint = false; // Reset mouse aim when using gamepad
|
|
}
|
|
}
|
|
|
|
private void HandleDirectionalMovement()
|
|
{
|
|
if (agent.isStopped) return;
|
|
|
|
currentMovementDirection = new Vector2(
|
|
Input.GetAxisRaw(GameConstants.Input.HorizontalAxis),
|
|
Input.GetAxisRaw(GameConstants.Input.VerticalAxis));
|
|
|
|
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 HandleAimingRotation()
|
|
{
|
|
if (isUsingGamepad)
|
|
{
|
|
HandleGamepadAiming();
|
|
}
|
|
else
|
|
{
|
|
HandleMouseAiming();
|
|
}
|
|
}
|
|
|
|
private void HandleGamepadAiming()
|
|
{
|
|
currentAimDirection = new Vector2(
|
|
Input.GetAxisRaw(GameConstants.Input.AimHorizontalAxis),
|
|
Input.GetAxisRaw(GameConstants.Input.AimVerticalAxis)
|
|
);
|
|
|
|
if (currentAimDirection.magnitude > gamepadDeadzone)
|
|
{
|
|
isAiming = true;
|
|
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
|
|
);
|
|
}
|
|
// Remove the else { isAiming = false; } - we want to maintain the last aim direction
|
|
// Instead, maintain the last valid aim direction
|
|
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
|
|
// Cross product for left/right movement
|
|
relativeMovementDirection.x = lastAimDirection2.x * currentMovementDirection.y -
|
|
lastAimDirection2.y * currentMovementDirection.x;
|
|
}
|
|
private void HandleMouseAiming()
|
|
{
|
|
Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
|
|
|
|
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;
|
|
|
|
// Always update rotation when using mouse
|
|
transform.rotation = Quaternion.LookRotation(aimDirection);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandlePointAndClickMovement()
|
|
{
|
|
agent.SetDestination(target.position);
|
|
FaceTarget();
|
|
}
|
|
|
|
private void SetupAgentForDirectionalMovement()
|
|
{
|
|
agent.updateRotation = false;
|
|
agent.stoppingDistance = 0f;
|
|
agent.acceleration = 100f;
|
|
agent.angularSpeed = 0f;
|
|
}
|
|
|
|
#region Public Methods
|
|
|
|
public void SetMovementType(MovementType type)
|
|
{
|
|
movementType = type;
|
|
if (movementType == MovementType.DirectionalInput)
|
|
{
|
|
SetupAgentForDirectionalMovement();
|
|
}
|
|
else
|
|
{
|
|
agent.updateRotation = true;
|
|
agent.stoppingDistance = 0.5f;
|
|
agent.acceleration = 8f;
|
|
agent.angularSpeed = 120f;
|
|
}
|
|
}
|
|
|
|
public void ToggleAgentMoving(bool busy)
|
|
{
|
|
agent.isStopped = busy;
|
|
if (busy)
|
|
{
|
|
agent.SetDestination(transform.position);
|
|
}
|
|
}
|
|
|
|
public void MoveToPoint(Vector3 point)
|
|
{
|
|
agent.SetDestination(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 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
|
|
} |