chore: initial commit
This commit is contained in:
@@ -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:
|
||||
Reference in New Issue
Block a user