Files
2026-05-08 11:04:00 +08:00

136 lines
4.8 KiB
C#

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace PathBerserker2d
{
internal static class NavSurfaceDrawer
{
[DrawGizmo(GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)]
public static void DrawGizmos(NavSurface surface, GizmoType gizmoType)
{
if (surface.NavSegments != null && !Application.IsPlaying(surface) && (PathBerserker2dSettings.DrawUnselectedSurfaces || (gizmoType & GizmoType.Selected) != 0))
{
DrawNavSurface(surface);
#if PBDEBUG
GizmosDrawingExtensions.DrawRect(surface.WorldBounds);
#endif
}
}
private static bool[] visited;
private static Dictionary<NavSurface, List<Mesh>> miterLinesMap;
public static void DrawNavSurface(NavSurface surface)
{
if (miterLinesMap == null)
miterLinesMap = new Dictionary<NavSurface, List<Mesh>>();
List<Mesh> miterLines = null;
miterLinesMap.TryGetValue(surface, out miterLines);
if (surface.hasDataChanged || miterLines == null)
{
if (visited == null || visited.Length < surface.NavSegments.Count)
{
visited = new bool[surface.NavSegments.Count];
}
else
{
for (int i = 0; i < visited.Length; i++)
{
visited[i] = false;
}
}
var miterCreator = new MiterLineMeshCreator();
bool newMiterLines = miterLines == null;
if (newMiterLines)
miterLines = new List<Mesh>();
int lineCount = 0;
for (int i = 0; i < surface.NavSegments.Count; i++)
{
if (!visited[i])
{
var points = GatherContourPoints(surface, surface.NavSegments[i], ref visited);
if (lineCount >= miterLines.Count)
{
miterLines.Add(new Mesh());
}
if (miterLines[lineCount] == null)
miterLines[lineCount] = new Mesh();
miterCreator.CreateLine(miterLines[lineCount], points, PathBerserker2dSettings.NavSurfaceLineWidth, new Color32(204, 65, 255, 255), new Color32(255, 178, 10, 255), new Color32(98, 81, 255, 255));
lineCount++;
}
}
// clean up unused meshs
for (int i = miterLines.Count - 1; i >= lineCount; i--)
{
GameObject.DestroyImmediate(miterLines[i]);
miterLines.RemoveAt(i);
}
if (newMiterLines)
miterLinesMap.Add(surface, miterLines);
surface.hasDataChanged = false;
}
SharedMaterials.UnlitVertexColorSolid.SetPass(0);
if (miterLines.Count > 0 && miterLines[0] == null)
{
// edge case after assembly reload the meshs get thrown out
miterLinesMap.Clear();
return;
}
foreach (var ml in miterLines)
{
Graphics.DrawMeshNow(ml, surface.LocalToWorldMatrixEditor);
}
}
private static List<Vector2> GatherContourPoints(NavSurface surface, NavSegment initialSeg, ref bool[] visited)
{
List<Vector2> contourPoints = new List<Vector2>();
if (!initialSeg.HasPrev)
{
contourPoints.Add(initialSeg.Start);
}
contourPoints.Add(initialSeg.End);
NavSegment seg = initialSeg;
while (seg.HasNext && !visited[seg.NextSegmentIndex])
{
visited[seg.NextSegmentIndex] = true;
seg = surface.NavSegments[seg.NextSegmentIndex];
contourPoints.Add(seg.End);
}
if (initialSeg.HasPrev && !visited[initialSeg.PrevSegmentIndex])
{
// we might have missed segments to the left get em
List<Vector2> leftPoints = new List<Vector2>();
seg = initialSeg;
while (seg.HasPrev)
{
visited[seg.PrevSegmentIndex] = true;
seg = surface.NavSegments[seg.PrevSegmentIndex];
leftPoints.Add(seg.End);
}
leftPoints.Add(seg.Start);
leftPoints.Reverse();
leftPoints.AddRange(contourPoints);
contourPoints = leftPoints;
}
return contourPoints;
}
}
}