Files
beyond/Assets/Scripts/Utils/DirectioIndicator.cs
2024-11-20 15:21:28 +01:00

313 lines
9.9 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
//using Mono.Cecil;
using PixelCrushers.DialogueSystem;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UI;
namespace Beyond
{
public class DirectioIndicator : MonoBehaviour
{
// Start is called before the first frame update
private Renderer m_renderer;
private Material m_material;
public Color m_baseColor;
public float m_minDistance = 5f;
public float m_FadeDistance = 10f;
public float m_refreshDistance = 2f;
public float m_fadeTime = 1f;
public float m_timeOut = 5f;
// public bool m_showNewTarget = false;
private NavMeshPath m_lastPath;
private Vector3 m_lastPlayerPos;
private Quaternion m_lastDirection;
private Transform m_lastTarget;
private float m_lastDistance;
private float lerpRate = 1f;
private float m_timer;
private float m_refreshTimer = 0f;
[SerializeField]
private float m_distanceTh = 1f;
[SerializeField] private float m_distanceUpdateTime = 2;
public State m_state = State.IDLE;
public bool m_showAllTheTime = false;
public enum State
{
IDLE,
FADE_IN,
TARGET,
TARGET_TIMEOUT,
FADE_OUT,
}
void SetState(State s)
{
Debug.Log("State: " + s);
switch (s)
{
case State.IDLE:
m_lastDistance = Single.MaxValue;
if (!m_showAllTheTime)
m_renderer.enabled = false;
break;
case State.FADE_IN:
m_renderer.enabled = true;
m_material.color = Color.black;
break;
case State.FADE_OUT:
break;
case State.TARGET:
//m_lastDistance = Single.MaxValue;
if (m_showAllTheTime)
{
m_renderer.enabled = true;
}
break;
case State.TARGET_TIMEOUT:
break;
}
m_timer = 0f;
m_state = s;
}
void Start()
{
m_renderer = GetComponentInChildren<Renderer>();
m_material = m_renderer.material;
m_lastPath = new NavMeshPath();
SetState(State.IDLE);
}
void GetTargetPoint(Vector3 target)
{
var playerTrans = Player.Instance.transform;
NavMesh.CalculatePath(playerTrans.position, target, NavMesh.AllAreas, m_lastPath);
}
bool ShouldRefreshPath(Transform target)
{
if (m_lastTarget != target)
return true;
Vector3 diff = m_lastPlayerPos - target.position;
diff.y = 0f;
m_refreshTimer += Time.deltaTime;
bool result = diff.magnitude > m_refreshDistance || m_refreshTimer > 1f;
if (result)
{
m_refreshTimer = 0f;
}
return result;
}
Vector3 GetDirection(Transform target, Vector3 playerPos, out float distance)
{
distance = Single.MaxValue;
Vector3 targetPos = target.position;
Vector3 diff = targetPos - playerPos;
diff.y = 0f;
distance = diff.magnitude;
diff /= distance;
if (distance < m_FadeDistance)
{
return diff;
}
if (ShouldRefreshPath(target))
{
if (NavMesh.CalculatePath(playerPos, targetPos, NavMesh.AllAreas, m_lastPath))
{
m_lastPlayerPos = playerPos;
}
else
{
return diff;
}
}
if (m_lastPath == null || m_lastPath.corners.Length == 0)
{
return diff;
}
float pointDist = 0f;
for (int id=0; id<m_lastPath.corners.Length; id++)
{
diff = m_lastPath.corners[id] - playerPos;
diff.y = 0f;
pointDist = diff.magnitude;
diff /= pointDist;
if (pointDist > m_minDistance)
{
break;
}
}
return diff;
}
// Update is called once per frame
void Update()
{
if (Compass.Instance == null)
{
return;
}
var playerTrans = Player.Instance.transform;
var target = Compass.Instance.FindClosestIndicator(playerTrans);
float distance = Single.MaxValue;
if (target != null)
{
var direction = GetDirection(target, playerTrans.position, out distance);
if (distance > m_minDistance)
{
var dir = Quaternion.LookRotation(direction.normalized);
transform.rotation = Quaternion.Slerp(m_lastDirection, dir,
1f - MathF.Pow(2, -Time.deltaTime * lerpRate));
m_lastDirection = transform.rotation;
}
if (target != m_lastTarget)
m_lastDistance = distance;
}
float a = 0f;
switch (m_state)
{
case State.IDLE:
if (target != null)
{
if (m_lastDistance == Single.MaxValue)
m_lastDistance = distance;
if (GameStateManager.Instance.CurrentState == GameStateManager.State.COMBAT)
return;
if (m_showAllTheTime)
{
SetState(State.TARGET);
break;
}
if (distance > m_FadeDistance && distance > m_lastDistance + m_distanceTh)
{
SetState(State.FADE_IN);
}
else if (m_timer > m_distanceUpdateTime)
{
m_timer = 0f;
m_lastDistance = distance;
}
}
break;
case State.FADE_IN:
a = (m_timer / m_fadeTime);
if (a < 1)
{
m_material.color = m_baseColor * a;
}
else
{
m_material.color = m_baseColor;
SetState(State.TARGET);
}
break;
case State.TARGET:
if (m_showAllTheTime)
break;
if (target != null)
{
if (distance < m_FadeDistance || (m_timer > m_timeOut && distance + m_distanceTh < m_lastDistance))
{
SetState(State.FADE_OUT);
m_lastDistance = distance;
}
}
else
{
SetState(State.FADE_OUT);
}
break;
case State.FADE_OUT:
a = (m_timer / m_fadeTime);
if (a < 1)
{
m_material.color = m_baseColor * (1-a);
}
else
{
m_material.color = Color.black;
SetState(State.TARGET_TIMEOUT);
/*
if (!m_showNewTarget)
{
m_lastDistance = distance;
}
*/
}
break;
case State.TARGET_TIMEOUT:
if (m_timer > m_timeOut)
{
/*
if (distance > m_lastDistance + m_distanceTh)
{
SetState(State.FADE_IN);
}
else
{
m_timer = 0f;
m_lastDistance = distance;
}
*/
SetState(State.IDLE);
}
break;
}
m_timer += Time.deltaTime;
m_lastTarget = target;
}
private void OnDrawGizmos()
{
if (Player.Instance == null)
return;
var playerTrans = Player.Instance.transform;
var target = Compass.Instance.FindClosestIndicator(playerTrans);
float distance = 0f;
if (target != null)
{
var direction = GetDirection(target, playerTrans.position, out distance);
Gizmos.color = Color.red;
Gizmos.DrawRay(playerTrans.position, direction*distance);
Gizmos.color = Color.blue;
if (m_lastPath != null && m_lastPath.corners.Length > 1)
{
for (int id = 0; id < m_lastPath.corners.Length-1; id++)
{
Gizmos.DrawLine(m_lastPath.corners[id], m_lastPath.corners[id+1]);
}
}
}
}
}
}