using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class NavCalcScript : MonoBehaviour { [NonSerialized] public GameObject character; [NonSerialized] public GameObject target; [NonSerialized] public Vector3 bestPosition = Vector3.zero; public GameObject testAgent; public GameObject cube; private List<GameObject> _obstacles = new List<GameObject>(); private GameObject[] _points; private List<Transform> _pointsListA = new List<Transform>(); private List<Transform> _pointsListB = new List<Transform>(); private List<Transform> _pointsListC = new List<Transform>(); private NavMeshPath _path; private float _shortestPath = 999; private float _currPath; private float _attackRange; private float _size; private Transform _bestPoint; private bool _atk; private bool _abl; private bool _mng; private bool _withinRange; private CharacterStats _charStats; private bool _turnOn; private Vector3 _position; // Start is called before the first frame update void Start() { _points = GameObject.FindGameObjectsWithTag("AttackPoint"); _path = new NavMeshPath(); if (_turnOn) { CheckForObstacles(); } } public void CalculateBestPosition(bool attack, bool ability, bool mining, CharacterStats stats, GameObject trg, Vector3 position, float attackRange, bool withinRng) { _atk = attack; _abl = ability; _mng = mining; _charStats = stats; target = trg; _withinRange = withinRng; _attackRange = attackRange; character = _charStats.gameObject; if (target == null) { _position = position; } else { _position = target.transform.position; } if (_withinRange) { _size = Vector3.Distance(character.transform.position, _position); } else { _size = _attackRange; } transform.localScale = new Vector3(_size*2, 0.1f, _size*2); _turnOn = true; } private Vector3 CalculateRay(Vector3 originPos, Vector3 targetPos) { float distance = Vector3.Distance(originPos, targetPos); Vector3 directionOfTravel = targetPos - originPos; Vector3 finalDirection = directionOfTravel.normalized * distance; return finalDirection; } private void CheckForObstacles() { foreach (var point in _points) { if (point.transform.IsChildOf(transform)) { _obstacles.Clear(); var origin = point.transform.position; origin.y += 1.5f; var direction = CalculateRay(origin, _position); Debug.DrawRay(origin, direction, Color.green, 10f, false); Ray aimRay = new Ray(origin, direction); if (Physics.Raycast(aimRay, out var targetHit, Mathf.Infinity, LayerMask.GetMask("Static", "Barrel", "Character", "HoverCharacter"))) { _obstacles.Add(targetHit.transform.gameObject); //Debug.Log(targetHit.transform.name + " was found"); } _obstacles.Remove(point.gameObject); _obstacles.Remove(target); if (_obstacles.Count == 0) { _pointsListA.Add(point.transform); } } } CheckForNavMesh(); } private void CheckForNavMesh() { //Debug.Log("List A: " + _pointsListA.Count); foreach (var point in _pointsListA) { //Instantiate(cube, point.transform.position, Quaternion.identity); GameObject testObject = Instantiate(testAgent, point.transform.position, Quaternion.identity); float onMeshThreshold = 1; Vector3 objectPosition = testObject.transform.position; NavMeshHit hit; // Check for nearest point on navmesh to agent, within onMeshThreshold if (NavMesh.SamplePosition(testObject.transform.position, out hit, onMeshThreshold, NavMesh.AllAreas)) { // Check if the positions are vertically aligned if (Mathf.Approximately(objectPosition.x, hit.position.x) && Mathf.Approximately(objectPosition.z, hit.position.z)) { _pointsListB.Add(point); } } Destroy(testObject); } CheckForPath(); } private void CheckForPath() { //Debug.Log("List B: " + _pointsListB.Count); foreach (var point in _pointsListB) { if (NavMesh.CalculatePath(point.transform.position, character.transform.position, NavMesh.AllAreas, _path)) { if (_path.status == NavMeshPathStatus.PathComplete) { _pointsListC.Add(point); //Debug.Log(character.name + " Path exists"); } } } FindShortestPath(); } private static float GetPathLength(NavMeshPath path) { float lng = 0.0f; for (int i = 1; i < path.corners.Length; ++i) { lng += Vector3.Distance(path.corners[i - 1], path.corners[i]); } return lng; } private float GetPathLengthB(Vector3 pointPos) { var navAgent = character.GetComponent<NavMeshAgent>(); navAgent.isStopped = false; navAgent.SetDestination(pointPos); float lng = navAgent.remainingDistance; navAgent.isStopped = true; Debug.Log(lng); return lng; } private void FindShortestPath() { //Debug.Log("List C: " + _pointsListC.Count); foreach (var point in _pointsListC) { NavMesh.CalculatePath(point.transform.position, character.transform.position, NavMesh.AllAreas, _path); _currPath = GetPathLength(_path); //_currPath = GetPathLengthB(point.transform.position); if (_currPath < _shortestPath && _currPath != 0) { _shortestPath = _currPath; _bestPoint = point; } } if (_bestPoint != null) { bestPosition = _bestPoint.position; //Debug.Log("found position"); _charStats.Move(target, bestPosition, _atk, _mng, _abl); Destroy(gameObject); } else { if (_withinRange && _size < _attackRange) { Debug.Log("NavCalc trying new size"); _size += 1; transform.localScale = new Vector3(_size*2, 0.1f, _size*2); CheckForObstacles(); } else { Debug.Log(_charStats.name + "Too far away"); _charStats.StartEndTurn(); Destroy(gameObject); } } } }