Skip to content

Instantly share code, notes, and snippets.

@phosphoer
Created June 18, 2022 22:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save phosphoer/0c530efebbc62ed442409e7819c0db80 to your computer and use it in GitHub Desktop.
Save phosphoer/0c530efebbc62ed442409e7819c0db80 to your computer and use it in GitHub Desktop.
using UnityEngine;
using UnityEngine.AI;
using System.Collections.Generic;
public class PathFindManager : Singleton<PathFindManager>
{
public bool IsBuilt => _isBuilt;
[SerializeField]
private LayerMask _obstacleMask = Physics.DefaultRaycastLayers;
[SerializeField]
private bool _generateDebugOnStart = false;
private bool _isBuilt;
private Bounds _worldBounds;
private NavMeshData _navMesh;
private NavMeshPath _path;
private static List<NavMeshBuildSource> _navMeshBuildSources = new List<NavMeshBuildSource>();
private static List<NavMeshBuildMarkup> _navMeshMarkups = new List<NavMeshBuildMarkup>();
private static List<PathFindObject> _pathFindObjects = new List<PathFindObject>();
#if UNITY_EDITOR
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void EditorStaticReset()
{
_navMeshBuildSources = new List<NavMeshBuildSource>();
_navMeshMarkups = new List<NavMeshBuildMarkup>();
_pathFindObjects = new List<PathFindObject>();
}
#endif
public static void AddObject(PathFindObject pathFindObject)
{
_pathFindObjects.Add(pathFindObject);
}
public static void RemoveObject(PathFindObject pathFindObject)
{
_pathFindObjects.Remove(pathFindObject);
}
public void GenerateGrid(Vector3 minCorner, Vector3 maxCorner)
{
_worldBounds.min = minCorner;
_worldBounds.max = maxCorner;
// Find all nav mesh object sources in the scene
NavMeshBuilder.CollectSources(_worldBounds, _obstacleMask, NavMeshCollectGeometry.PhysicsColliders, 1, _navMeshMarkups, _navMeshBuildSources);
for (int i = 0; i < _pathFindObjects.Count; ++i)
{
_navMeshBuildSources.Add(_pathFindObjects[i].Source);
}
// Add a source to represent the 'ground' plane
NavMeshBuildSource groundSource = default(NavMeshBuildSource);
groundSource.area = 0;
groundSource.shape = NavMeshBuildSourceShape.Box;
groundSource.size = _worldBounds.size.WithY(0.1f);
groundSource.transform = Matrix4x4.identity * Matrix4x4.Translate(_worldBounds.center.WithY(0));
_navMeshBuildSources.Add(groundSource);
// Build settings for default agent
NavMeshBuildSettings buildSettings = NavMesh.GetSettingsByID(0);
// Create or update the nav mesh
if (_navMesh == null)
{
_navMesh = NavMeshBuilder.BuildNavMeshData(buildSettings, _navMeshBuildSources, _worldBounds, Vector3.zero, Quaternion.identity);
NavMesh.AddNavMeshData(_navMesh);
}
else
{
NavMeshBuilder.UpdateNavMeshData(_navMesh, buildSettings, _navMeshBuildSources, _worldBounds);
}
_isBuilt = true;
}
public void RebuildGrid(bool skipIfNotBuilt = false)
{
if (!_isBuilt)
{
if (skipIfNotBuilt)
return;
Debug.LogError("Attempt to rebuild grid without ever being initialized");
return;
}
Debug.Log("Rebuilding pathfind grid");
GenerateGrid(_worldBounds.min, _worldBounds.max);
}
public bool IsPointTraversable(Vector3 worldPoint)
{
worldPoint = worldPoint.WithY(0);
if (_worldBounds.Contains(worldPoint))
{
NavMeshHit navMeshHit;
if (NavMesh.SamplePosition(worldPoint, out navMeshHit, 3f, NavMesh.AllAreas))
{
return true;
}
else
{
return false;
}
}
return true;
}
public bool CalculatePathToPoint(Vector3 fromPoint, Vector3 toPoint, List<Vector3> outPath)
{
outPath.Clear();
if (!IsPointTraversable(fromPoint))
{
NavMeshHit navMeshHit;
if (NavMesh.SamplePosition(fromPoint, out navMeshHit, 50f, NavMesh.AllAreas))
{
fromPoint = navMeshHit.position;
}
}
if (!IsPointTraversable(toPoint))
{
NavMeshHit navMeshHit;
if (NavMesh.SamplePosition(toPoint, out navMeshHit, 50f, NavMesh.AllAreas))
{
toPoint = navMeshHit.position;
}
}
if (NavMesh.CalculatePath(fromPoint, toPoint, NavMesh.AllAreas, _path))
{
outPath.AddRange(_path.corners);
return true;
}
return false;
}
private void Awake()
{
Instance = this;
_path = new NavMeshPath();
}
private void Start()
{
if (_generateDebugOnStart)
DebugBuildGrid();
}
[ContextMenu("Build Debug")]
private void DebugBuildGrid()
{
GenerateGrid(Vector3.one.WithY(0) * -500, Vector3.one.WithY(0) * 500);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment