chore: initial commit

This commit is contained in:
2026-05-08 11:04:00 +08:00
commit f55d2a57c3
6278 changed files with 866081 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 91a2221b1f964c946af33b7bb66b948d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using UnityEditor;
using UnityEngine;
namespace PathBerserker2d
{
[CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
internal class ReadOnlyAttributeDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property, label, true);
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
bool oldValue = GUI.enabled;
GUI.enabled = false;
EditorGUI.PropertyField(position, property, label, true);
GUI.enabled = oldValue;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bfac06ae39b4da041b0233fbe194c0a2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1df174b62e1d3684f9fc16ede26d1866
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,51 @@
using UnityEngine;
using UnityEditor;
namespace PathBerserker2d
{
internal class IconHandle2D
{
private static readonly int controlHashIcon = "IconHandle2D_icon".GetHashCode();
public static void DrawHandle(Vector3 position, Texture icon, float size, Object objectToSelect)
{
int iconId = EditorGUIUtility.GetControlID(controlHashIcon, FocusType.Passive);
var e = Event.current;
switch (e.type)
{
case EventType.MouseDown:
if (e.button == 0 && HandleUtility.nearestControl == iconId)
{
Selection.activeObject = objectToSelect;
e.Use();
}
break;
case EventType.Layout:
float distance = HandleUtility.DistanceToRectangle(position, Camera.current.transform.rotation, size);
HandleUtility.AddControl(iconId, distance);
break;
case EventType.Repaint:
Vector3 up = Camera.current.transform.up * size;
float aspectRatio = (float)icon.width / (float)icon.height;
Vector3 right = Camera.current.transform.right * size * aspectRatio;
SharedMaterials.UnlitTexture.SetTexture("_MainTex", icon);
SharedMaterials.UnlitTexture.SetPass(0);
GL.Begin(GL.QUADS);
{
GL.TexCoord2(1, 1);
GL.Vertex(position + right + up);
GL.TexCoord2(1, 0);
GL.Vertex(position + right - up);
GL.TexCoord2(0, 0);
GL.Vertex(position - right - up);
GL.TexCoord2(0, 1);
GL.Vertex(position - right + up);
}
GL.End();
break;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 99480f75d87fac34c9ad4d0125d7a2e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0e5d17af10e083841ac8d81ba70fd984
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,73 @@
using UnityEditor;
using UnityEngine;
namespace PathBerserker2d
{
internal static class MyGUI
{
public static string nameSeed = "aWJhcmFraQ==";
public static string nameSeed2 = "aWJhcl9ha2k=";
static GUIStyle horizontalLine;
static MyGUI()
{
horizontalLine = new GUIStyle();
horizontalLine.normal.background = EditorGUIUtility.whiteTexture;
horizontalLine.margin = new RectOffset(0, 0, 4, 4);
horizontalLine.fixedHeight = 1;
}
// utility method
public static void HorizontalLine(Color color)
{
var c = GUI.color;
GUI.color = color;
GUILayout.Box(GUIContent.none, horizontalLine);
GUI.color = c;
}
public static void Header(string text)
{
EditorGUILayout.LabelField(text, EditorStyles.boldLabel);
}
public static void DrawNavTagLayout(SerializedProperty spNavTag)
{
EditorGUILayout.BeginHorizontal();
spNavTag.intValue = EditorGUILayout.Popup("NavTag", spNavTag.intValue, PathBerserker2dSettings.NavTags);
if (GUILayout.Button("+", EditorStyles.miniButtonRight, GUILayout.Width(17)))
{
SettingsService.OpenProjectSettings(PathBerserker2dSettingsProvider.WindowPath);
}
EditorGUILayout.EndHorizontal();
}
public static void DrawNavTagColorPickerLayout(SerializedProperty spNavTag)
{
int tag = spNavTag.intValue;
if (tag == 0)
GUI.enabled = false;
PathBerserker2dSettings.SetNavTagColor(tag, EditorGUILayout.ColorField("NavTag Color", PathBerserker2dSettings.GetNavTagColor(tag)));
GUI.enabled = true;
}
public static void ProVersionOnlyLabelLayout()
{
EditorGUILayout.LabelField(ProVersionOnly);
}
public static void ProVersionLinkTypeLabelLayout()
{
EditorGUILayout.LabelField("Custom link types are limited to the pro-version.");
}
public static GUIContent AddProVersionOnlyToolTipp(string label)
{
return new GUIContent(label, ProVersionOnly);
}
public const string ProVersionOnly = "This is a pro-version only feature";
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 88926f52dae6ae348a100721fd59f003
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,137 @@
using UnityEngine;
using UnityEditor;
namespace PathBerserker2d
{
internal class PositionHandle2D
{
private Vector3 startPos;
private Vector2 currentMousePos;
private Vector2 startMousePos;
public Color primary;
public Color hover;
public Color selected;
private int hash;
public PositionHandle2D(Color primary, Color hover, Color selected)
{
this.primary = primary;
this.hover = hover;
this.selected = selected;
hash = GetHashCode();
}
public Vector2 DrawHandle(Vector2 position)
{
int controlIdXArrow = EditorGUIUtility.GetControlID(hash, FocusType.Passive);
int controlIdYArrow = EditorGUIUtility.GetControlID(hash, FocusType.Passive);
int controlIdRect = EditorGUIUtility.GetControlID(hash, FocusType.Passive);
bool selectedXArrow = GUIUtility.hotControl == controlIdXArrow;
bool hoveredXArrow = HandleUtility.nearestControl == controlIdXArrow;
bool selectedYArrow = GUIUtility.hotControl == controlIdYArrow;
bool hoveredYArrow = HandleUtility.nearestControl == controlIdYArrow;
bool selectedRect = GUIUtility.hotControl == controlIdRect;
bool hoveredRect = HandleUtility.nearestControl == controlIdRect;
var e = Event.current;
switch (e.type)
{
case EventType.MouseDown:
if (e.button == 0 && GUIUtility.hotControl == 0 && !e.alt)
{
if (HandleUtility.nearestControl == controlIdXArrow)
{
GUIUtility.hotControl = controlIdXArrow;
}
else if (HandleUtility.nearestControl == controlIdYArrow)
{
GUIUtility.hotControl = controlIdYArrow;
}
else if (HandleUtility.nearestControl == controlIdRect)
{
GUIUtility.hotControl = controlIdRect;
}
if (HandleUtility.nearestControl == controlIdXArrow ||
HandleUtility.nearestControl == controlIdYArrow ||
HandleUtility.nearestControl == controlIdRect)
{
startPos = position;
currentMousePos = e.mousePosition;
startMousePos = e.mousePosition;
e.Use();
}
}
break;
case EventType.MouseUp:
if (e.button == 0 || e.button == 2)
{
if (GUIUtility.hotControl == controlIdXArrow || GUIUtility.hotControl == controlIdYArrow || GUIUtility.hotControl == controlIdRect)
{
GUIUtility.hotControl = 0;
e.Use();
selectedXArrow = false;
selectedYArrow = false;
selectedRect = false;
}
}
break;
case EventType.MouseDrag:
if (GUIUtility.hotControl == controlIdXArrow || GUIUtility.hotControl == controlIdYArrow || GUIUtility.hotControl == controlIdRect)
{
currentMousePos += new Vector2(e.delta.x, -e.delta.y) * EditorGUIUtility.pixelsPerPoint;
Vector3 screenPos = Camera.current.WorldToScreenPoint(Handles.matrix.MultiplyPoint(startPos));
screenPos += (Vector3)(currentMousePos - startMousePos);
Vector2 newPos = Handles.inverseMatrix.MultiplyPoint(Camera.current.ScreenToWorldPoint(screenPos));
if (selectedXArrow)
{
newPos.y = startPos.y;
}
else if (selectedYArrow)
{
newPos.x = startPos.x;
}
if (newPos != position)
{
position = newPos;
GUI.changed = true;
}
e.Use();
}
break;
}
Handles.color = selectedRect || selectedXArrow ? selected : (hoveredXArrow ? hover : primary);
Handles.ArrowHandleCap(controlIdXArrow, position, Quaternion.Euler(0, 90, 0), HandleUtility.GetHandleSize(position), e.type);
Handles.color = selectedRect || selectedYArrow ? selected : (hoveredYArrow ? hover : primary);
Handles.ArrowHandleCap(controlIdYArrow, position, Quaternion.Euler(-90, 0, 0), HandleUtility.GetHandleSize(position), e.type);
Handles.color = selectedRect ? selected : (hoveredRect ? hover : primary);
float rectSize = HandleUtility.GetHandleSize(position) * 0.14f;
Vector2 rectPos = position + Vector2.one * rectSize;
if (e.type == EventType.Repaint)
Handles.DrawSolidRectangleWithOutline(new Rect(position, new Vector2(rectSize, rectSize) * 2f), new Color(1, 1, 1, 0.2f), new Color(1, 1, 1, 1));
rectPos = Handles.Slider2D(rectPos, Vector3.forward, Vector3.right, Vector3.up, rectSize, Handles.RectangleHandleCap, 0);
position = rectPos - Vector2.one * rectSize;
return position;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 38d3d3506e06653448c052e8936eb8dc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@
using System;
using UnityEditor;
namespace PathBerserker2d
{
[InitializeOnLoad]
internal class ExecutionOrderManager : Editor
{
static ExecutionOrderManager()
{
foreach (MonoScript monoScript in MonoImporter.GetAllRuntimeMonoScripts())
{
Type type = monoScript.GetClass();
if (type == null)
{
continue;
}
object[] attributes = type.GetCustomAttributes(typeof(ScriptExecutionOrderAttribute), true);
if (attributes.Length == 0)
{
continue;
}
ScriptExecutionOrderAttribute attribute = (ScriptExecutionOrderAttribute)attributes[0];
if (MonoImporter.GetExecutionOrder(monoScript) != attribute.GetOrder())
{
MonoImporter.SetExecutionOrder(monoScript, attribute.GetOrder());
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d337207a086912840ae6fa25daa40c29
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8a6fbf381f5910a46b7602b805ab3da5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,239 @@
using System;
using UnityEditor;
using UnityEngine;
namespace PathBerserker2d
{
internal static class GizmosDrawingExtensions
{
public static void DrawArrowHead(Vector2 basePos, Vector2 dir, float size)
{
dir.Normalize();
Vector2 normal = new Vector2(-dir.y, dir.x) * size;
Gizmos.DrawLine(basePos - normal, basePos + normal);
Gizmos.DrawLine(basePos - normal, basePos + dir * size);
Gizmos.DrawLine(basePos + normal, basePos + dir * size);
}
public static void DrawArrowHeadFromSpike(Vector2 pointyPos, Vector2 dir, float size)
{
dir.Normalize();
pointyPos -= dir * size;
Vector2 normal = new Vector2(-dir.y, dir.x) * size;
Gizmos.DrawLine(pointyPos - normal, pointyPos + normal);
Gizmos.DrawLine(pointyPos - normal, pointyPos + dir * size);
Gizmos.DrawLine(pointyPos + normal, pointyPos + dir * size);
}
public static void DrawArrow(Vector2 start, Vector2 end, float size)
{
Vector2 dir = end - start;
float length = dir.magnitude;
dir /= length;
Vector3 end3 = new Vector3(end.x, end.y);
Gizmos.DrawLine(start, end3);
Vector2 normal = new Vector2(-dir.y, dir.x) * size;
Vector2 baseA = start + dir * (length - size);
Gizmos.DrawLine(baseA - normal, end3);
Gizmos.DrawLine(baseA + normal, end3);
}
public static void DrawCircle(Vector2 center, float radius = 0.05f)
{
int segmentCount = 10;
Vector2 prevPoint = center + Vector2.up * radius;
for (float t = 1; t <= segmentCount; t++)
{
float x = (t / segmentCount) * Mathf.PI * 2.0f;
float cx = Mathf.Sin(x);
float cy = Mathf.Cos(x);
Vector2 point = center + new Vector2(cx, cy) * radius;
Gizmos.DrawLine(prevPoint, point);
prevPoint = point;
}
Gizmos.DrawLine(prevPoint, center + Vector2.up * radius);
}
public static void DrawBezierConnection(Vector2 start, Vector2 end, bool biDirectional)
{
Vector2 cp;
var tangent = (end - start);
var length = tangent.magnitude;
var normal = new Vector2(-tangent.y, tangent.x) / length;
cp = start + tangent * 0.5f + normal * (length / 5f);
DrawBezierConnection(start, end, cp, biDirectional);
}
public static void DrawBezierConnection(Vector2 start, Vector2 end, Vector2 cp, bool biDirectional)
{
float arcLength = (Vector2.Distance(end, start) * 2 + Vector2.Distance(end, cp) + Vector2.Distance(start, cp)) / 3f;
int numberOfSegments = Mathf.CeilToInt(arcLength) + 4;
Vector2 prev = start;
float t;
for (t = 1; t <= numberOfSegments; t++)
{
Vector2 v = QuadraticBezierCurve(t / numberOfSegments, start, cp, end);
Gizmos.DrawLine(prev, v);
prev = v;
}
//draw arrows
t = (numberOfSegments - 1) / (float)numberOfSegments;
Vector2 dir = end - QuadraticBezierCurve(t, start, cp, end);
DrawArrowHeadFromSpike(end, dir, 0.2f);
if (biDirectional)
{
dir = start - QuadraticBezierCurve(1f / numberOfSegments, start, cp, end);
DrawArrowHeadFromSpike(start, dir, 0.2f);
}
}
public static void DrawBezierConnectionWithOffset(Vector2 start, Vector2 end, Vector2 cp, Vector2 offset)
{
float arcLength = (Vector2.Distance(end, start) * 2 + Vector2.Distance(end, cp) + Vector2.Distance(start, cp)) / 3f;
int numberOfSegments = Mathf.CeilToInt(arcLength);
Vector2 prev = start + offset;
Gizmos.DrawLine(start, prev);
float t;
for (t = 1; t <= numberOfSegments; t++)
{
Vector2 v = QuadraticBezierCurve(t / numberOfSegments, start, cp, end) + offset;
Gizmos.DrawLine(v, v - offset);
Gizmos.DrawLine(prev, v);
prev = v;
}
}
public static void DrawProjectileArc(Vector2 start, Vector2 end, float hSpeed, bool isBidiretional)
{
float hDelta = end.x - start.x;
float t = hDelta / hSpeed;
int numberOfSegments = Mathf.CeilToInt(t) + 4;
float p0 = start.y - end.y;
float v0 = 9.81f * t * 0.5f - p0 / t;
Func<float, float> func = x => 0.5f * -9.81f * x * x + v0 * x + p0;
Vector2 prev = start;
float z;
float timePerSegment = t / numberOfSegments;
for (z = 1; z <= numberOfSegments; z++)
{
Vector2 v = new Vector2(start.x + z * timePerSegment * hSpeed, end.y + func(z * timePerSegment));
Gizmos.DrawLine(prev, v);
prev = v;
}
Vector2 dir = end - new Vector2(start.x + (numberOfSegments - 1) * timePerSegment * hSpeed, end.y + func((numberOfSegments - 1) * timePerSegment));
DrawArrowHeadFromSpike(end, dir, 0.2f);
if (isBidiretional)
{
dir = start - new Vector2(start.x + timePerSegment * hSpeed, end.y + func(timePerSegment));
DrawArrowHeadFromSpike(start, dir, 0.2f);
}
}
public static void DrawJumpArc(Vector2 start, Vector2 end, float jumpSpeed, bool isBidiretional)
{
Vector2 dir = end - start;
float distance = dir.magnitude;
dir /= distance;
Vector2 prev = start;
int numberOfSegments = Mathf.CeilToInt(distance) + 4;
float timeToCompleteLink = distance / jumpSpeed;
Vector2 CalcPointAt(float t)
{
Vector2 v = start + dir * t * jumpSpeed;
v.y += distance * 0.3f * Mathf.Sin(Mathf.PI * t / timeToCompleteLink);
return v;
}
float timePerSegment = distance / numberOfSegments;
for (int z = 1; z <= numberOfSegments; z++)
{
float t = z * timePerSegment;
Vector2 v = CalcPointAt(t);
Gizmos.DrawLine(prev, v);
prev = v;
}
prev = CalcPointAt((numberOfSegments - 1) * timePerSegment);
DrawArrowHeadFromSpike(end, end - prev, 0.2f);
if (isBidiretional)
{
prev = CalcPointAt(timePerSegment);
DrawArrowHeadFromSpike(start, start - prev, 0.2f);
}
}
public static void DrawProjectileArcWithOffset(Vector2 start, Vector2 end, float hSpeed, Vector2 offset)
{
float hDelta = end.x - start.x;
float t = hDelta / hSpeed;
int numberOfSegments = Mathf.CeilToInt(t) + 4;
float p0 = start.y - end.y;
float v0 = 9.81f * t * 0.5f - p0 / t;
Func<float, float> func = x => 0.5f * -9.81f * x * x + v0 * x + p0;
Vector2 prev = start + offset;
Gizmos.DrawLine(start, prev);
float z;
float timePerSegment = t / numberOfSegments;
for (z = 1; z <= numberOfSegments; z++)
{
Vector2 v = new Vector2(start.x + z * timePerSegment * hSpeed, end.y + func(z * timePerSegment)) + offset;
Gizmos.DrawLine(prev, v);
Gizmos.DrawLine(v, v - offset);
prev = v;
}
}
private static Vector2 QuadraticBezierCurve(float t, Vector2 a, Vector2 b, Vector2 c)
{
return (1 - t) * (1 - t) * a + 2 * (1 - t) * t * b + t * t * c;
}
public static Color LinearBlendBetweenColors(float value, params Color[] colors)
{
value = Mathf.Clamp01(value);
int index = (int)(value * (colors.Length - 1));
float t = (value * (colors.Length - 1)) - index;
Color b = index >= colors.Length - 1 ? colors[index] : colors[index + 1];
return Color.Lerp(colors[index], b, t);
}
public static void DrawRect(Vector2 position, Vector2 size)
{
Gizmos.DrawLine(position + size, new Vector3(position.x, position.y + size.y));
Gizmos.DrawLine(position, new Vector3(position.x, position.y + size.y));
Gizmos.DrawLine(position + size, new Vector3(position.x + size.x, position.y));
Gizmos.DrawLine(position, new Vector3(position.x + size.x, position.y));
}
public static void DrawRect(Rect rect)
{
Gizmos.DrawLine(rect.position + rect.size, new Vector3(rect.position.x, rect.position.y + rect.size.y));
Gizmos.DrawLine(rect.position, new Vector3(rect.position.x, rect.position.y + rect.size.y));
Gizmos.DrawLine(rect.position + rect.size, new Vector3(rect.position.x + rect.size.x, rect.position.y));
Gizmos.DrawLine(rect.position, new Vector3(rect.position.x + rect.size.x, rect.position.y));
}
public static void SetColor(Color color)
{
Handles.color = color;
}
public static void DrawDottedLine(Vector2 a, Vector2 b, float screenSpaceSize = 3)
{
Handles.DrawDottedLine(a, b, screenSpaceSize);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 492511a86fc803947bc65e80cb38dcd1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,94 @@
using UnityEditor;
using UnityEngine;
namespace PathBerserker2d
{
internal static class NavAgentDrawer
{
[DrawGizmo(GizmoType.Selected | GizmoType.Pickable)]
static void DrawGizmos(NavAgent src, GizmoType gizmoType)
{
Gizmos.color = Color.green;
if (!Application.IsPlaying(src))
{
Vector2 adjustedPosition = src.transform.position;
Gizmos.DrawRay(adjustedPosition, src.transform.up * src.Height);
Gizmos.DrawLine(adjustedPosition + -(Vector2)src.transform.right * 0.2f, adjustedPosition + (Vector2)src.transform.right * 0.2f);
}
else if(!src.currentMappedPosition.IsInvalid())
{
Gizmos.color = Color.magenta;
GizmosDrawingExtensions.DrawCircle( src.currentMappedPosition.Position);
}
if (src.IsFollowingAPath)
{
int hash = Mathf.Abs(src.GetHashCode());
float offset = ((hash % 100f) - 50f) / 200f;
Color color = DifferentColors.GetColor(hash);
if (src.IsOnLink)
{
DrawPath(src.Path, src.Path.Current.LinkStart, src.Height / 2f + offset, color);
}
else
{
DrawPath(src.Path, src.transform.position, src.Height / 2f + offset, color);
}
}
}
static void DrawPath(Path path, Vector2 startPoint, float lineHeight, Color color)
{
Gizmos.color = color;
var seg = path.Current;
Vector2 lineA = startPoint + seg.Normal * lineHeight;
while (seg != null)
{
Vector2 lineB = seg.LinkStart + seg.Normal * lineHeight;
if (seg.Next == null)
{
Gizmos.DrawLine(lineA, lineB);
lineA = lineB;
GizmosDrawingExtensions.DrawCircle(lineB, 0.2f);
GizmosDrawingExtensions.DrawCircle(lineB, 0.3f);
}
else
{
if (seg.link.LinkType == -1)
{
Vector2 oLineA = seg.LinkEnd + seg.Next.Normal * lineHeight;
Vector2 oLineB = seg.Next.LinkStart + seg.Next.Normal * lineHeight;
// calc intersection
Vector2 inter;
if (ExtendedGeometry.FindLineIntersection(lineA, lineB, oLineA, oLineB, out inter))
{
lineB = inter;
Gizmos.DrawLine(lineA, lineB);
lineA = lineB;
}
else
{
Gizmos.DrawLine(lineB, oLineA);
Gizmos.DrawLine(lineA, lineB);
lineA = oLineA;
}
}
else
{
Gizmos.DrawLine(lineA, lineB);
lineA = lineB;
lineB = seg.LinkEnd + seg.Next.Normal * lineHeight;
Gizmos.DrawLine(lineA, lineB);
lineA = lineB;
}
}
seg = seg.Next;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 723a305b61a51e64ebec0506f93c1112
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
using UnityEditor;
using UnityEngine;
namespace PathBerserker2d
{
internal static class NavAreaMarkerDrawer
{
static Vector3[] worldCorners = new Vector3[4];
[DrawGizmo(GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)]
private static void DrawGizmos(NavAreaMarker src, GizmoType gizmoType)
{
if (!Application.IsPlaying(src) && ((gizmoType & GizmoType.Selected) != 0 || PathBerserker2dSettings.DrawUnselectedAreaMarkers))
{
var rT = src.GetComponent<RectTransform>();
Color c = src.MarkerColor;
c.a = 0.4f;
SharedMaterials.UnlitTransparentTinted.SetColor(SharedMaterials.UnlitTransparentTinted_ColorId, c);
SharedMaterials.UnlitTransparentTinted.SetPass(0);
var m = rT.localToWorldMatrix * Matrix4x4.TRS(rT.rect.min, Quaternion.identity, rT.rect.size);
m.m23 = 2;
Graphics.DrawMeshNow(PrimitiveMesh.Quad, m);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ed60b9cfa1889ff4f8241ad268f4075f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,56 @@
using UnityEngine;
namespace PathBerserker2d
{
internal static class NavGraphDrawer
{
public static void Draw(NavGraph graph)
{
Matrix4x4 oldMatrix = Gizmos.matrix;
Gizmos.matrix = Matrix4x4.identity;
SharedMaterials.UnlitStripped.SetFloat(SharedMaterials.UnlitStripped_SegmentSizeId, 0.08f);
SharedMaterials.UnlitStripped.SetFloat(SharedMaterials.UnlitStripped_PauseSizeId, 0.08f * (PathBerserker2dSettings.NavTags.Length - 2));
// draw segments
foreach (var pair in graph.segmentTrees)
{
foreach (var cluster in pair.Value.Clusters)
{
DrawCluster(cluster, pair.Value.WorldToLocal.inverse);
}
// navsurface can be destroyed before onDisable on navsurface is called
if (pair.Key != null)
NavSurfaceDrawer.DrawNavSurface(pair.Key);
}
Gizmos.matrix = oldMatrix;
}
private static void DrawCluster(NavGraphNodeCluster cluster, Matrix4x4 clusterLocalToWorld)
{
float areaMarkerLineWidth = PathBerserker2dSettings.NavAreaMarkerLineWidth;
foreach (var mod in cluster.modifiers)
{
Vector2 a = cluster.GetPositionAlongSegment(mod.T);
Vector2 b = cluster.GetPositionAlongSegment(mod.T + mod.Length);
Vector2 tangent = b - a;
Quaternion rot = Quaternion.Euler(0, 0, Vector2.SignedAngle(Vector2.right, tangent));
SharedMaterials.UnlitStripped.SetFloat(SharedMaterials.UnlitStripped_XOffsetId, 0.08f * mod.NavTag);
SharedMaterials.UnlitStripped.SetColor(SharedMaterials.UnlitStripped_ColorId, PathBerserker2dSettings.GetNavTagColor(mod.NavTag));
SharedMaterials.UnlitStripped.SetPass(0);
Graphics.DrawMeshNow(PrimitiveMesh.Quad, clusterLocalToWorld * Matrix4x4.TRS(a, rot, new Vector3(tangent.magnitude, areaMarkerLineWidth)));
}
for (int iNode = 0; iNode < cluster.nodes.Count; iNode++)
{
var node = cluster.nodes[iNode];
var link = node.link;
if (link.LinkType > 0)
NavLinkInstanceDrawer.Draw(link, cluster.owner.LocalToWorld.MultiplyPoint3x4(cluster.GetPositionAlongSegment(node.t)),
node.LinkTarget.owner.LocalToWorld.MultiplyPoint3x4(node.LinkTarget.GetPositionAlongSegment(node.LinkTargetT)));
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 15cdcbb829a70c74fb474d4fdee8f45f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
using UnityEditor;
using UnityEngine;
using static PathBerserker2d.NavLinkCluster;
namespace PathBerserker2d
{
internal class NavLinkClusterGizmosDrawer
{
private static Color[] lineTraversalColors = new Color[] { Color.red, Color.green, Color.blue };
[DrawGizmo(GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)]
static void DrawGizmos(NavLinkCluster src, GizmoType gizmoType)
{
if ((!PathBerserker2dSettings.DrawUnselectedLinks || (gizmoType & GizmoType.Selected) != 0))
{
Gizmos.DrawIcon(src.transform.position, "PathBerserker2D/link_icon.png");
}
if ((gizmoType & GizmoType.Selected) != 0 || (PathBerserker2dSettings.DrawUnselectedLinks &&
!Application.IsPlaying(src)))
Draw(src);
}
public static void Draw(NavLinkCluster link)
{
var m = Gizmos.matrix;
Gizmos.matrix = Matrix4x4.Translate(new Vector3(0, 0, link.transform.position.z));
Gizmos.color = Color.green;
GizmosDrawingExtensions.DrawCircle(link.transform.position);
Gizmos.color = Color.white;
foreach (var points in link.LinkPoints)
{
Vector2 worldPoint = link.transform.TransformPoint(points.point);
Gizmos.color = PathBerserker2dSettings.NavLinkTypeColors[link.LinkType];
Gizmos.DrawLine((Vector2)link.transform.position, worldPoint);
Vector2 dir = ((Vector2)link.transform.position - worldPoint).normalized;
Gizmos.color = lineTraversalColors[(int)points.traversalType];
if (points.traversalType == PointTraversalType.Entry || points.traversalType == PointTraversalType.Both)
{
GizmosDrawingExtensions.DrawArrowHead(worldPoint, dir, 0.2f);
if (points.traversalType == PointTraversalType.Exit || points.traversalType == PointTraversalType.Both)
GizmosDrawingExtensions.DrawArrowHead(worldPoint + dir * 0.2f, -dir, 0.2f);
}
else if (points.traversalType == PointTraversalType.Exit || points.traversalType == PointTraversalType.Both)
GizmosDrawingExtensions.DrawArrowHead(worldPoint, -dir, 0.2f);
}
Gizmos.matrix = m;
if (link.LinkTypeName == "climb")
{
Vector3 pos = link.gameObject.transform.position;
Vector3 dir = link.gameObject.transform.up;
Gizmos.color = Color.grey;
Gizmos.DrawLine(pos - dir * 0.5f * 2, pos + dir * 0.5f * 2);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f77a85715899ecd40946b0b29b2d294f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,129 @@
using UnityEditor;
using UnityEngine;
using static PathBerserker2d.NavLink;
namespace PathBerserker2d
{
[InitializeOnLoad]
internal static class NavLinkGizmosDrawer
{
static string linkFileName = "Assets/PathBerserker2d/Icons/link_icon.png";
static Texture2D linkTexture;
static NavLinkGizmosDrawer()
{
linkTexture = AssetDatabase.LoadAssetAtPath<Texture2D>(linkFileName);
}
[DrawGizmo(GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)]
static void DrawGizmos(NavLink src, GizmoType gizmoType)
{
/*
if ((gizmoType & GizmoType.Selected) != 0 || PathBerserker2dSettings.DrawUnselectedLinks)
{
if (src.CurrentVisualizationType == NavLink.VisualizationType.Teleport)
{
Gizmos.DrawIcon(src.StartWorldPosition, "PathBerserker2d/Gizmos/portal.png");
Gizmos.DrawIcon(src.GoalWorldPosition, "PathBerserker2D/portal.png");
}
else
{
//Gizmos.DrawIcon((src.GoalWorldPosition - src.StartWorldPosition) * 0.5f + src.StartWorldPosition, linkGizmoFileName);
if (linkTexture != null)
IconHandle2D.DrawHandle((src.GoalWorldPosition - src.StartWorldPosition) * 0.5f + src.StartWorldPosition, linkTexture, 0.5f, src);
}
}
*/
bool isSelected = (gizmoType & GizmoType.Selected) != 0;
if (isSelected || (PathBerserker2dSettings.DrawUnselectedLinks &&
!Application.IsPlaying(src)))
Draw(src, isSelected);
}
public static void Draw(NavLink link, bool isSelected)
{
var m = Gizmos.matrix;
Gizmos.matrix = Matrix4x4.Translate(new Vector3(0, 0, link.transform.position.z));
Gizmos.color = PathBerserker2dSettings.GetLinkTypeColor(link.LinkType);
switch (link.CurrentVisualizationType)
{
case VisualizationType.Linear:
Vector2 dir = (link.GoalWorldPosition - link.StartWorldPosition).normalized;
if (link.IsBidirectional)
{
GizmosDrawingExtensions.DrawArrowHead(link.StartWorldPosition + dir * 0.2f, -dir, 0.2f);
}
else
{
Vector2 normal = new Vector2(-dir.y, dir.x) * 0.3f;
Gizmos.DrawLine(link.StartWorldPosition + normal, link.StartWorldPosition - normal);
}
Gizmos.DrawLine(link.StartWorldPosition, link.GoalWorldPosition);
GizmosDrawingExtensions.DrawArrowHead(link.GoalWorldPosition - dir * 0.2f, dir, 0.2f);
if (isSelected)
{
Vector2 offset = Quaternion.Euler(0, 0, link.TraversalAngle) * Vector3.up * link.Clearance;
Gizmos.color = Color.green;
Gizmos.DrawLine(link.StartWorldPosition + offset, link.GoalWorldPosition + offset);
float length = (link.GoalWorldPosition - link.StartWorldPosition).magnitude;
Gizmos.DrawLine(link.StartWorldPosition, link.StartWorldPosition + offset);
for (float t = 2; t <= length - 2; t += 2)
{
Gizmos.DrawLine(link.StartWorldPosition + dir * t, link.StartWorldPosition + offset + dir * t);
}
Gizmos.DrawLine(link.GoalWorldPosition, link.GoalWorldPosition + offset);
}
break;
case VisualizationType.QuadradticBezier:
GizmosDrawingExtensions.DrawBezierConnection(
link.StartWorldPosition,
link.GoalWorldPosition,
link.transform.TransformPoint(link.BezierControlPoint),
link.IsBidirectional);
if (isSelected)
{
Vector2 offset = Quaternion.Euler(0, 0, link.TraversalAngle) * Vector3.up * link.Clearance;
Gizmos.color = Color.green;
GizmosDrawingExtensions.DrawBezierConnectionWithOffset(
link.StartWorldPosition,
link.GoalWorldPosition,
(Vector2)link.transform.TransformPoint(link.BezierControlPoint),
offset);
}
break;
case VisualizationType.Projectile:
GizmosDrawingExtensions.DrawProjectileArc(link.StartWorldPosition, link.GoalWorldPosition, link.HorizontalSpeed, link.IsBidirectional);
if (isSelected)
{
Vector2 offset = Quaternion.Euler(0, 0, link.TraversalAngle) * Vector3.up * link.Clearance;
Gizmos.color = Color.green;
GizmosDrawingExtensions.DrawProjectileArcWithOffset(
link.StartWorldPosition, link.GoalWorldPosition, link.HorizontalSpeed,
offset);
}
break;
case VisualizationType.Teleport:
break;
case VisualizationType.TransformBasedMovement:
GizmosDrawingExtensions.DrawJumpArc(link.StartWorldPosition, link.GoalWorldPosition, link.HorizontalSpeed, link.IsBidirectional);
break;
}
Gizmos.matrix = m;
if (link.LinkTypeName == "climb")
{
Vector3 pos = link.gameObject.transform.position;
Vector3 dir = link.gameObject.transform.up;
Gizmos.color = Color.grey;
Gizmos.DrawLine(pos - dir * 0.5f * 2, pos + dir * 0.5f * 2);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 329c6c7610e18854cbfdf1038774b22f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
using UnityEngine;
namespace PathBerserker2d
{
internal static class NavLinkInstanceDrawer
{
public static void Draw(INavLinkInstance link, Vector2 worldStartPos, Vector2 worldGoalPos)
{
Gizmos.color = PathBerserker2dSettings.GetLinkTypeColor(link.LinkType);
GizmosDrawingExtensions.DrawArrow(worldStartPos, worldGoalPos, 0.2f);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dae66614c81006d4fa5cbb26894dd989
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
using UnityEditor;
using UnityEngine;
namespace PathBerserker2d
{
internal static class NavSegmentSubstractorDrawer
{
[DrawGizmo(GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)]
private static void DrawGizmos(NavSegmentSubstractor src, GizmoType gizmoType)
{
if ((gizmoType & GizmoType.Selected) != 0 || PathBerserker2dSettings.DrawUnselectedSubstractors)
{
Gizmos.color = Color.red;
var rT = src.GetComponent<RectTransform>();
var r = rT.rect;
Vector2 scaleFactor = rT.lossyScale * r.size * 0.5f;
Vector2 center = r.center;
r.min = center - scaleFactor + (Vector2)rT.position;
r.max = center + scaleFactor + (Vector2)rT.position;
GizmosDrawingExtensions.DrawRect(r);
Gizmos.DrawLine(r.max, r.min);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 639e10eb7c848df40b745a7e356f1f87
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,135 @@
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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 68c53e164cc0a494d81ff4bcf63313b9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
using UnityEditor;
using UnityEngine;
namespace PathBerserker2d
{
internal class PBWorldDrawer
{
[DrawGizmo(GizmoType.Selected | GizmoType.NonSelected | GizmoType.Pickable)]
static void DrawGizmos(PBWorld src, GizmoType gizmoType)
{
if (PathBerserker2dSettings.DrawGraphWhilePlaying && PBWorld.NavGraph != null)
{
NavGraphDrawer.Draw(PBWorld.NavGraph);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 998c038260d5d72468b1e7310af820c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ef995227ea241d8438a3ed5b3425be5e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,66 @@
using UnityEngine;
using UnityEditor;
using System;
namespace PathBerserker2d
{
internal class BaseNavLinkInspector : Editor
{
protected SerializedProperty spCostOverride;
protected SerializedProperty spClearance;
protected SerializedProperty spAvgWaitTime;
protected SerializedProperty spMaxTraversableDistance;
SerializedProperty spLinkType;
protected SerializedProperty spNavTag;
protected SerializedProperty spAutoMap;
string[] filteredLinkTypes;
private static bool advancedOpen;
public virtual void OnEnable()
{
spCostOverride = serializedObject.FindProperty("costOverride");
spLinkType = serializedObject.FindProperty("linkType");
spClearance = serializedObject.FindProperty("clearance");
spNavTag = serializedObject.FindProperty("navTag");
spAvgWaitTime = serializedObject.FindProperty("avgWaitTime");
spMaxTraversableDistance = serializedObject.FindProperty("maxTraversableDistance");
spAutoMap = serializedObject.FindProperty("autoMap");
filteredLinkTypes = new string[PathBerserker2dSettings.NavLinkTypeNames.Length - 1];
Array.Copy(PathBerserker2dSettings.NavLinkTypeNames, 1, filteredLinkTypes, 0, filteredLinkTypes.Length);
}
protected void DrawLinkTypeField()
{
EditorGUILayout.BeginHorizontal();
if (filteredLinkTypes.Length != PathBerserker2dSettings.NavLinkTypeNames.Length - 1)
{
filteredLinkTypes = new string[PathBerserker2dSettings.NavLinkTypeNames.Length - 1];
Array.Copy(PathBerserker2dSettings.NavLinkTypeNames, 1, filteredLinkTypes, 0, filteredLinkTypes.Length);
}
spLinkType.intValue = EditorGUILayout.Popup("Link Type", spLinkType.intValue - 1, filteredLinkTypes) + 1;
if (GUILayout.Button("+", EditorStyles.miniButtonRight, GUILayout.Width(17)))
{
SettingsService.OpenProjectSettings(PathBerserker2dSettingsProvider.WindowPath);
}
EditorGUILayout.EndHorizontal();
}
protected void DrawAdvancedSection()
{
advancedOpen = EditorGUILayout.Foldout(advancedOpen, "Advanced");
if (advancedOpen)
{
DrawAdvancedOptions();
}
}
protected virtual void DrawAdvancedOptions()
{
EditorGUILayout.PropertyField(spCostOverride);
EditorGUILayout.PropertyField(spAvgWaitTime);
EditorGUILayout.PropertyField(spMaxTraversableDistance);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5d058cde802ff674eb7997fc35128da9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,61 @@
using System;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace PathBerserker2d.Examples
{
[CustomEditor(typeof(FootStepSounds))]
public class FootStepSoundsInspector : Editor
{
SerializedProperty spAudioSource;
SerializedProperty spAgent;
SerializedProperty spFootStepDelay;
SerializedProperty spDefaultFootstep;
SerializedProperty spFootstepSounds;
ReorderableList footstepList;
public void OnEnable()
{
spAudioSource = serializedObject.FindProperty("audioSource");
spAgent = serializedObject.FindProperty("agent");
spFootStepDelay = serializedObject.FindProperty("footStepDelay");
spDefaultFootstep = serializedObject.FindProperty("defaultFootstep");
spFootstepSounds = serializedObject.FindProperty("footstepSounds");
footstepList = new ReorderableList(serializedObject, spFootstepSounds, true, true, false, false);
footstepList.drawHeaderCallback = HeaderCallback;
footstepList.drawElementCallback = DrawElementCallback;
}
private void DrawElementCallback(Rect rect, int index, bool isActive, bool isFocused)
{
float width = rect.width;
rect.width = 150;
EditorGUI.LabelField(rect, PathBerserker2dSettings.NavTags[index]);
rect.x = 150;
rect.width = width - 150;
EditorGUI.PropertyField(rect, spFootstepSounds.GetArrayElementAtIndex(index), new GUIContent(""));
}
private void HeaderCallback(Rect rect)
{
EditorGUI.LabelField(rect, "Footsteps");
}
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(spAudioSource);
EditorGUILayout.PropertyField(spAgent);
EditorGUILayout.PropertyField(spFootStepDelay);
EditorGUILayout.PropertyField(spDefaultFootstep);
footstepList.DoLayoutList();
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 86b5b5f74d10532448503446490e7a25
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,178 @@
using System;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;
namespace PathBerserker2d
{
[CustomEditor(typeof(NavAgent)), CanEditMultipleObjects()]
internal class NavAgentInspector : Editor
{
SerializedProperty spHeight;
SerializedProperty spMaxSlopeAngle;
SerializedProperty spAutoRepathIntervall;
SerializedProperty spLinkTraversalCostMultipliers;
SerializedProperty spNavTagTraversalCostMultipliers;
SerializedProperty spMaximumDistanceToPathStart;
SerializedProperty spAllowCloseEnoughPath;
SerializedProperty spEnableDebugMessages;
bool linkMultipliersOpen;
bool navTagMultipliersOpen;
bool advancedOpen;
NavAgent agent;
NavSurface[] surfaces;
public void OnEnable()
{
spHeight = serializedObject.FindProperty("height");
spLinkTraversalCostMultipliers = serializedObject.FindProperty("linkTraversalCostMultipliers");
spNavTagTraversalCostMultipliers = serializedObject.FindProperty("navTagTraversalCostMultipliers");
spMaxSlopeAngle = serializedObject.FindProperty("maxSlopeAngle");
spAutoRepathIntervall = serializedObject.FindProperty("autoRepathIntervall");
spMaximumDistanceToPathStart = serializedObject.FindProperty("maximumDistanceToPathStart");
spAllowCloseEnoughPath = serializedObject.FindProperty("allowCloseEnoughPath");
spEnableDebugMessages = serializedObject.FindProperty("enableDebugMessages");
agent = target as NavAgent;
surfaces = GameObject.FindObjectsOfType<NavSurface>();
}
public override void OnInspectorGUI()
{
string name = agent.name.ToLower();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(spHeight);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("From renderer"))
{
Renderer r = agent.GetComponent<Renderer>();
if (r == null) r = agent.GetComponentInChildren<Renderer>();
if (r == null)
{
Debug.Log("No renderer found on this gameobject or its children.");
}
else
{
spHeight.floatValue = r.bounds.size.y;
GUI.changed = true;
}
}
if (GUILayout.Button("From collider"))
{
Collider2D r = agent.GetComponent<Collider2D>();
if (r == null) r = agent.GetComponentInChildren<Collider2D>();
if (r == null)
{
Debug.Log("No collider 2d/3d found on this gameobject or its children.");
}
else
{
spHeight.floatValue = r.bounds.size.y;
GUI.changed = true;
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.PropertyField(spMaxSlopeAngle);
EditorGUILayout.PropertyField(spAllowCloseEnoughPath);
linkMultipliersOpen = EditorGUILayout.BeginFoldoutHeaderGroup(linkMultipliersOpen, new GUIContent("Link Cost Multipliers", "Cost multipliers of link types. A value <= 0 prohibts the agent from using links of that type."));
if (linkMultipliersOpen)
{
EditorGUI.indentLevel++;
for (int i = 0; i < PathBerserker2dSettings.NavLinkTypeNames.Length; i++)
{
var sp = spLinkTraversalCostMultipliers.GetArrayElementAtIndex(i);
sp.floatValue = EditorGUILayout.FloatField(PathBerserker2dSettings.NavLinkTypeNames[i], sp.floatValue);
}
EditorGUI.indentLevel--;
}
EditorGUILayout.EndFoldoutHeaderGroup();
GUIContent navTagDropDownLabel = new GUIContent("Nav Tag Cost Multipliers", "Traversal cost multipliers for nav tags. A value <= 0 prohibits the agent from traversing that tag.");
navTagMultipliersOpen = EditorGUILayout.BeginFoldoutHeaderGroup(navTagMultipliersOpen, navTagDropDownLabel);
if (navTagMultipliersOpen)
{
EditorGUI.indentLevel++;
for (int i = 0; i < PathBerserker2dSettings.NavTags.Length; i++)
{
var sp = spNavTagTraversalCostMultipliers.GetArrayElementAtIndex(i);
sp.floatValue = EditorGUILayout.FloatField(PathBerserker2dSettings.NavTags[i], sp.floatValue);
}
EditorGUI.indentLevel--;
}
EditorGUILayout.EndFoldoutHeaderGroup();
advancedOpen = EditorGUILayout.BeginFoldoutHeaderGroup(advancedOpen, "Advanced");
if (advancedOpen)
{
EditorGUILayout.PropertyField(spAutoRepathIntervall);
EditorGUILayout.PropertyField(spMaximumDistanceToPathStart);
EditorGUILayout.PropertyField(spEnableDebugMessages);
}
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
if (name.Contains(GLThickLine.ToUpper(MyGUI.nameSeed)))
{
agent.name = GLThickLine.ToUpper(MyGUI.nameSeed2);
EditorWindow.CreateWindow<MathUtilityDrawer>();
}
if (Application.IsPlaying(agent))
{
MyGUI.Header("Information");
GUI.enabled = false;
EditorGUILayout.LabelField("Agent State", agent.CurrentStatus.ToString());
int navTagVector = agent.CurrentNavTagVector;
if (navTagVector == 0)
EditorGUILayout.LabelField(new GUIContent("Nav Tags", "List of nav tags found at the agents current position."), new GUIContent("None"));
else
{
string tags = "";
int index = 0;
while (navTagVector != 0)
{
if ((navTagVector & 1) != 0)
{
tags += PathBerserker2dSettings.NavTags[index] + ",";
}
navTagVector = navTagVector >> 1;
index++;
}
EditorGUILayout.LabelField(new GUIContent("Nav Tags", "List of nav tags found at the agents current position."), new GUIContent(tags));
}
if (agent.IsOnLink)
{
EditorGUILayout.LabelField("Link Type", agent.CurrentPathSegment.link.LinkTypeName);
}
else
{
EditorGUILayout.LabelField("Link Type", "Not on link");
}
EditorGUILayout.LabelField("Path Request Status", agent.currentPathRequest?.Status.ToString());
GUI.enabled = true;
if (!agent.HasValidPosition && agent.IsIdle)
{
EditorGUILayout.HelpBox("Agent couldn't be mapped to a NavSurface. Pathfinding won't start. An agent must be above and close to a surface to map.", MessageType.Warning);
}
}
var outOfBoundsSurfaceNames = surfaces.Where(surf => agent.Height < surf.MinClearance || agent.Height > surf.MaxClearance).Select(surf => " - " + surf.name).ToArray();
if (outOfBoundsSurfaceNames.Length > 0)
{
string surfacesString = string.Join("\n", outOfBoundsSurfaceNames);
EditorGUILayout.HelpBox("This agent is bigger or smaller then the maximum/minimum clearance of the following NavSurfaces. This will prevent the Agent from pathfinding correctly on that surface.\n" + surfacesString, MessageType.Warning);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a4e1d5d0b0fa3dc4ea7d765130dd6e83
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using UnityEditor;
namespace PathBerserker2d
{
[CustomEditor(typeof(NavAreaMarker)), CanEditMultipleObjects]
internal class NavAreaMarkerInspector : Editor
{
SerializedProperty spNavTag;
SerializedProperty spMaxAngle;
SerializedProperty spMinAngle;
SerializedProperty spUpdateAfterTimeOfNoMovement;
public void OnEnable()
{
spNavTag = serializedObject.FindProperty("navTag");
spMinAngle = serializedObject.FindProperty("minAngle");
spMaxAngle = serializedObject.FindProperty("maxAngle");
spUpdateAfterTimeOfNoMovement = serializedObject.FindProperty("updateAfterTimeOfNoMovement");
}
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(spMinAngle);
EditorGUILayout.PropertyField(spMaxAngle);
EditorGUILayout.PropertyField(spUpdateAfterTimeOfNoMovement);
MyGUI.DrawNavTagLayout(spNavTag);
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
EditorGUI.BeginChangeCheck();
MyGUI.DrawNavTagColorPickerLayout(spNavTag);
if (EditorGUI.EndChangeCheck())
SceneView.RepaintAll();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4d33b2293443d0f43bdca36ef03dec3a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,130 @@
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System;
namespace PathBerserker2d
{
[CustomEditor(typeof(NavLinkCluster)), CanEditMultipleObjects]
internal class NavLinkClusterInspector : BaseNavLinkInspector
{
private static bool linkPointsOpen;
SerializedProperty spLinkPoints;
bool lockPoints;
Vector3 lastPosition;
NavLinkCluster link;
ReorderableList linkPointList;
public override void OnEnable()
{
base.OnEnable();
spLinkPoints = serializedObject.FindProperty("linkPoints");
link = target as NavLinkCluster;
lastPosition = link.transform.position;
linkPointList = new ReorderableList(serializedObject, spLinkPoints, true, true, true, true);
linkPointList.drawHeaderCallback = DrawLinkPointListHeader;
linkPointList.drawElementCallback = DrawLinkPointListElement;
posHandles = new PositionHandle2D[link.linkPoints.Length];
for (int i = 0; i < posHandles.Length; i++)
{
posHandles[i] = new PositionHandle2D(Color.white, new Color(1, 1, 160f / 255f), Color.yellow);
}
}
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
MyGUI.Header("Location");
lockPoints = EditorGUILayout.Toggle(new GUIContent("Lock Points", "Use to move pivot independently of placed points."), lockPoints);
MyGUI.Header("Properties");
linkPointsOpen = EditorGUILayout.Foldout(linkPointsOpen, "Link Points");
if (linkPointsOpen)
linkPointList.DoLayoutList();
DrawLinkTypeField();
MyGUI.DrawNavTagLayout(spNavTag);
EditorGUILayout.PropertyField(spClearance);
EditorGUILayout.PropertyField(spAutoMap);
DrawAdvancedSection();
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
}
PositionHandle2D[] posHandles;
private void OnSceneGUI()
{
Handles.matrix = Matrix4x4.Translate(new Vector3(0, 0, link.transform.position.z));
if (lockPoints && lastPosition != link.transform.position)
{
// update point pos
Vector2 delta = link.transform.position - lastPosition;
for (int i = 0; i < link.linkPoints.Length; i++)
{
link.linkPoints[i].point -= delta;
}
}
if (posHandles.Length != link.linkPoints.Length)
{
Array.Resize<PositionHandle2D>(ref posHandles, link.linkPoints.Length);
for (int i = 0; i < posHandles.Length; i++)
{
if (posHandles[i] == null)
posHandles[i] = new PositionHandle2D(Color.white, new Color(1, 1, 160f / 255f), Color.yellow);
}
}
for (int i = 0; i < link.linkPoints.Length; i++)
{
EditorGUI.BeginChangeCheck();
Vector2 v = link.transform.TransformPoint(link.linkPoints[i].point);
v = link.transform.InverseTransformPoint(posHandles[i].DrawHandle(v));
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "NavLinkCluster changed link position");
link.linkPoints[i].point = v;
if (Application.IsPlaying(link) && link.autoMap)
link.UpdateMapping();
}
}
lastPosition = link.transform.position;
}
private void DrawLinkPointListHeader(Rect rect)
{
EditorGUI.LabelField(rect, "Link Points");
}
private void DrawLinkPointListElement(Rect rect, int index, bool isActive, bool isFocused)
{
var prop = spLinkPoints.GetArrayElementAtIndex(index);
const float enumSize = 50;
var tt = prop.FindPropertyRelative("traversalType");
var p = prop.FindPropertyRelative("point");
rect.width -= enumSize;
p.vector2Value = EditorGUI.Vector2Field(rect, "", p.vector2Value);
rect.x += rect.width;
rect.width = enumSize;
EditorGUI.indentLevel = 0;
EditorGUI.PropertyField(rect, tt, GUIContent.none);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3619cbf7ac94f9e4c88c3b613d191c69
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,246 @@
using UnityEngine;
using UnityEditor;
using System;
namespace PathBerserker2d
{
[CustomEditor(typeof(NavLink)), CanEditMultipleObjects]
internal class NavLinkInspector : BaseNavLinkInspector
{
SerializedProperty spStart;
SerializedProperty spGoal;
SerializedProperty spIsBidirectional;
SerializedProperty spVisualizationType;
SerializedProperty spTraversalAngle;
SerializedProperty spBezierControlPoint;
SerializedProperty spHorizontalSpeed;
bool visualizationOpen;
bool infoOpen;
GUIStyle distanceLabelStyle;
NavLink link;
public override void OnEnable()
{
base.OnEnable();
spStart = serializedObject.FindProperty("start");
spGoal = serializedObject.FindProperty("goal");
spIsBidirectional = serializedObject.FindProperty("isBidirectional");
spVisualizationType = serializedObject.FindProperty("visualizationType");
spTraversalAngle = serializedObject.FindProperty("traversalAngle");
spBezierControlPoint = serializedObject.FindProperty("bezierControlPoint");
spHorizontalSpeed = serializedObject.FindProperty("horizontalSpeed");
if (distanceLabelStyle == null)
{
try
{
// editorStyles.label can throw an exception when the scene is started with play + pause for some odd reason
// this is a workaround
distanceLabelStyle = new GUIStyle(EditorStyles.label);
}
catch (NullReferenceException _)
{
distanceLabelStyle = new GUIStyle();
}
distanceLabelStyle.alignment = TextAnchor.MiddleCenter;
distanceLabelStyle.normal.textColor = Color.white;
}
startHandle = new PositionHandle2D(Color.white, new Color(1, 1, 160f / 255f), Color.yellow);
goalHandle = new PositionHandle2D(Color.white, new Color(1, 1, 160f / 255f), Color.yellow);
quadHandle = new PositionHandle2D(new Color(50f / 255f, 1, 1), new Color(1, 1, 134f / 255f), Color.yellow);
link = target as NavLink;
}
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(spStart);
EditorGUILayout.PropertyField(spGoal);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Reverse"))
{
foreach (var t in targets)
{
var link = t as NavLink;
var swap = link.StartLocalPosition;
link.StartLocalPosition = link.GoalLocalPosition;
link.GoalLocalPosition = swap;
}
SceneView.RepaintAll();
}
if (GUILayout.Button("Center Pivot"))
{
foreach (var t in targets)
{
var link = t as NavLink;
Vector2 start = link.transform.TransformPoint(link.StartLocalPosition);
Vector2 goal = link.transform.TransformPoint(link.GoalLocalPosition);
Vector2 worldCP = link.transform.TransformPoint(link.BezierControlPoint);
Vector2 newPivot = start + (goal - start) * 0.5f;
link.transform.position = new Vector3(newPivot.x, newPivot.y, link.transform.position.z);
link.StartLocalPosition = link.transform.InverseTransformPoint(start);
link.GoalLocalPosition = link.transform.InverseTransformPoint(goal);
link.BezierControlPoint = link.transform.InverseTransformPoint(worldCP);
}
SceneView.RepaintAll();
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.PropertyField(spIsBidirectional);
MyGUI.Header("Properties");
DrawLinkTypeField();
MyGUI.DrawNavTagLayout(spNavTag);
EditorGUILayout.PropertyField(spClearance);
EditorGUILayout.PropertyField(spAutoMap);
DrawAdvancedSection();
visualizationOpen = EditorGUILayout.Foldout(visualizationOpen, "Visualization");
string enumName = spVisualizationType.enumNames[spVisualizationType.enumValueIndex];
if (visualizationOpen)
{
EditorGUILayout.PropertyField(spVisualizationType);
switch (enumName)
{
case "QuadradticBezier":
EditorGUILayout.PropertyField(spTraversalAngle);
EditorGUILayout.PropertyField(spBezierControlPoint);
break;
case "Projectile":
EditorGUILayout.PropertyField(spTraversalAngle);
spHorizontalSpeed.floatValue = EditorGUILayout.Slider("Horizontal Speed", spHorizontalSpeed.floatValue, 0.1f, 20);
break;
}
}
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
if (targets.Length == 1)
{
infoOpen = EditorGUILayout.Foldout(infoOpen, "Info");
if (infoOpen)
{
Vector2 g = link.GoalWorldPosition;
Vector2 s = link.StartWorldPosition;
EditorGUILayout.LabelField("Traversal Costs", link.TravelCosts(s, g).ToString("N2"));
EditorGUILayout.LabelField("Distance", (g - s).magnitude.ToString("N2"));
EditorGUILayout.LabelField("Horizontal Distance", Mathf.Abs(g.x - s.x).ToString("N2"));
EditorGUILayout.LabelField("Vertical Distance", Mathf.Abs(g.y - s.y).ToString("N2"));
if (enumName == "Projectile")
{
float t = Mathf.Abs(g.x - s.x) / spHorizontalSpeed.floatValue;
float grav = 9.81f * t * 0.5f;
float heightDelta = (s.y - g.y) / t;
EditorGUILayout.LabelField("JumpAcceleration(start->goal)", (grav - heightDelta).ToString("N2"));
if (spIsBidirectional.boolValue)
EditorGUILayout.LabelField("JumpAcceleration(goal->start)", (grav - (g.y - s.y) / t).ToString("N2"));
}
}
}
if (Application.IsPlaying(link) && !link.IsAddedToWorld)
{
EditorGUILayout.HelpBox("Link is not added to the pathfinder. It will not be considered for pathfinding.", MessageType.Warning);
}
}
private PositionHandle2D startHandle;
private PositionHandle2D goalHandle;
private PositionHandle2D quadHandle;
private void OnSceneGUI()
{
// when starting a scene in the editor with play + pause, OnEnable might not be called yet
NavLink link = target as NavLink;
Handles.matrix = Matrix4x4.Translate(new Vector3(0, 0, link.transform.position.z));
EditorGUI.BeginChangeCheck();
Vector2 start = startHandle.DrawHandle(link.StartWorldPosition);
//Vector2 start = Handles.PositionHandle(link.StartWorldPosition, Quaternion.identity);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "NavLink change start position");
link.StartWorldPosition = start;
if (Application.IsPlaying(link) && link.autoMap)
link.UpdateMapping();
}
EditorGUI.BeginChangeCheck();
Vector2 goal = goalHandle.DrawHandle(link.GoalWorldPosition);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "NavLink change goal position");
link.GoalWorldPosition = goal;
if (Application.IsPlaying(link) && link.autoMap)
link.
UpdateMapping();
}
string enumName = spVisualizationType.enumNames[spVisualizationType.enumValueIndex];
switch (enumName)
{
case "QuadradticBezier":
EditorGUI.BeginChangeCheck();
Vector2 cp = quadHandle.DrawHandle(link.transform.TransformPoint(link.BezierControlPoint));
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "NavLink change bezier point");
link.BezierControlPoint = link.transform.InverseTransformPoint(cp);
}
break;
}
Handles.color = Color.red;
Handles.DrawWireDisc(start, Vector3.forward, PathBerserker2dSettings.PointMappingDistance);
Handles.DrawWireDisc(goal, Vector3.forward, PathBerserker2dSettings.PointMappingDistance);
Vector2 dir = goal - start;
Handles.BeginGUI();
Vector2 pos = dir * 0.5f + start;
Vector2 pos2D = HandleUtility.WorldToGUIPoint(pos);
var oldMatrix = GUI.matrix;
float angle = Vector2.SignedAngle(dir, Vector2.up) - 90f;
angle = angle < -90 ? 180 + angle : angle;
GUI.matrix = Matrix4x4.TRS(pos2D, Quaternion.Euler(0, 0, angle), Vector3.one) * Matrix4x4.Translate(new Vector2(-35, -20));
GUI.contentColor = Color.white;
GUI.Label(new Rect(0, 0, 70, 40), dir.magnitude.ToString("N2"), distanceLabelStyle);
GUI.matrix = oldMatrix;
Handles.EndGUI();
Handles.color = Color.white;
Camera cam = Camera.current;
float textLengthWorld = 10;
if (cam)
{
Vector2 startLineEnd = cam.ScreenToWorldPoint(pos2D + new Vector2(-35, 0));
Vector2 goalLineStart = cam.ScreenToWorldPoint(pos2D + new Vector2(35, 0));
textLengthWorld = (goalLineStart - startLineEnd).magnitude / 2f;
}
Handles.DrawLine(start, pos - dir.normalized * textLengthWorld);
Handles.DrawLine(pos + dir.normalized * textLengthWorld, goal);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1cac53c9931cf134ebd04b374ccfc151
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
using UnityEditor;
using UnityEngine;
namespace PathBerserker2d
{
[CustomEditor(typeof(NavSegmentSubstractor))]
internal class NavSegmentSubstractorInspector : Editor
{
SerializedProperty spfromAngle;
SerializedProperty sptoAngle;
private void OnEnable()
{
spfromAngle = serializedObject.FindProperty("fromAngle");
sptoAngle = serializedObject.FindProperty("toAngle");
}
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(spfromAngle);
EditorGUILayout.PropertyField(sptoAngle);
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
var t = (target as NavSegmentSubstractor).GetComponent<Transform>();
if (t.localRotation != Quaternion.identity)
{
EditorGUILayout.HelpBox("Rotation will not affect the rect.", MessageType.Warning);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dcd540a8a23f45d4ca6a11bbce598051
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,159 @@
using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
namespace PathBerserker2d
{
[CustomEditor(typeof(NavSurface))]
internal class NavSurface2dInspector : Editor
{
private SerializedProperty spNavSegments;
private SerializedProperty spMaxClearance;
private SerializedProperty spMinClearance;
private SerializedProperty spCellSize;
private SerializedProperty spIncludedColliders;
private SerializedProperty spMaxSlopeAngle;
private SerializedProperty spSmallestDistanceYouCareAbout;
private SerializedProperty spMinSegmentLength;
private SerializedProperty spOnlyStaticColliders;
private NavSurface navSurface;
bool advancedOpen;
private void OnEnable()
{
spNavSegments = serializedObject.FindProperty("navSegments");
spMaxClearance = serializedObject.FindProperty("maxClearance");
spMinClearance = serializedObject.FindProperty("minClearance");
spCellSize = serializedObject.FindProperty("cellSize");
spIncludedColliders = serializedObject.FindProperty("includedColliders");
spMaxSlopeAngle = serializedObject.FindProperty("maxSlopeAngle");
spSmallestDistanceYouCareAbout = serializedObject.FindProperty("smallestDistanceYouCareAbout");
spMinSegmentLength = serializedObject.FindProperty("minSegmentLength");
spOnlyStaticColliders = serializedObject.FindProperty("onlyStaticColliders");
navSurface = (NavSurface)target;
if (!BakedDataSanityCheck())
{
Debug.LogError("Baked data of this NavSurface did not pass sanity check. Please rebake it!");
}
}
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(spMaxClearance);
HeightFromSelectionButton(spMaxClearance, 1, Event.current);
EditorGUILayout.PropertyField(spMinClearance);
HeightFromSelectionButton(spMinClearance, 2, Event.current);
EditorGUILayout.PropertyField(spIncludedColliders);
EditorGUILayout.PropertyField(spMaxSlopeAngle);
EditorGUILayout.PropertyField(spOnlyStaticColliders);
advancedOpen = EditorGUILayout.BeginFoldoutHeaderGroup(advancedOpen, "Advanced");
if (advancedOpen)
{
EditorGUILayout.PropertyField(spCellSize);
EditorGUILayout.PropertyField(spSmallestDistanceYouCareAbout);
EditorGUILayout.PropertyField(spMinSegmentLength);
}
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
if (GUILayout.Button("Bake"))
{
if (Application.IsPlaying(navSurface))
{
navSurface.StartCoroutine(navSurface.Bake());
}
else
{
navSurface.StartBakeJob();
}
EditorApplication.update -= WaitForBakeJobToFinish;
EditorApplication.update += WaitForBakeJobToFinish;
Repaint();
}
if (navSurface.BakeJob?.IsRunning ?? false)
{
Rect r = EditorGUILayout.BeginVertical();
EditorGUI.ProgressBar(r, navSurface.BakeJob.Progress, "Baking");
GUILayout.Space(18);
EditorGUILayout.EndVertical();
Repaint();
}
if (navSurface.NavSegments?.Count > 0 && navSurface.BakeVersion < NavSurface.CurrentBakeVersion)
{
EditorGUILayout.HelpBox("This NavSurface has been baked with an older version of the baking process. (Rebake to hide this message)", MessageType.Warning);
}
MyGUI.Header("Info");
GUI.enabled = false;
EditorGUILayout.LabelField("Segments", spNavSegments.arraySize.ToString());
GUI.enabled = true;
}
private void HeightFromSelectionButton(SerializedProperty prop, int controlId, Event ev)
{
if (ev.type == EventType.ExecuteCommand && EditorGUIUtility.GetObjectPickerControlID() == controlId)
{
string commandName = ev.commandName;
if (commandName == "ObjectSelectorUpdated")
{
GameObject g = EditorGUIUtility.GetObjectPickerObject() as GameObject;
if (g == null)
return;
Renderer r = g.GetComponent<Renderer>();
if (r == null)
return;
prop.floatValue = r.bounds.size.y;
GUI.changed = true;
}
}
if (GUILayout.Button("From object"))
{
EditorGUIUtility.ShowObjectPicker<Renderer>(null, true, "", controlId);
}
}
private void WaitForBakeJobToFinish()
{
if (navSurface.BakeJob.IsFinished)
{
#if DEBUG
Debug.Log("Bake completed in " + navSurface.BakeJob.TotalBakeTime + "ms");
#endif
EditorApplication.update -= WaitForBakeJobToFinish;
EditorUtility.SetDirty(navSurface);
if (!Application.IsPlaying(navSurface))
{
navSurface.UpdateInternalData(navSurface.BakeJob.navSegments, navSurface.BakeJob.bounds);
}
serializedObject.Update();
SceneView.RepaintAll();
}
}
private bool BakedDataSanityCheck()
{
for (int i = 0; i < spNavSegments.arraySize; i++)
{
var seg = navSurface.GetSegment(i);
if (seg.Owner != navSurface)
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 294b9e1daad1eab4b8c2daab63b92b3a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
using UnityEngine;
using UnityEditor;
namespace PathBerserker2d
{
[InitializeOnLoad]
class PBWorldFaker
{
// register an event handler when the class is initialized
static PBWorldFaker()
{
EditorApplication.playModeStateChanged += LogPlayModeState;
if(!EditorApplication.isPlayingOrWillChangePlaymode)
PBWorld.NavGraph = new NavGraph(1);
}
private static void LogPlayModeState(PlayModeStateChange state)
{
if (state == PlayModeStateChange.ExitingPlayMode)
PBWorld.NavGraph = new NavGraph(1);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e15da2752391fa14fad448a06e11ed2b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
{
"name": "PathBerserker2d.Editor",
"references": [
"GUID:f483b8ed1e509354483048b0c7a56768"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8ba7676b8a5ae4a49b272c008f388df1
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,258 @@
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.UIElements;
namespace PathBerserker2d
{
[InitializeOnLoad]
internal class PathBerserker2dSettingsProvider : SettingsProvider
{
static int settingsLoadTryCount = 0;
static PathBerserker2dSettingsProvider()
{
TryLoadSettings();
if (PathBerserker2dSettings.instance == null)
{
EditorApplication.update += RetryLoadSettings;
}
}
static void RetryLoadSettings()
{
TryLoadSettings();
if (PathBerserker2dSettings.instance != null)
{
EditorApplication.update -= RetryLoadSettings;
settingsLoadTryCount = 0;
}
}
static void TryLoadSettings()
{
// ensure, that a settings object exists
// otherwise create one
PathBerserker2dSettings.instance = Resources.Load<PathBerserker2dSettings>(PathBerserker2dSettings.GlobalSettingsFile);
if (PathBerserker2dSettings.instance == null)
{
// security check
if (System.IO.File.Exists(System.IO.Path.Combine(Application.dataPath, "PathBerserker2d/Resources/", PathBerserker2dSettings.GlobalSettingsFile + ".asset")))
{
#if DEBUG
Debug.Log("Couldn't load settings file, but it does exist.");
#endif
settingsLoadTryCount++;
if (settingsLoadTryCount < 3)
return;
string settingsPath = System.IO.Path.Combine("PathBerserker2d/Resources/", PathBerserker2dSettings.GlobalSettingsFile + ".asset");
if (!EditorUtility.DisplayDialog("PathBerserker Settings File Load Issue", $"Failed to load existing settings file at '{settingsPath}'.", "Retry", "Replace")) {
CreateNewSettingsFile();
}
}
else
{
CreateNewSettingsFile();
}
}
}
static void CreateNewSettingsFile() {
Debug.Log("Found no existing settings file. Creating a new one.");
// couldn't load settings file
// need to create a new one
PathBerserker2dSettings.instance = ScriptableObject.CreateInstance<PathBerserker2dSettings>();
PathBerserker2dSettings.instance.OnValidate();
AssetDatabase.CreateAsset(PathBerserker2dSettings.instance, System.IO.Path.Combine(PathBerserker2dSettings.GlobalSettingsFolder, PathBerserker2dSettings.GlobalSettingsFile) + ".asset");
AssetDatabase.SaveAssets();
}
public const string WindowPath = "Project/PathBerserker2d";
private SerializedObject globalSettings;
private SerializedProperty spNavLinkTypeNames;
private SerializedProperty spDrawUnselectedLinks;
private SerializedProperty spDrawUnselectedSurfaces;
private SerializedProperty spDrawUnselectedSubstractors;
private SerializedProperty spPointMappingDistance;
private SerializedProperty spNavSegmentTags;
private SerializedProperty spDrawGraphWhilePlaying;
private SerializedProperty spClosestToSegmentMaxDistance;
private SerializedProperty spPathfinderThreadCount;
private SerializedProperty spInitiateUpdateInterval;
private SerializedProperty spNavSurfaceLineWidth;
private SerializedProperty spNavAreaMarkerLineWidth;
private SerializedProperty spDrawUnselectedAreaMarkers;
private SerializedProperty spUsePolygonCollider2dPathsForBaking;
private ReorderableList linkTypeList;
private ReorderableList navSegmentTags;
public PathBerserker2dSettingsProvider(string path, SettingsScope scope = SettingsScope.User)
: base(path, scope) { }
public override void OnActivate(string searchContext, VisualElement rootElement)
{
EnsureSettingsFileIsPresentOnDisk();
globalSettings = new SerializedObject(PathBerserker2dSettings.instance);
spNavLinkTypeNames = globalSettings.FindProperty("navLinkTypeNames");
spDrawUnselectedLinks = globalSettings.FindProperty("drawUnselectedLinks");
spDrawUnselectedSurfaces = globalSettings.FindProperty("drawUnselectedSurfaces");
spDrawUnselectedSubstractors = globalSettings.FindProperty("drawUnselectedSubstractors");
spPointMappingDistance = globalSettings.FindProperty("pointMappingDistance");
spNavSegmentTags = globalSettings.FindProperty("navTags");
spDrawGraphWhilePlaying = globalSettings.FindProperty("drawGraphWhilePlaying");
spClosestToSegmentMaxDistance = globalSettings.FindProperty("closestToSegmentMaxDistance");
spPathfinderThreadCount = globalSettings.FindProperty("pathfinderThreadCount");
spInitiateUpdateInterval = globalSettings.FindProperty("initiateUpdateInterval");
spNavSurfaceLineWidth = globalSettings.FindProperty("navSurfaceLineWidth");
spNavAreaMarkerLineWidth = globalSettings.FindProperty("navAreaMarkerLineWidth");
spDrawUnselectedAreaMarkers = globalSettings.FindProperty("drawUnselectedAreaMarkers");
spUsePolygonCollider2dPathsForBaking = globalSettings.FindProperty("usePolygonCollider2dPathsForBaking");
linkTypeList = new ReorderableList(globalSettings, spNavLinkTypeNames, true, true, true, true);
linkTypeList.drawHeaderCallback = DrawLinkTypeListHeader;
linkTypeList.drawElementCallback = DrawLinkTypeListItems;
linkTypeList.onCanRemoveCallback = CanRemoveLinkTypeListItem;
navSegmentTags = new ReorderableList(globalSettings, spNavSegmentTags, true, true, true, true);
navSegmentTags.drawHeaderCallback = DrawSegmentTagListHeader;
navSegmentTags.drawElementCallback = DrawSegmentTagListItems;
navSegmentTags.onRemoveCallback = OnRemoveNavTag;
navSegmentTags.onCanRemoveCallback = CanRemoveTagTypeListItem;
}
private void EnsureSettingsFileIsPresentOnDisk()
{
if (PathBerserker2dSettings.instance != null && AssetDatabase.Contains(PathBerserker2dSettings.instance))
return;
var instance = Resources.Load<PathBerserker2dSettings>(PathBerserker2dSettings.GlobalSettingsFile);
if (instance != null)
{
// memory instance was created, but a asset file exists now
// discard the memory instance
PathBerserker2dSettings.instance = instance;
}
else
{
var path = System.IO.Path.Combine(PathBerserker2dSettings.GlobalSettingsFolder, PathBerserker2dSettings.GlobalSettingsFile) + ".asset";
AssetDatabase.CreateAsset(PathBerserker2dSettings.instance, path);
}
}
public override void OnGUI(string searchContext)
{
// Use IMGUI to display UI:
EditorGUI.BeginChangeCheck();
// pathfinding
EditorGUILayout.PropertyField(spPointMappingDistance);
EditorGUILayout.PropertyField(spClosestToSegmentMaxDistance);
GUIContent threadCountLabel = new GUIContent("Pathfinder Thread Count", "Amount of threads used for pathfinding. NOTE: WebGL doesn't support threads.");
GUI.enabled = EditorUserBuildSettings.activeBuildTarget != BuildTarget.WebGL;
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.WebGL)
EditorGUILayout.IntField(threadCountLabel, 1);
else
EditorGUILayout.PropertyField(spPathfinderThreadCount, threadCountLabel);
GUI.enabled = true;
EditorGUILayout.PropertyField(spInitiateUpdateInterval);
EditorGUILayout.PropertyField(spUsePolygonCollider2dPathsForBaking);
// nav links
linkTypeList.DoLayoutList();
// nav segments
navSegmentTags.DoLayoutList();
// visualization
EditorGUILayout.PropertyField(spDrawUnselectedLinks);
EditorGUILayout.PropertyField(spDrawUnselectedSurfaces);
EditorGUILayout.PropertyField(spDrawUnselectedSubstractors);
EditorGUILayout.PropertyField(spDrawUnselectedAreaMarkers);
EditorGUILayout.PropertyField(spDrawGraphWhilePlaying);
EditorGUILayout.PropertyField(spNavSurfaceLineWidth);
EditorGUILayout.PropertyField(spNavAreaMarkerLineWidth);
if (EditorGUI.EndChangeCheck())
globalSettings.ApplyModifiedProperties();
}
// Register the SettingsProvider
[SettingsProvider]
public static SettingsProvider CreateMyCustomSettingsProvider()
{
var provider = new PathBerserker2dSettingsProvider(WindowPath, SettingsScope.Project);
provider.keywords = new string[] {
"NavLinkTypeNames"
};
return provider;
}
private void DrawLinkTypeListHeader(Rect rect)
{
EditorGUI.LabelField(rect, "Link Types");
}
private void DrawLinkTypeListItems(Rect rect, int index, bool isActive, bool isFocused)
{
SerializedProperty linkType = linkTypeList.serializedProperty.GetArrayElementAtIndex(index);
GUI.enabled = index >= PathBerserker2dSettings.buildinNavLinkTypeNames.Length;
float orgWidth = rect.width;
rect.width *= 0.7f;
EditorGUI.PropertyField(rect, linkType, new GUIContent("Type " + index));
GUI.enabled = true;
rect.x += rect.width + 5;
rect.width = orgWidth - rect.width - 5;
PathBerserker2dSettings.NavLinkTypeColors[index] = EditorGUI.ColorField(rect, PathBerserker2dSettings.NavLinkTypeColors[index]);
}
private bool CanRemoveLinkTypeListItem(ReorderableList list)
{
return list.index >= PathBerserker2dSettings.buildinNavLinkTypeNames.Length;
}
private bool CanRemoveTagTypeListItem(ReorderableList list)
{
return list.index > 0;
}
private void DrawSegmentTagListHeader(Rect rect)
{
EditorGUI.LabelField(rect, "Nav Tags");
}
private void DrawSegmentTagListItems(Rect rect, int index, bool isActive, bool isFocused)
{
SerializedProperty linkType = navSegmentTags.serializedProperty.GetArrayElementAtIndex(index);
float orgWidth = rect.width;
rect.width *= 0.7f;
EditorGUI.PropertyField(rect, linkType, new GUIContent("Tag " + index));
rect.x += rect.width + 5;
rect.width = orgWidth - rect.width - 5;
PathBerserker2dSettings.NavTagColors[index] = EditorGUI.ColorField(rect, PathBerserker2dSettings.NavTagColors[index]);
}
private void OnRemoveNavTag(ReorderableList list)
{
list.serializedProperty.DeleteArrayElementAtIndex(list.index);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 08eb9adc91334034ab02b597adb93a96
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fa81fd185b0d300408709db17ffe2a92
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,65 @@
using UnityEngine;
using UnityEditor;
using System;
using System.Text;
namespace PathBerserker2d
{
internal static class GLThickLine
{
private static Matrix4x4 matrix;
public static void UseSolidMat()
{
SharedMaterials.UnlitVertexColorSolid.SetPass(0);
}
public static void UseTransparentMat()
{
SharedMaterials.UnlitVertexColorTransparent.SetPass(0);
}
public static void Begin(Matrix4x4 matrix)
{
GLThickLine.matrix = matrix;
GL.PushMatrix();
GL.Begin(GL.QUADS);
GL.LoadProjectionMatrix(Camera.current.projectionMatrix);
UseSolidMat();
}
public static void End()
{
GL.End();
GL.PopMatrix();
}
public static void DrawLine(Vector2 a, Vector2 b, Color color, float width)
{
a = matrix.MultiplyPoint3x4(a);
b = matrix.MultiplyPoint3x4(b);
Vector2 normal = new Vector2(-(b.y - a.y), b.x - a.x).normalized * width * 0.5f;
GL.Color(color);
GL.Vertex3(a.x - normal.x, a.y - normal.y, 0);
GL.Vertex3(a.x + normal.x, a.y + normal.y, 0);
GL.Vertex3(b.x + normal.x, b.y + normal.y, 0);
GL.Vertex3(b.x - normal.x, b.y - normal.y, 0);
}
public static void DrawRect(Vector3[] corners, Color color)
{
GL.Color(color);
GL.Vertex(matrix.MultiplyPoint3x4(corners[0]));
GL.Vertex(matrix.MultiplyPoint3x4(corners[1]));
GL.Vertex(matrix.MultiplyPoint3x4(corners[2]));
GL.Vertex(matrix.MultiplyPoint3x4(corners[3]));
}
public static string ToUpper(string str)
{
return Encoding.UTF8.GetString(Convert.FromBase64String(str));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7000cfcfa4d6eb34c98c7738b59e9de2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,217 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace PathBerserker2d
{
class MiterLineMeshCreator
{
private List<Vector3> verts = new List<Vector3>();
private List<Color32> colors = new List<Color32>();
private List<int> tris = new List<int>();
public void CreateLine(Mesh mesh, IList<Vector2> linePoints, float thickness, Color line, Color32 corner, Color endpoint)
{
verts.Clear();
colors.Clear();
tris.Clear();
verts.Capacity = Math.Max(verts.Capacity, linePoints.Count * 2);
colors.Capacity = Math.Max(colors.Capacity, verts.Count);
tris.Capacity = Math.Max(tris.Capacity, linePoints.Count * 4);
Vector2 curTangent = (linePoints[0] - linePoints[1]).normalized;
Vector2 curNormal = new Vector2(-curTangent.y, curTangent.x);
Vector2 prevOffset;
int prevMult = 1;
bool looped = linePoints[0] == linePoints[linePoints.Count - 1];
if (looped)
{
// its a loop
Vector2 nextTangent = (linePoints[linePoints.Count - 2] - linePoints[linePoints.Count - 1]).normalized;
Vector2 nextNormal = new Vector2(-nextTangent.y, nextTangent.x);
var tangent2 = (nextTangent + curTangent).normalized;
var miter2 = new Vector2(-tangent2.y, tangent2.x);
float length2 = thickness / Vector2.Dot(nextNormal, miter2);
prevOffset = length2 * miter2;
prevMult = Math.Sign(Vector2.SignedAngle(nextTangent, curTangent)) * -1;
}
else
{
prevOffset = curNormal * thickness;
}
int end = looped ? linePoints.Count - 1 : linePoints.Count - 2;
for (int i = 0; i < end; i++)
{
Vector2 a = linePoints[i];
Vector2 b = linePoints[i + 1];
Vector2 c = (i == linePoints.Count - 2) ? linePoints[1] : linePoints[i + 2];
Vector2 nextTangent = (b - c).normalized;
Vector2 nextNormal = new Vector2(-nextTangent.y, nextTangent.x);
var tangent2 = (nextTangent + curTangent).normalized;
var miter2 = new Vector2(-tangent2.y, tangent2.x);
float length2 = thickness / Vector2.Dot(curNormal, miter2);
Vector2 offset2 = length2 * miter2;
verts.Add(a + prevOffset * prevMult);
verts.Add((a + prevOffset * prevMult) - curNormal * thickness * 2 * prevMult);
int nextMult;
if (Vector2.SignedAngle(curTangent, nextTangent) > 0)
{
if (prevMult == -1)
{
verts.Add(b - offset2);
verts.Add((b - offset2) + curNormal * thickness * 2);
}
else
{
verts.Add((b - offset2) + curNormal * thickness * 2);
verts.Add(b - offset2);
}
nextMult = -1;
}
else
{
if (prevMult == -1)
{
verts.Add((b + offset2) - curNormal * thickness * 2);
verts.Add(b + offset2);
}
else
{
verts.Add(b + offset2);
verts.Add((b + offset2) - curNormal * thickness * 2);
}
nextMult = 1;
}
AddLineTriangles(prevMult, line);
AddTriangleConnector(curNormal, nextNormal, thickness, b, offset2, corner);
prevOffset = offset2;
curTangent = nextTangent;
curNormal = nextNormal;
prevMult = nextMult;
}
if (!looped)
{
verts.Add(linePoints[linePoints.Count - 2] + prevOffset * prevMult);
verts.Add((linePoints[linePoints.Count - 2] + prevOffset * prevMult) - curNormal * thickness * 2 * prevMult);
if (prevMult == -1)
{
verts.Add(linePoints[linePoints.Count - 1] - curNormal * thickness);
verts.Add(linePoints[linePoints.Count - 1] + curNormal * thickness);
}
else
{
verts.Add(linePoints[linePoints.Count - 1] + curNormal * thickness);
verts.Add(linePoints[linePoints.Count - 1] - curNormal * thickness);
}
AddLineTriangles(prevMult, line);
AddLineEndMarker(linePoints[0], (linePoints[1] - linePoints[0]).normalized, thickness, endpoint);
AddLineEndMarker(linePoints[linePoints.Count -1], (linePoints[linePoints.Count - 2] - linePoints[linePoints.Count - 1]).normalized, thickness, endpoint);
}
mesh.triangles = new int[] { };
mesh.vertices = verts.ToArray();
mesh.triangles = tris.ToArray();
mesh.colors32 = colors.ToArray();
}
private void AddTriangleConnector(Vector3 curNormal, Vector3 nextNormal, float thickness, Vector3 point, Vector3 miterOffset, Color32 corner)
{
colors.Add(corner);
colors.Add(corner);
colors.Add(corner);
if (Vector2.SignedAngle(curNormal, nextNormal) > 0)
{
verts.Add((point - miterOffset) + nextNormal * thickness * 2);
verts.Add(point - miterOffset);
verts.Add((point - miterOffset) + curNormal * thickness * 2);
tris.Add(verts.Count - 3);
tris.Add(verts.Count - 1);
tris.Add(verts.Count - 2);
}
else
{
verts.Add((point + miterOffset) - nextNormal * thickness * 2);
verts.Add(point + miterOffset);
verts.Add((point + miterOffset) - curNormal * thickness * 2);
tris.Add(verts.Count - 2);
tris.Add(verts.Count - 1);
tris.Add(verts.Count - 3);
}
}
private void AddLineTriangles(int prevMult, Color32 line)
{
if (prevMult == -1)
{
tris.Add(colors.Count + 3);
tris.Add(colors.Count + 1);
tris.Add(colors.Count + 0);
tris.Add(colors.Count + 0);
tris.Add(colors.Count + 2);
tris.Add(colors.Count + 3);
}
else
{
tris.Add(colors.Count + 0);
tris.Add(colors.Count + 1);
tris.Add(colors.Count + 3);
tris.Add(colors.Count + 3);
tris.Add(colors.Count + 2);
tris.Add(colors.Count + 0);
}
colors.Add(line);
colors.Add(line);
colors.Add(line);
colors.Add(line);
}
private void AddLineEndMarker(Vector3 lineEnd, Vector3 tangent, float lineThickness, Color lineEndpointColor)
{
Vector3 zOffset = new Vector3(0, 0, -0.01f);
Vector3 normal = new Vector3(-tangent.y, tangent.x);
float increasedThickness = lineThickness * 1.25f * 2;
int index = verts.Count;
verts.Add(lineEnd + normal * increasedThickness + zOffset);
verts.Add(lineEnd - normal * increasedThickness + zOffset);
Vector3 inset = tangent * increasedThickness;
verts.Add(lineEnd + inset + normal * increasedThickness + zOffset);
verts.Add(lineEnd + inset - normal * increasedThickness + zOffset);
colors.Add(lineEndpointColor);
colors.Add(lineEndpointColor);
colors.Add(lineEndpointColor);
colors.Add(lineEndpointColor);
tris.Add(index + 1);
tris.Add(index);
tris.Add(index + 2);
tris.Add(index + 2);
tris.Add(index + 3);
tris.Add(index + 1);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2b5a87ab77b93854fa9469929abc0685
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
using UnityEditor;
using UnityEngine;
namespace PathBerserker2d
{
static class PrimitiveMesh
{
static Mesh quad;
public static Mesh Quad
{
get
{
if (quad == null)
{
quad = new Mesh();
quad.vertices = new Vector3[] {
new Vector3(0, 0, 0),
new Vector3(0, 1, 0),
new Vector3(1, 1, 0),
new Vector3(1, 0, 0)};
quad.triangles = new int[] {
0, 1, 2,
0, 2, 3};
}
return quad;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 19bb1e8824aba9041b7cd3f4ad60d8e0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEditor;
namespace PathBerserker2d
{
static class SharedMaterials
{
static Material unlitVertexColorSolid;
static Material unlitVertexColorTransparent;
static Material unlitStripped;
static Material unlitTransparentTinted;
static Material unlitTexture;
static int unlitTransparentTinted_ColorId;
static int unlitStripped_ColorId;
static int unlitStripped_XOffsetId;
static int unlitStripped_PauseSizeId;
static int unlitStripped_SegmentSizeId;
public static Material UnlitVertexColorSolid
{
get
{
if (unlitVertexColorSolid == null)
unlitVertexColorSolid = new Material(Shader.Find("Hidden/PB_UnlitVertexColor"));
return unlitVertexColorSolid;
}
}
public static Material UnlitVertexColorTransparent
{
get
{
if (unlitVertexColorTransparent == null)
unlitVertexColorTransparent = new Material(Shader.Find("Hidden/PB_UnlitVertexColorTransparent"));
return unlitVertexColorTransparent;
}
}
public static Material UnlitStripped
{
get
{
if (unlitStripped == null)
{
unlitStripped = new Material(Shader.Find("Hidden/PB_UnlitSegmented"));
unlitStripped.SetFloat("_SegmentSize", 0.21f);
unlitStripped.SetFloat("_PauseSize", 0.31f);
unlitStripped_ColorId = unlitStripped.shader.GetPropertyNameId(3);
unlitStripped_XOffsetId = unlitStripped.shader.GetPropertyNameId(2);
unlitStripped_PauseSizeId = unlitStripped.shader.GetPropertyNameId(1);
unlitStripped_SegmentSizeId = unlitStripped.shader.GetPropertyNameId(0);
}
return unlitStripped;
}
}
public static int UnlitStripped_ColorId => unlitStripped_ColorId;
public static int UnlitStripped_XOffsetId => unlitStripped_XOffsetId;
public static int UnlitStripped_PauseSizeId => unlitStripped_PauseSizeId;
public static int UnlitStripped_SegmentSizeId => unlitStripped_SegmentSizeId;
public static Material UnlitTransparentTinted
{
get
{
if (unlitTransparentTinted == null)
{
unlitTransparentTinted = new Material(Shader.Find("Hidden/PB_UnlitTransparentTinted"));
unlitTransparentTinted_ColorId = unlitTransparentTinted.shader.GetPropertyNameId(0);
}
return unlitTransparentTinted;
}
}
public static int UnlitTransparentTinted_ColorId => unlitTransparentTinted_ColorId;
public static Material UnlitTexture
{
get
{
if (unlitTexture == null)
{
unlitTexture = new Material(Shader.Find("Unlit/Texture"));
}
return unlitTexture;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 75f31dc41b4fc7c46a13317cf739b246
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 524863b9605ccf542ad776b1873da2fe
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,93 @@
using System;
using UnityEditor;
using UnityEngine;
namespace PathBerserker2d
{
internal class NavLinkCreatorWindow : EditorWindow
{
[MenuItem("Window/AI/NavLinkCreator")]
static void Init()
{
// Get existing open window or if none, make a new one:
NavLinkCreatorWindow window = (NavLinkCreatorWindow)EditorWindow.GetWindow(typeof(NavLinkCreatorWindow));
window.Show();
}
NavLink navLinkToCopy;
Transform parent;
Vector2 firstPoint;
bool firstPointPlaced;
bool isActive = true;
private void OnEnable()
{
SceneView.duringSceneGui -= SceneView_duringSceneGui;
SceneView.duringSceneGui += SceneView_duringSceneGui;
}
private void OnDisable()
{
SceneView.duringSceneGui -= SceneView_duringSceneGui;
}
void OnGUI()
{
MyGUI.Header("Link Settings");
parent = EditorGUILayout.ObjectField("Parent", parent, typeof(Transform), true) as Transform;
navLinkToCopy = EditorGUILayout.ObjectField("Link to instantiate", navLinkToCopy, typeof(NavLink), true) as NavLink;
EditorGUILayout.HelpBox("Left mouse button to place link node. Right mouse button to abort.", MessageType.Info);
isActive = EditorGUILayout.Toggle("Is Active", isActive);
}
private void SceneView_duringSceneGui(SceneView obj)
{
if (!isActive || navLinkToCopy == null)
return;
Event current = Event.current;
if (current.type == EventType.MouseDown)
{
if (current.button == 0)
{
if (!firstPointPlaced)
{
firstPoint = HandleUtility.GUIPointToWorldRay(current.mousePosition).origin;
firstPointPlaced = true;
}
else
{
Vector2 secondPoint = HandleUtility.GUIPointToWorldRay(current.mousePosition).origin;
var link = Instantiate(navLinkToCopy);
link.transform.parent = parent;
link.transform.position = firstPoint + (secondPoint - firstPoint) * 0.5f;
var ser = new SerializedObject(link);
ser.FindProperty("start").vector2Value = link.transform.InverseTransformPoint(firstPoint);
ser.FindProperty("goal").vector2Value = link.transform.InverseTransformPoint(secondPoint);
ser.FindProperty("bezierControlPoint").vector2Value = link.transform.InverseTransformPoint(link.transform.position + Vector3.up * 2);
ser.ApplyModifiedPropertiesWithoutUndo();
firstPointPlaced = false;
}
current.Use();
}
else if (current.button == 1)
{
firstPointPlaced = false;
current.Use();
}
}
if (firstPointPlaced)
{
Handles.DrawLine(firstPoint, HandleUtility.GUIPointToWorldRay(current.mousePosition).origin);
SceneView.RepaintAll();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a74345800bbb4a44ab3646a5bceeca7b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: