chore: initial commit

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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