using RPG.Attributes;
using RPG.Movement;
using System;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;
namespace RPG.Control
{
public class PlayerController : MonoBehaviour
{
Health health = null;
[Serializable]
public struct CursorMapping
{
public CursorType type;
public Texture2D texture;
public Vector2 hotspot;
}
[SerializeField] CursorMapping[] cursorMappings = null;
[SerializeField] float maxNavMeshProjectionDistance = 1.0f;
[SerializeField] float maxPathLength = 40.0f;
void Awake()
{
health = GetComponent<Health>();
}
void Update()
{
if (InteractWithUI()) { return; }
if (health.IsDead())
{
SetCursor(CursorType.None);
return;
}
if (InteractWithComponent()) { return; }
if (InteractWithMovement()) { return; }
SetCursor(CursorType.None);
}
private bool InteractWithUI()
{
if (EventSystem.current.IsPointerOverGameObject())
{
SetCursor(CursorType.UI);
return true;
}
return false;
}
private bool InteractWithComponent()
{
RaycastHit[] hits = RaycastAllSorted();
foreach (RaycastHit hit in hits)
{
IRaycastable[] raycastables = hit.transform.GetComponents<IRaycastable>();
foreach (IRaycastable raycastable in raycastables)
{
if (raycastable.HandleRaycast(this))
{
SetCursor(raycastable.GetCursorType());
return true;
}
}
}
return false;
}
private bool InteractWithMovement()
{
Vector3 target;
bool hasHit = RaycastNavMesh(out target);
if (hasHit)
{
if (Input.GetMouseButton(0))
{
GetComponent<Mover>().StartMoveAction(target, 1f);
}
SetCursor(CursorType.Movement);
return true;
}
return false;
}
private bool RaycastNavMesh(out Vector3 target)
{
target = new Vector3();
RaycastHit hit;
bool hasHit = Physics.Raycast(GetMouseRay(), out hit);
if (!hasHit)
{
return false;
}
NavMeshHit navMeshHit;
bool hasCastToNavMesh = NavMesh.SamplePosition(hit.point, out navMeshHit, maxNavMeshProjectionDistance, NavMesh.AllAreas);
if (!hasCastToNavMesh)
{
//NavMeshPath tempPath = new NavMeshPath();
//target = navMeshHit.position;
//NavMesh.CalculatePath(transform.position, hit.point, NavMesh.AllAreas, tempPath);
Debug.Log($"Hit point {hit.point}.");
//Debug.Log(target);
//Debug.Log(GetPathLength(tempPath));
Debug.Log($"NavMeshHit position = {navMeshHit.position}.");
Debug.Log("Has not cast to navmesh");
return false;
}
target = navMeshHit.position;
NavMeshPath path = new NavMeshPath();
bool hasPath = NavMesh.CalculatePath(transform.position, target, NavMesh.AllAreas, path);
if (!hasPath)
{
return false;
}
if (path.status != NavMeshPathStatus.PathComplete)
{
return false;
}
if (GetPathLength(path) > maxPathLength)
{
return false;
}
Debug.Log($"Hit point {hit.point} and NavMeshHitPosition {navMeshHit.position}.");
return true;
}
private float GetPathLength(NavMeshPath path)
{
float total = 0.0f;
if (path.corners.Length < 2) { return total; }
for (int i = 1; i < path.corners.Length; i++)
{
total += Vector3.Distance(path.corners[i - 1], path.corners[i]);
}
return total;
}
private void SetCursor(CursorType type)
{
CursorMapping mapping = GetCursorMapping(type);
Cursor.SetCursor(mapping.texture, mapping.hotspot, CursorMode.Auto);
}
private CursorMapping GetCursorMapping(CursorType type)
{
foreach (CursorMapping mapping in cursorMappings)
{
if (mapping.type == type)
{
return mapping;
}
}
return cursorMappings[0];
}
private RaycastHit[] RaycastAllSorted()
{
RaycastHit[] hits = Physics.RaycastAll(GetMouseRay());
float[] distances = new float[hits.Length];
for (int i = 0; i < hits.Length; i++)
{
distances[i] = hits[i].distance;
}
Array.Sort(distances, hits);
return hits;
}
private Ray GetMouseRay()
{
return Camera.main.ScreenPointToRay(Input.mousePosition);
}
}
}