chore: initial commit
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd800ca490ca3504a91a04cbbe34fe93
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91a2221b1f964c946af33b7bb66b948d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfac06ae39b4da041b0233fbe194c0a2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1df174b62e1d3684f9fc16ede26d1866
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e5d17af10e083841ac8d81ba70fd984
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88926f52dae6ae348a100721fd59f003
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38d3d3506e06653448c052e8936eb8dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d337207a086912840ae6fa25daa40c29
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a6fbf381f5910a46b7602b805ab3da5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 492511a86fc803947bc65e80cb38dcd1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 723a305b61a51e64ebec0506f93c1112
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed60b9cfa1889ff4f8241ad268f4075f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15cdcbb829a70c74fb474d4fdee8f45f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f77a85715899ecd40946b0b29b2d294f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 329c6c7610e18854cbfdf1038774b22f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dae66614c81006d4fa5cbb26894dd989
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 639e10eb7c848df40b745a7e356f1f87
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68c53e164cc0a494d81ff4bcf63313b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 998c038260d5d72468b1e7310af820c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef995227ea241d8438a3ed5b3425be5e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d058cde802ff674eb7997fc35128da9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86b5b5f74d10532448503446490e7a25
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4e1d5d0b0fa3dc4ea7d765130dd6e83
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d33b2293443d0f43bdca36ef03dec3a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3619cbf7ac94f9e4c88c3b613d191c69
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1cac53c9931cf134ebd04b374ccfc151
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dcd540a8a23f45d4ca6a11bbce598051
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 294b9e1daad1eab4b8c2daab63b92b3a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e15da2752391fa14fad448a06e11ed2b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "PathBerserker2d.Editor",
|
||||
"references": [
|
||||
"GUID:f483b8ed1e509354483048b0c7a56768"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ba7676b8a5ae4a49b272c008f388df1
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08eb9adc91334034ab02b597adb93a96
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa81fd185b0d300408709db17ffe2a92
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7000cfcfa4d6eb34c98c7738b59e9de2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b5a87ab77b93854fa9469929abc0685
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19bb1e8824aba9041b7cd3f4ad60d8e0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75f31dc41b4fc7c46a13317cf739b246
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 524863b9605ccf542ad776b1873da2fe
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a74345800bbb4a44ab3646a5bceeca7b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fee4b89171754694689b0f4ac77ec981
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,62 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.PathBerserker2d.Scripts.PathBerserker2d.Upgrade
|
||||
{
|
||||
static class DeleteObsoleteFiles
|
||||
{
|
||||
static string[] obsoleteFiles = new string[] {
|
||||
"Corgi.zip",
|
||||
"Editor/PathBerserker2d-Editor.dll",
|
||||
"Editor/ShowAssetIds.cs",
|
||||
"Editor/FootStepSoundsInspector.cs",
|
||||
"Scripts/PathBerserker2d.dll",
|
||||
"Scripts/PathBerserker2d.xml",
|
||||
"Scripts/TransformBasedMovement.cs",
|
||||
"Scripts/Examples/AdjustRotation.cs",
|
||||
"Scripts/Examples/CornerRotationSkipper.cs",
|
||||
"Scripts/Examples/Elevator.cs",
|
||||
"Scripts/Examples/Follower.cs",
|
||||
"Scripts/Examples/FootStepSounds.cs",
|
||||
"Scripts/Examples/GoalWalker.cs",
|
||||
"Scripts/Examples/KeepGrounded.cs",
|
||||
"Scripts/Examples/MouseWalker.cs",
|
||||
"Scripts/Examples/MovingPlatform.cs",
|
||||
"Scripts/Examples/MultiGoalWalker.cs",
|
||||
"Scripts/Examples/PatrolWalker.cs",
|
||||
"Scripts/Examples/RandomWalker.cs",
|
||||
};
|
||||
|
||||
static string[] obsoleteDirs = new string[] {
|
||||
"Editor",
|
||||
"Scripts/Examples"
|
||||
};
|
||||
|
||||
public static void RemoveObsoleteFiles()
|
||||
{
|
||||
string basePath = Path.Combine(Application.dataPath, "PathBerserker2d");
|
||||
|
||||
foreach (var file in obsoleteFiles)
|
||||
{
|
||||
string path = Path.Combine(basePath, file);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
Debug.Log("Deleted " + path);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var dir in obsoleteDirs)
|
||||
{
|
||||
string path = Path.Combine(basePath, dir);
|
||||
if (Directory.Exists(path) && !Directory.EnumerateFiles(path).GetEnumerator().MoveNext())
|
||||
{
|
||||
Directory.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3bbdff88e6872d74d9dd37db0b6e9c12
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
198
Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MD4.cs
Normal file
198
Assets/PathBerserker2d/Scripts/PathBerserker2d.Upgrade/MD4.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Assets.PathBerserker2d.Scripts.PathBerserker2d.Upgrade
|
||||
{
|
||||
// Taken from http://www.superstarcoders.com/blogs/posts/md4-hash-algorithm-in-c-sharp.aspx
|
||||
// Probably not the best implementation of MD4, but it works.
|
||||
public class MD4 : HashAlgorithm
|
||||
{
|
||||
private uint _a;
|
||||
private uint _b;
|
||||
private uint _c;
|
||||
private uint _d;
|
||||
private uint[] _x;
|
||||
private int _bytesProcessed;
|
||||
|
||||
public MD4()
|
||||
{
|
||||
_x = new uint[16];
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_a = 0x67452301;
|
||||
_b = 0xefcdab89;
|
||||
_c = 0x98badcfe;
|
||||
_d = 0x10325476;
|
||||
|
||||
_bytesProcessed = 0;
|
||||
}
|
||||
|
||||
protected override void HashCore(byte[] array, int offset, int length)
|
||||
{
|
||||
ProcessMessage(Bytes(array, offset, length));
|
||||
}
|
||||
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessMessage(Padding());
|
||||
|
||||
return new[] { _a, _b, _c, _d }.SelectMany(word => Bytes(word)).ToArray();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessMessage(IEnumerable<byte> bytes)
|
||||
{
|
||||
foreach (byte b in bytes)
|
||||
{
|
||||
int c = _bytesProcessed & 63;
|
||||
int i = c >> 2;
|
||||
int s = (c & 3) << 3;
|
||||
|
||||
_x[i] = (_x[i] & ~((uint)255 << s)) | ((uint)b << s);
|
||||
|
||||
if (c == 63)
|
||||
{
|
||||
Process16WordBlock();
|
||||
}
|
||||
|
||||
_bytesProcessed++;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<byte> Bytes(byte[] bytes, int offset, int length)
|
||||
{
|
||||
for (int i = offset; i < length; i++)
|
||||
{
|
||||
yield return bytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<byte> Bytes(uint word)
|
||||
{
|
||||
yield return (byte)(word & 255);
|
||||
yield return (byte)((word >> 8) & 255);
|
||||
yield return (byte)((word >> 16) & 255);
|
||||
yield return (byte)((word >> 24) & 255);
|
||||
}
|
||||
|
||||
private IEnumerable<byte> Repeat(byte value, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
yield return value;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<byte> Padding()
|
||||
{
|
||||
return Repeat(128, 1)
|
||||
.Concat(Repeat(0, ((_bytesProcessed + 8) & 0x7fffffc0) + 55 - _bytesProcessed))
|
||||
.Concat(Bytes((uint)_bytesProcessed << 3))
|
||||
.Concat(Repeat(0, 4));
|
||||
}
|
||||
|
||||
private void Process16WordBlock()
|
||||
{
|
||||
uint aa = _a;
|
||||
uint bb = _b;
|
||||
uint cc = _c;
|
||||
uint dd = _d;
|
||||
|
||||
foreach (int k in new[] { 0, 4, 8, 12 })
|
||||
{
|
||||
aa = Round1Operation(aa, bb, cc, dd, _x[k], 3);
|
||||
dd = Round1Operation(dd, aa, bb, cc, _x[k + 1], 7);
|
||||
cc = Round1Operation(cc, dd, aa, bb, _x[k + 2], 11);
|
||||
bb = Round1Operation(bb, cc, dd, aa, _x[k + 3], 19);
|
||||
}
|
||||
|
||||
foreach (int k in new[] { 0, 1, 2, 3 })
|
||||
{
|
||||
aa = Round2Operation(aa, bb, cc, dd, _x[k], 3);
|
||||
dd = Round2Operation(dd, aa, bb, cc, _x[k + 4], 5);
|
||||
cc = Round2Operation(cc, dd, aa, bb, _x[k + 8], 9);
|
||||
bb = Round2Operation(bb, cc, dd, aa, _x[k + 12], 13);
|
||||
}
|
||||
|
||||
foreach (int k in new[] { 0, 2, 1, 3 })
|
||||
{
|
||||
aa = Round3Operation(aa, bb, cc, dd, _x[k], 3);
|
||||
dd = Round3Operation(dd, aa, bb, cc, _x[k + 8], 9);
|
||||
cc = Round3Operation(cc, dd, aa, bb, _x[k + 4], 11);
|
||||
bb = Round3Operation(bb, cc, dd, aa, _x[k + 12], 15);
|
||||
}
|
||||
|
||||
unchecked
|
||||
{
|
||||
_a += aa;
|
||||
_b += bb;
|
||||
_c += cc;
|
||||
_d += dd;
|
||||
}
|
||||
}
|
||||
|
||||
private static uint ROL(uint value, int numberOfBits)
|
||||
{
|
||||
return (value << numberOfBits) | (value >> (32 - numberOfBits));
|
||||
}
|
||||
|
||||
private static uint Round1Operation(uint a, uint b, uint c, uint d, uint xk, int s)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return ROL(a + ((b & c) | (~b & d)) + xk, s);
|
||||
}
|
||||
}
|
||||
|
||||
private static uint Round2Operation(uint a, uint b, uint c, uint d, uint xk, int s)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return ROL(a + ((b & c) | (b & d) | (c & d)) + xk + 0x5a827999, s);
|
||||
}
|
||||
}
|
||||
|
||||
private static uint Round3Operation(uint a, uint b, uint c, uint d, uint xk, int s)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return ROL(a + (b ^ c ^ d) + xk + 0x6ed9eba1, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class FileIDUtil
|
||||
{
|
||||
public static int Compute(Type t)
|
||||
{
|
||||
string toBeHashed = "s\0\0\0" + t.Namespace + t.Name;
|
||||
|
||||
using (HashAlgorithm hash = new MD4())
|
||||
{
|
||||
byte[] hashed = hash.ComputeHash(System.Text.Encoding.UTF8.GetBytes(toBeHashed));
|
||||
|
||||
int result = 0;
|
||||
|
||||
for (int i = 3; i >= 0; --i)
|
||||
{
|
||||
result <<= 8;
|
||||
result |= hashed[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d2b504d66469914ea89897e98917234
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,127 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Assets.PathBerserker2d.Scripts.PathBerserker2d.Upgrade
|
||||
{
|
||||
class MissingScriptResolver
|
||||
{
|
||||
string navAgentFI;
|
||||
string navSurfaceFI;
|
||||
string navSegmentSubstractorFI;
|
||||
string navAreaMarkerFI;
|
||||
string dynamicObstacleFI;
|
||||
|
||||
public static void UpdateReferences()
|
||||
{
|
||||
string dllGuid = "45d3c5b18a3fb854b94b339e477774af";
|
||||
|
||||
int navAgentFI = -1018851484;
|
||||
string navAgentGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavAgent/NavAgent.cs");
|
||||
|
||||
int navSurfaceFI = -567900050;
|
||||
string navSurfaceGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavSurface/NavSurface.cs");
|
||||
|
||||
int navLinkFI = -546232842;
|
||||
string navLinkGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLink.cs");
|
||||
|
||||
int navLinkClusterFI = 1837436107;
|
||||
string navLinkClusterGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavLinkCluster.cs");
|
||||
|
||||
int navSegmentSubstractorFI = -274983532;
|
||||
string navSegmentSubstractorGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavSegmentSubstractor.cs");
|
||||
|
||||
int navAreaMarkerFI = 709968320;
|
||||
string navAreaMarkerGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/NavAreaMarker.cs");
|
||||
|
||||
int dynamicObstacleFI = -721922897;
|
||||
string dynamicObstacleGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/NavObjects/DynamicObstacle.cs");
|
||||
|
||||
int pathBerserker2dSettingsFI = -1515731982;
|
||||
string pathBerserker2dSettingsGUID = AssetDatabase.AssetPathToGUID("Assets/PathBerserker2d/Scripts/PathBerserker2d/PathBerserker2dSettings.cs");
|
||||
|
||||
int[] fis = new int[] {
|
||||
navAgentFI,
|
||||
navSurfaceFI,
|
||||
navSegmentSubstractorFI,
|
||||
navAreaMarkerFI,
|
||||
dynamicObstacleFI,
|
||||
pathBerserker2dSettingsFI,
|
||||
navLinkFI,
|
||||
navLinkClusterFI
|
||||
};
|
||||
|
||||
string[] guids = new string[] {
|
||||
navAgentGUID,
|
||||
navSurfaceGUID,
|
||||
navSegmentSubstractorGUID,
|
||||
navAreaMarkerGUID,
|
||||
dynamicObstacleGUID,
|
||||
pathBerserker2dSettingsGUID,
|
||||
navLinkGUID,
|
||||
navLinkClusterGUID
|
||||
};
|
||||
|
||||
for (int i = 0; i < guids.Length; i++)
|
||||
{
|
||||
if (guids[i] == null)
|
||||
{
|
||||
Debug.LogError("One or multiple cs files could not be found. Aborting upgrade. Please make sure that the Plugin files are in Assets/PathBerserker2d");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// first patch settings
|
||||
foreach (var metaFile in Directory.EnumerateFiles(System.IO.Path.Combine(Application.dataPath, "PathBerserker2d/Resources/"), "*.asset", SearchOption.AllDirectories))
|
||||
{
|
||||
FixFile(metaFile, fis, dllGuid, guids);
|
||||
}
|
||||
|
||||
// patch everything else
|
||||
foreach (var metaFile in Directory.EnumerateFiles(Application.dataPath, "*", SearchOption.AllDirectories).Where(f => f.EndsWith(".unity") || f.EndsWith(".prefab")))
|
||||
{
|
||||
FixFile(metaFile, fis, dllGuid, guids);
|
||||
}
|
||||
|
||||
Debug.Log("Finished!");
|
||||
}
|
||||
|
||||
private static void FixFile(string path, int[] fis, string dllGuid, string[] guids)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileInfo file = new FileInfo(path);
|
||||
bool isHidden = (file.Attributes & FileAttributes.Hidden) != 0;
|
||||
file.Attributes &= ~FileAttributes.Hidden;
|
||||
|
||||
string prevText = File.ReadAllText(path);
|
||||
string text = prevText;
|
||||
|
||||
for (int i = 0; i < fis.Length; i++)
|
||||
{
|
||||
text = text.Replace($"fileID: {fis[i]}, guid: {dllGuid}",
|
||||
$"fileID: 11500000, guid: {guids[i]}");
|
||||
}
|
||||
|
||||
File.WriteAllText(path, text);
|
||||
if (isHidden)
|
||||
file.Attributes |= FileAttributes.Hidden;
|
||||
|
||||
if (prevText != text)
|
||||
{
|
||||
Debug.Log("Updated " + path);
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ad6757722d743440857770a88e128cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "PathBerserker2d.Upgrade",
|
||||
"references": [
|
||||
"GUID:f483b8ed1e509354483048b0c7a56768"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd89c7216da4dd2478872203e056f46b
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.PathBerserker2d.Scripts.PathBerserker2d.Upgrade
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
class UpdateNotificationWindow : EditorWindow
|
||||
{
|
||||
[MenuItem("Window/General/PathBerserker Update Log")]
|
||||
static void ShowWindow()
|
||||
{
|
||||
// Get existing open window or if none, make a new one:
|
||||
UpdateNotificationWindow window = (UpdateNotificationWindow)EditorWindow.GetWindow(typeof(UpdateNotificationWindow));
|
||||
window.Show();
|
||||
}
|
||||
|
||||
static UpdateNotificationWindow()
|
||||
{
|
||||
EditorApplication.update += EditorUpdate;
|
||||
}
|
||||
|
||||
static void EditorUpdate()
|
||||
{
|
||||
if (!EditorPrefs.GetBool("pathberserker.showedupgrader") && EditorPrefs.GetBool("pathberserker.showedupdate.1_4"))
|
||||
{
|
||||
ShowWindow();
|
||||
|
||||
EditorPrefs.SetBool("pathberserker.showedupgrader", true);
|
||||
}
|
||||
EditorPrefs.SetString("pathberserker.installed_version", AssemblyInfo.Version);
|
||||
EditorApplication.update -= EditorUpdate;
|
||||
}
|
||||
|
||||
GUIStyle labelStyle;
|
||||
GUIStyle headingStyle;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
try
|
||||
{
|
||||
labelStyle = new GUIStyle(EditorStyles.label);
|
||||
}
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
labelStyle = new GUIStyle();
|
||||
}
|
||||
|
||||
labelStyle.normal.textColor = Color.white;
|
||||
labelStyle.richText = true;
|
||||
labelStyle.wordWrap = true;
|
||||
|
||||
headingStyle = new GUIStyle(labelStyle);
|
||||
headingStyle.fontSize += 20;
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if (labelStyle == null || headingStyle == null)
|
||||
OnEnable();
|
||||
if (labelStyle == null || headingStyle == null)
|
||||
return;
|
||||
|
||||
EditorGUILayout.LabelField("<color=orange>Pathberserker 2d - Upgrader</color>", headingStyle);
|
||||
EditorGUILayout.LabelField(AssemblyInfo.Version, labelStyle);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("<i>This window can be reopened at 'Window/General/PathBerserker Update Log'</i>", labelStyle);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("<size=15><color=red>Important</color></size>", labelStyle);
|
||||
EditorGUILayout.LabelField("All Dll files have been replaced with AssemblyDefinitions. <b>All references to MonoBehaviors that where previously located in a DLL are now broken!</b> This will lead to a lot of missing scripts in your project.", labelStyle);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Fear not. By clicking the button below an upgrade script runs, that should restore all those references. <b>It will directly modify your projects .meta files.</b>", labelStyle);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
|
||||
EditorGUILayout.LabelField("<b>BE WARNED, this might cause damage</b>. You should backup your project before starting this process. This will not work, if you moved the plugin-files from its default directory.", labelStyle);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Perform Upgrade") && EditorUtility.DisplayDialog("Have you made a backup?", "This process may fail or do unexpected things. Don't blame me if it ends up destroying something. Make a backup.", "Yes, I have a backup."))
|
||||
{
|
||||
MissingScriptResolver.UpdateReferences();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("<b>If this is your first time installing this plugin, you don't have to do anything.</b>", labelStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39d4bf2bf4a69e34cb47809c0d366e36
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/PathBerserker2d/Scripts/PathBerserker2d.meta
Normal file
8
Assets/PathBerserker2d/Scripts/PathBerserker2d.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4636456b2610ddb4e8982b105b11e0df
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("PathBerserker2d.Editor")]
|
||||
[assembly: InternalsVisibleTo("PathBerserker2d.Upgrade")]
|
||||
[assembly: AssemblyVersion("2.1")]
|
||||
|
||||
internal static class AssemblyInfo
|
||||
{
|
||||
public static string Version => typeof(AssemblyInfo).Assembly.GetName().Version.ToString();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8fed312cd3761ca4f9b284e6f05e37e8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dbd7032f0753f4943b51d2103bd60b60
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,136 @@
|
||||
using ClipperLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace PathBerserker2d
|
||||
{
|
||||
class ClipperWrapper : IClipper
|
||||
{
|
||||
const int FloatToIntMult = 10000;
|
||||
const float IntToFloatDiv = 10000;
|
||||
|
||||
Clipper clipper = new Clipper();
|
||||
|
||||
public ResultType Compute(Polygon sp, Polygon cp, BoolOpType op, out List<Polygon> result, bool includeOpenPolygons = false)
|
||||
{
|
||||
result = new List<Polygon>();
|
||||
|
||||
if (!sp.BoundsOverlap(cp))
|
||||
{
|
||||
return ResultType.NoOverlap;
|
||||
}
|
||||
|
||||
AddPolygonToClipper(sp, PolyType.ptSubject);
|
||||
AddPolygonToClipper(cp, PolyType.ptClip);
|
||||
|
||||
double prevArea = 0;
|
||||
ClipType clipType;
|
||||
switch (op)
|
||||
{
|
||||
case BoolOpType.INTERSECTION:
|
||||
clipType = ClipType.ctIntersection;
|
||||
break;
|
||||
case BoolOpType.UNION:
|
||||
clipType = ClipType.ctUnion;
|
||||
break;
|
||||
case BoolOpType.DIFFERENCE:
|
||||
clipType = ClipType.ctDifference;
|
||||
prevArea = sp.SignedArea();
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("Unknown op type " + op);
|
||||
}
|
||||
|
||||
PolyTree resultTree = new PolyTree();
|
||||
bool succeeded = clipper.Execute(clipType, resultTree);
|
||||
|
||||
GetResultsFromNode(resultTree, result, includeOpenPolygons);
|
||||
foreach (var poly in result)
|
||||
{
|
||||
poly.EnsureCWOrdering();
|
||||
}
|
||||
|
||||
clipper.Clear();
|
||||
|
||||
bool intersectionHappened = false;
|
||||
double afterArea = 0;
|
||||
switch (op)
|
||||
{
|
||||
case BoolOpType.INTERSECTION:
|
||||
intersectionHappened = result.Count > 0;
|
||||
break;
|
||||
case BoolOpType.UNION:
|
||||
if (result.Count == 1)
|
||||
intersectionHappened = true;
|
||||
break;
|
||||
case BoolOpType.DIFFERENCE:
|
||||
if (result.Count > 1)
|
||||
intersectionHappened = true;
|
||||
else
|
||||
{
|
||||
foreach (var poly in result)
|
||||
afterArea += poly.SignedArea();
|
||||
|
||||
intersectionHappened = !(Math.Abs(afterArea - prevArea) < 0.001);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("Unknown op type " + op);
|
||||
}
|
||||
|
||||
|
||||
return intersectionHappened ? ResultType.Clipped : ResultType.NoOverlap;
|
||||
}
|
||||
|
||||
private void AddPolygonToClipper(Polygon polygon, PolyType polyType)
|
||||
{
|
||||
var points = ConvertContour(polygon.Hull);
|
||||
clipper.AddPath(points, polyType, polygon.Hull.IsClosed);
|
||||
|
||||
foreach (var hole in polygon.Holes)
|
||||
{
|
||||
points = ConvertContour(hole);
|
||||
clipper.AddPath(points, polyType, hole.IsClosed);
|
||||
}
|
||||
}
|
||||
|
||||
private List<IntPoint> ConvertContour(Contour contour)
|
||||
{
|
||||
List<IntPoint> points = new List<IntPoint>(contour.VertexCount);
|
||||
for (int i = 0; i < contour.VertexCount; i++)
|
||||
{
|
||||
points.Add(new IntPoint(contour.Verts[i].x * FloatToIntMult, contour.Verts[i].y * FloatToIntMult));
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
private void GetResultsFromNode(PolyNode node, List<Polygon> polygons, bool includeOpenPolygons)
|
||||
{
|
||||
foreach (var child in node.Childs)
|
||||
{
|
||||
if (child.IsOpen && !includeOpenPolygons)
|
||||
continue;
|
||||
|
||||
Polygon p = new Polygon(ConvertChain(child.m_polygon, !child.IsOpen));
|
||||
polygons.Add(p);
|
||||
foreach (var holeNode in child.Childs)
|
||||
{
|
||||
var hole = ConvertChain(holeNode.m_polygon, !holeNode.IsOpen);
|
||||
p.Holes.Add(hole);
|
||||
|
||||
GetResultsFromNode(holeNode, polygons, includeOpenPolygons);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Contour ConvertChain(List<IntPoint> chain, bool closed)
|
||||
{
|
||||
return new Contour(chain.Select(ip => new Vector2(ip.X / IntToFloatDiv, ip.Y / IntToFloatDiv)), closed);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9276a8b2beda8b54ba7afae4535ba503
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf69683b55c9a474ab9f1585d2c62c61
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e13902fa43e71754f9e04b2f44d5f71b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be8365f59449a0a4aa11aa4ad834006f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace PathBerserker2d
|
||||
{
|
||||
internal class Contour : IEnumerable<Vector2>
|
||||
{
|
||||
public int VertexCount { get { return verts.Count; } }
|
||||
public bool IsEmpty { get { return verts.Count == 0; } }
|
||||
public bool IsClosed { get; private set; }
|
||||
public List<Vector2> Verts => verts;
|
||||
|
||||
private List<Vector2> verts;
|
||||
|
||||
public Contour(List<Vector2> verticies, bool isClosed = true)
|
||||
{
|
||||
this.verts = verticies;
|
||||
IsClosed = isClosed;
|
||||
}
|
||||
|
||||
public Contour(IEnumerable<Vector2> verticies, bool isClosed = true)
|
||||
{
|
||||
this.verts = new List<Vector2>(verticies);
|
||||
IsClosed = isClosed;
|
||||
}
|
||||
|
||||
public Vector2 this[int key]
|
||||
{
|
||||
get { return verts[key]; }
|
||||
}
|
||||
|
||||
public IEnumerator<Vector2> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<Vector2>)verts).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<Vector2>)verts).GetEnumerator();
|
||||
}
|
||||
|
||||
public double SignedArea()
|
||||
{
|
||||
double area = 0;
|
||||
for (int i = 0, j = verts.Count - 1; i < verts.Count; j = i, i++)
|
||||
area += (verts[i].x - verts[j].x) *
|
||||
(verts[i].y + verts[j].y);
|
||||
return area / 2.0;
|
||||
}
|
||||
|
||||
public double Area()
|
||||
{
|
||||
return Math.Abs(SignedArea());
|
||||
}
|
||||
|
||||
public void MakeCW()
|
||||
{
|
||||
if (!IsCW())
|
||||
verts.Reverse();
|
||||
}
|
||||
|
||||
public void Invert()
|
||||
{
|
||||
verts.Reverse();
|
||||
}
|
||||
|
||||
public bool IsCW()
|
||||
{
|
||||
Vector2 lowestPoint = verts[0];
|
||||
int lowestPointIndex = 0;
|
||||
for (int i = 1; i < VertexCount; i++)
|
||||
{
|
||||
if (lowestPoint.y > verts[i].y ||
|
||||
lowestPoint.y == verts[i].y && lowestPoint.x < verts[i].x)
|
||||
{
|
||||
lowestPoint = verts[i];
|
||||
lowestPointIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 prevPoint = lowestPointIndex == 0 ? verts[VertexCount - 1] : verts[lowestPointIndex - 1];
|
||||
Vector2 nextPoint = lowestPointIndex == VertexCount - 1 ? verts[0] : verts[lowestPointIndex + 1];
|
||||
|
||||
return ((lowestPoint.x - prevPoint.x) * (nextPoint.y - prevPoint.y) - (nextPoint.x - prevPoint.x) * (lowestPoint.y - prevPoint.y)) < 0;
|
||||
}
|
||||
|
||||
public bool PointInContour(Vector2 point)
|
||||
{
|
||||
bool c = false;
|
||||
for (int i = 0, j = VertexCount - 1; i < VertexCount; j = i++)
|
||||
{
|
||||
if (((verts[i].y > point.y) != (verts[j].y > point.y)) &&
|
||||
(point.x < (verts[j].x - verts[i].x) * (point.y - verts[i].y) / (verts[j].y - verts[i].y) + verts[i].x))
|
||||
c = !c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public bool Contains(Contour other)
|
||||
{
|
||||
foreach (var v in other)
|
||||
if (!PointInContour(v))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
for (int i = IsClosed ? 0 : 1, j = IsClosed ? VertexCount - 1 : 0; i < VertexCount; j = i, i++)
|
||||
{
|
||||
DebugDrawingExtensions.DrawArrow(verts[i], verts[j]);
|
||||
}
|
||||
}
|
||||
|
||||
public void Simplify(float tolerance)
|
||||
{
|
||||
ExtendedGeometry.MergeCloseVerts(verts, tolerance);
|
||||
this.verts = ExtendedGeometry.SimplifyContour(this.verts, tolerance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dad3920a5830b8e438bc7c5d3c92636d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PathBerserker2d
|
||||
{
|
||||
public enum ResultType { NoOverlap, Clipped };
|
||||
public enum BoolOpType { INTERSECTION, UNION, DIFFERENCE };
|
||||
|
||||
interface IClipper
|
||||
{
|
||||
ResultType Compute(Polygon sp, Polygon cp, BoolOpType op, out List<Polygon> result, bool includeOpenPolygons = false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6f0c0aa6263ff54ca7f6be8694b9fa7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,162 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace PathBerserker2d
|
||||
{
|
||||
internal class Polygon : System.IEquatable<Polygon>, IEnumerable<Contour>
|
||||
{
|
||||
public Contour Hull => hull;
|
||||
public List<Contour> Holes { get; set; }
|
||||
public bool IsEmpty => hull.IsEmpty;
|
||||
public float XMax => boundingRect.xMax;
|
||||
public Rect BoundingRect => boundingRect;
|
||||
|
||||
private Contour hull;
|
||||
private Rect boundingRect;
|
||||
|
||||
public Polygon(Contour hull, List<Contour> holes)
|
||||
{
|
||||
this.hull = hull;
|
||||
this.Holes = holes;
|
||||
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
public Polygon(Contour hull)
|
||||
{
|
||||
this.hull = hull;
|
||||
this.Holes = new List<Contour>(0);
|
||||
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
public Polygon()
|
||||
{
|
||||
this.hull = new Contour(new Vector2[0]);
|
||||
this.Holes = new List<Contour>(0);
|
||||
}
|
||||
|
||||
public bool Equals(Polygon other)
|
||||
{
|
||||
return other == this;
|
||||
}
|
||||
|
||||
public void AddAsChild(Polygon other)
|
||||
{
|
||||
this.Holes.Add(other.hull);
|
||||
this.Holes.AddRange(other.Holes);
|
||||
}
|
||||
|
||||
public int TotalVertCount()
|
||||
{
|
||||
int result = hull.VertexCount;
|
||||
foreach (var path in Holes)
|
||||
{
|
||||
result += path.VertexCount;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool BoundsOverlap(Polygon other)
|
||||
{
|
||||
return boundingRect.Overlaps(other.boundingRect);
|
||||
}
|
||||
|
||||
public bool PointInPolyon(Vector2 point)
|
||||
{
|
||||
return boundingRect.Contains(point) && hull.PointInContour(point);
|
||||
}
|
||||
|
||||
public bool Contains(Polygon other)
|
||||
{
|
||||
foreach (var v in other.hull)
|
||||
{
|
||||
if (!PointInPolyon(v))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Contains(Contour other)
|
||||
{
|
||||
foreach (var v in other)
|
||||
{
|
||||
if (!PointInPolyon(v))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
Gizmos.color = Color.green;
|
||||
hull.Draw();
|
||||
|
||||
Gizmos.color = Color.yellow;
|
||||
foreach (var contour in this.Holes)
|
||||
{
|
||||
contour.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<Contour> GetEnumerator()
|
||||
{
|
||||
yield return hull;
|
||||
foreach (var hole in Holes)
|
||||
yield return hole;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
yield return hull;
|
||||
foreach (var hole in Holes)
|
||||
yield return hole;
|
||||
}
|
||||
|
||||
public void UpdateBounds()
|
||||
{
|
||||
if (hull.VertexCount == 0)
|
||||
return;
|
||||
|
||||
Vector2 min = hull[0];
|
||||
Vector2 max = hull[0];
|
||||
for (int iVert = 1; iVert < hull.VertexCount; iVert++)
|
||||
{
|
||||
min = Vector2.Min(hull[iVert], min);
|
||||
max = Vector2.Max(hull[iVert], max);
|
||||
}
|
||||
// add some fudge
|
||||
Vector2 fudge = new Vector2(0.0001f, 0.0001f);
|
||||
boundingRect = new Rect(min - fudge, max - min + fudge * 2);
|
||||
}
|
||||
|
||||
public void Simplify(float tolerance)
|
||||
{
|
||||
hull.Simplify(tolerance);
|
||||
foreach (var hole in Holes)
|
||||
{
|
||||
hole.Simplify(tolerance);
|
||||
}
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
public double SignedArea()
|
||||
{
|
||||
double area = Hull.SignedArea();
|
||||
foreach (var hole in Holes)
|
||||
area += hole.SignedArea();
|
||||
return area;
|
||||
}
|
||||
|
||||
public void EnsureCWOrdering()
|
||||
{
|
||||
if (Hull.IsCW())
|
||||
return;
|
||||
|
||||
Hull.Invert();
|
||||
foreach (var child in Holes)
|
||||
child.Invert();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24eb0a7c0c44eff48b61ea1d3120dd18
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81309357b39e41942b7819480b292f4a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user