public override void OnInspectorGUI() { GraphUpdateScene script = target as GraphUpdateScene; #if !UNITY_LE_4_3 Undo.RecordObject(script, "modify settings on GraphUpdateObject"); #endif if (script.points == null) { script.points = new Vector3[0]; } if (script.points == null || script.points.Length == 0) { if (script.GetComponent <Collider>() != null) { EditorGUILayout.HelpBox("No points, using collider.bounds", MessageType.Info); } else if (script.GetComponent <Renderer>() != null) { EditorGUILayout.HelpBox("No points, using renderer.bounds", MessageType.Info); } else { EditorGUILayout.HelpBox("No points and no collider or renderer attached, will not affect anything\nPoints can be added using the transform tool and holding shift", MessageType.Warning); } } Vector3[] prePoints = script.points; #if UNITY_4 EditorGUILayout.PropertyField(serializedObject.FindProperty("points"), true); if (GUI.changed) { serializedObject.ApplyModifiedProperties(); } #else DrawDefaultInspector(); #endif #if UNITY_LE_4_3 EditorGUI.indentLevel = 1; #else EditorGUI.indentLevel = 0; #endif script.updatePhysics = EditorGUILayout.Toggle(new GUIContent("Update Physics", "Perform similar calculations on the nodes as during scan.\n" + "Grid Graphs will update the position of the nodes and also check walkability using collision.\nSee online documentation for more info."), script.updatePhysics); if (script.updatePhysics) { EditorGUI.indentLevel++; script.resetPenaltyOnPhysics = EditorGUILayout.Toggle(new GUIContent("Reset Penalty On Physics", "Will reset the penalty to the default value during the update."), script.resetPenaltyOnPhysics); EditorGUI.indentLevel--; } script.updateErosion = EditorGUILayout.Toggle(new GUIContent("Update Erosion", "Recalculate erosion for grid graphs.\nSee online documentation for more info"), script.updateErosion); if (prePoints != script.points) { script.RecalcConvex(); HandleUtility.Repaint(); } bool preConvex = script.convex; script.convex = EditorGUILayout.Toggle(new GUIContent("Convex", "Sets if only the convex hull of the points should be used or the whole polygon"), script.convex); if (script.convex != preConvex) { script.RecalcConvex(); HandleUtility.Repaint(); } script.minBoundsHeight = EditorGUILayout.FloatField(new GUIContent("Min Bounds Height", "Defines a minimum height to be used for the bounds of the GUO.\nUseful if you define points in 2D (which would give height 0)"), script.minBoundsHeight); script.applyOnStart = EditorGUILayout.Toggle("Apply On Start", script.applyOnStart); script.applyOnScan = EditorGUILayout.Toggle("Apply On Scan", script.applyOnScan); script.modifyWalkability = EditorGUILayout.Toggle(new GUIContent("Modify walkability", "If true, walkability of all nodes will be modified"), script.modifyWalkability); if (script.modifyWalkability) { EditorGUI.indentLevel++; script.setWalkability = EditorGUILayout.Toggle(new GUIContent("Walkability", "Nodes' walkability will be set to this value"), script.setWalkability); EditorGUI.indentLevel--; } script.penaltyDelta = EditorGUILayout.IntField(new GUIContent("Penalty Delta", "A penalty will be added to the nodes, usually you need very large values, at least 1000-10000.\n" + "A higher penalty will mean that agents will try to avoid those nodes."), script.penaltyDelta); if (script.penaltyDelta < 0) { EditorGUILayout.HelpBox("Be careful when lowering the penalty. Negative penalties are not supported and will instead underflow and get really high.\n" + "You can set an initial penalty on graphs (see their settings) and then lower them like this to get regions which are easier to traverse.", MessageType.Warning); } script.modifyTag = EditorGUILayout.Toggle(new GUIContent("Modify Tags", "Should the tags of the nodes be modified"), script.modifyTag); if (script.modifyTag) { EditorGUI.indentLevel++; script.setTag = EditorGUILayout.Popup("Set Tag", script.setTag, AstarPath.FindTagNames()); EditorGUI.indentLevel--; } if (GUILayout.Button("Tags can be used to restrict which units can walk on what ground. Click here for more info", "HelpBox")) { Application.OpenURL(AstarPathEditor.GetURL("tags")); } EditorGUILayout.Separator(); bool worldSpace = EditorGUILayout.Toggle(new GUIContent("Use World Space", "Specify coordinates in world space or local space. When using local space you can move the GameObject " + "around and the points will follow.\n" + "Some operations, like calculating the convex hull, and snapping to Y will change axis depending on how the object is rotated if world space is not used." ), script.useWorldSpace); if (worldSpace != script.useWorldSpace) { #if !UNITY_LE_4_3 Undo.RecordObject(script, "switch use-world-space"); #endif script.ToggleUseWorldSpace(); } #if UNITY_4 EditorGUI.BeginChangeCheck(); #endif script.lockToY = EditorGUILayout.Toggle("Lock to Y", script.lockToY); if (script.lockToY) { EditorGUI.indentLevel++; script.lockToYValue = EditorGUILayout.FloatField("Lock to Y value", script.lockToYValue); EditorGUI.indentLevel--; #if !UNITY_LE_4_3 if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(script, "change Y locking"); } #endif script.LockToY(); } EditorGUILayout.Separator(); if (GUILayout.Button("Clear all points")) { #if UNITY_LE_4_3 Undo.RegisterUndo(script, "Removed All Points"); #endif script.points = new Vector3[0]; EditorUtility.SetDirty(target); script.RecalcConvex(); } if (GUI.changed) { #if UNITY_LE_4_3 Undo.RegisterUndo(script, "Modify Settings on GraphUpdateObject"); #endif EditorUtility.SetDirty(target); } }
public override void OnInspectorGUI() { GraphUpdateScene script = target as GraphUpdateScene; if (script.points == null) { script.points = new Vector3[0]; } Vector3[] prePoints = script.points; DrawDefaultInspector(); EditorGUI.indentLevel = 1; if (prePoints != script.points) { script.RecalcConvex(); HandleUtility.Repaint(); } bool preConvex = script.convex; script.convex = EditorGUILayout.Toggle(new GUIContent("Convex", "Sets if only the convex hull of the points should be used or the whole polygon"), script.convex); if (script.convex != preConvex) { script.RecalcConvex(); HandleUtility.Repaint(); } script.applyOnStart = EditorGUILayout.Toggle("Apply On Start", script.applyOnStart); script.applyOnScan = EditorGUILayout.Toggle("Apply On Scan", script.applyOnScan); script.modifyWalkability = EditorGUILayout.Toggle("Modify walkability", script.modifyWalkability); if (script.modifyWalkability) { EditorGUI.indentLevel++; script.setWalkability = EditorGUILayout.Toggle("Walkability", script.setWalkability); EditorGUI.indentLevel--; } script.penalty = EditorGUILayout.IntField("Penalty", script.penalty); #if ConfigureTagsAsMultiple script.modifyTag = EditorGUILayout.Toggle(new GUIContent("Modify Tags", "Should the tags of the nodes be modified"), script.modifyTag); EditorGUILayoutx.TagsMaskField(new GUIContent("Tags Change", "Which tags to change the value of. The values the tags will gain can be set below"), new GUIContent("Tags Set", "What to set the tag to if it is going to be changed"), ref script.tags); #else script.modifyTag = EditorGUILayout.Toggle(new GUIContent("Modify Tags", "Should the tags of the nodes be modified"), script.modifyTag); if (script.modifyTag) { EditorGUI.indentLevel++; script.setTag = EditorGUILayout.Popup("Set Tag", script.setTag, AstarPath.FindTagNames()); EditorGUI.indentLevel--; } #endif //GUI.color = Color.red; if (GUILayout.Button("Tags can be used to restrict which units can walk on what ground. Click here for more info", "HelpBox")) { Application.OpenURL(AstarPathEditor.GetURL("tags")); } //GUI.color = Color.white; if (GUILayout.Button("Clear all points")) { Undo.RegisterUndo(script, "Removed All Points"); script.points = new Vector3[0]; script.RecalcConvex(); } if (GUI.changed) { EditorUtility.SetDirty(target); } }
public override void OnInspectorGUI() { DrawDefaultInspector(); //Do some loading and checking if (!AstarPathEditor.stylesLoaded) { if (!AstarPathEditor.LoadStyles()) { if (AstarPathEditor.upArrow == null) { AstarPathEditor.upArrow = GUI.skin.FindStyle("Button"); AstarPathEditor.downArrow = AstarPathEditor.upArrow; } } else { AstarPathEditor.stylesLoaded = true; } } GUIStyle helpBox = GUI.skin.GetStyle("helpBox"); Seeker script = target as Seeker; if (mods == null) { mods = new List <IPathModifier>(script.GetComponents <MonoModifier>() as IPathModifier[]); } else { mods.Clear(); mods.AddRange(script.GetComponents <MonoModifier>() as IPathModifier[]); } mods.Add(script.startEndModifier as IPathModifier); bool changed = true; while (changed) { changed = false; for (int i = 0; i < mods.Count - 1; i++) { if (mods[i].Priority < mods[i + 1].Priority) { IPathModifier tmp = mods[i + 1]; mods[i + 1] = mods[i]; mods[i] = tmp; changed = true; } } } for (int i = 0; i < mods.Count; i++) { if (mods.Count - i != mods[i].Priority) { mods[i].Priority = mods.Count - i; GUI.changed = true; EditorUtility.SetDirty(target); } } bool modifierErrors = false; for (int i = 1; i < mods.Count; i++) { if (!ModifierConverter.CanConvert(mods[i - 1].output, mods[i].input)) { modifierErrors = true; } } EditorGUI.indentLevel = 0; modifiersOpen = EditorGUILayout.Foldout(modifiersOpen, "Modifiers Priorities" + (modifierErrors ? " - Errors in modifiers!" : ""), EditorStyles.foldout); EditorGUI.indentLevel = 1; if (modifiersOpen) { EditorGUI.indentLevel += 2; //GUILayout.BeginHorizontal (); //GUILayout.Space (28); if (GUILayout.Button("Modifiers attached to this gameObject are listed here.\nModifiers with a higher priority (higher up in the list) will be executed first.\nClick here for more info", helpBox)) { Application.OpenURL(AstarPathEditor.ModifierHelpURL); } //GUILayout.EndHorizontal (); for (int i = 0; i < mods.Count; i++) { //EditorGUILayout.LabelField (mods[i].GetType ().ToString (),mods[i].Priority.ToString ()); GUILayout.BeginVertical(GUI.skin.box); if (i > 0) { if (!ModifierConverter.CanConvert(mods[i - 1].output, mods[i].input)) { //GUILayout.BeginHorizontal (); //GUILayout.Space (28); GUIUtilityx.SetColor(new Color(0.8F, 0, 0)); GUILayout.Label("Cannot convert " + mods[i - 1].GetType().Name + "'s output to " + mods[i].GetType().Name + "'s input\nRearranging the modifiers might help", EditorStyles.whiteMiniLabel); GUIUtilityx.ResetColor(); //GUILayout.EndHorizontal (); } } GUILayout.Label("Input: " + mods[i].input, EditorStyles.wordWrappedMiniLabel); int newPrio = EditorGUILayoutx.UpDownArrows(new GUIContent(ObjectNames.NicifyVariableName(mods[i].GetType().ToString())), mods[i].Priority, EditorStyles.label, AstarPathEditor.upArrow, AstarPathEditor.downArrow); GUILayout.Label("Output: " + mods[i].output, EditorStyles.wordWrappedMiniLabel); GUILayout.EndVertical(); int diff = newPrio - mods[i].Priority; if (i > 0 && diff > 0) { mods[i - 1].Priority = mods[i].Priority; } else if (i < mods.Count - 1 && diff < 0) { mods[i + 1].Priority = mods[i].Priority; } mods[i].Priority = newPrio; } EditorGUI.indentLevel -= 2; } }
public override void OnInspectorGUI() { DrawDefaultInspector(); Seeker script = target as Seeker; //EditorGUILayoutx.SetTagField (new GUIContent ("Valid Tags","Sets which tags are traversable. Tags can be used to restrict which units can traverse which ground"),ref script.traversableTags); EditorGUI.indentLevel = 0; tagPenaltiesOpen = EditorGUILayout.Foldout(tagPenaltiesOpen, new GUIContent("Tag Penalties", "Penalties for each tag")); if (tagPenaltiesOpen) { EditorGUI.indentLevel = 2; string[] tagNames = AstarPath.FindTagNames(); for (int i = 0; i < script.tagPenalties.Length; i++) { int tmp = EditorGUILayout.IntField((i < tagNames.Length ? tagNames[i] : "Tag " + i), (int)script.tagPenalties[i]); if (tmp < 0) { tmp = 0; } script.tagPenalties[i] = tmp; } if (GUILayout.Button("Edit Tags...")) { AstarPathEditor.EditTags(); } } EditorGUI.indentLevel = 1; //Do some loading and checking if (!AstarPathEditor.stylesLoaded) { if (!AstarPathEditor.LoadStyles()) { if (AstarPathEditor.upArrow == null) { AstarPathEditor.upArrow = GUI.skin.FindStyle("Button"); AstarPathEditor.downArrow = AstarPathEditor.upArrow; } } else { AstarPathEditor.stylesLoaded = true; } } GUIStyle helpBox = GUI.skin.GetStyle("helpBox"); if (mods == null) { mods = new List <IPathModifier>(script.GetComponents <MonoModifier>() as IPathModifier[]); } else { mods.Clear(); mods.AddRange(script.GetComponents <MonoModifier>() as IPathModifier[]); } mods.Add(script.startEndModifier as IPathModifier); bool changed = true; while (changed) { changed = false; for (int i = 0; i < mods.Count - 1; i++) { if (mods[i].Priority < mods[i + 1].Priority) { IPathModifier tmp = mods[i + 1]; mods[i + 1] = mods[i]; mods[i] = tmp; changed = true; } } } for (int i = 0; i < mods.Count; i++) { if (mods.Count - i != mods[i].Priority) { mods[i].Priority = mods.Count - i; GUI.changed = true; EditorUtility.SetDirty(target); } } bool modifierErrors = false; IPathModifier prevMod = mods[0]; //Loops through all modifiers and checks if there are any errors in converting output between modifiers for (int i = 1; i < mods.Count; i++) { MonoModifier monoMod = mods[i] as MonoModifier; if ((prevMod as MonoModifier) != null && !(prevMod as MonoModifier).enabled) { if (monoMod == null || monoMod.enabled) { prevMod = mods[i]; } continue; } if ((monoMod == null || monoMod.enabled) && prevMod != mods[i] && !ModifierConverter.CanConvert(prevMod.output, mods[i].input)) { modifierErrors = true; } if (monoMod == null || monoMod.enabled) { prevMod = mods[i]; } } EditorGUI.indentLevel = 0; modifiersOpen = EditorGUILayout.Foldout(modifiersOpen, "Modifiers Priorities" + (modifierErrors ? " - Errors in modifiers!" : ""), EditorStyles.foldout); EditorGUI.indentLevel = 1; if (modifiersOpen) { EditorGUI.indentLevel += 2; //GUILayout.BeginHorizontal (); //GUILayout.Space (28); if (GUILayout.Button("Modifiers attached to this gameObject are listed here.\nModifiers with a higher priority (higher up in the list) will be executed first.\nClick here for more info", helpBox)) { Application.OpenURL(AstarPathEditor.GetURL("modifiers")); } //GUILayout.EndHorizontal (); prevMod = mods[0]; for (int i = 0; i < mods.Count; i++) { //EditorGUILayout.LabelField (mods[i].GetType ().ToString (),mods[i].Priority.ToString ()); MonoModifier monoMod = mods[i] as MonoModifier; Color prevCol = GUI.color; if (monoMod != null && !monoMod.enabled) { GUI.color *= new Color(1, 1, 1, 0.5F); } GUILayout.BeginVertical(GUI.skin.box); if (i > 0) { if ((prevMod as MonoModifier) != null && !(prevMod as MonoModifier).enabled) { prevMod = mods[i]; } else { if ((monoMod == null || monoMod.enabled) && !ModifierConverter.CanConvert(prevMod.output, mods[i].input)) { //GUILayout.BeginHorizontal (); //GUILayout.Space (28); GUIUtilityx.SetColor(new Color(0.8F, 0, 0)); GUILayout.Label("Cannot convert " + prevMod.GetType().Name + "'s output to " + mods[i].GetType().Name + "'s input\nRearranging the modifiers might help", EditorStyles.whiteMiniLabel); GUIUtilityx.ResetColor(); //GUILayout.EndHorizontal (); } if (monoMod == null || monoMod.enabled) { prevMod = mods[i]; } } } GUILayout.Label("Input: " + mods[i].input, EditorStyles.wordWrappedMiniLabel); int newPrio = EditorGUILayoutx.UpDownArrows(new GUIContent(ObjectNames.NicifyVariableName(mods[i].GetType().ToString())), mods[i].Priority, EditorStyles.label, AstarPathEditor.upArrow, AstarPathEditor.downArrow); GUILayout.Label("Output: " + mods[i].output, EditorStyles.wordWrappedMiniLabel); GUILayout.EndVertical(); int diff = newPrio - mods[i].Priority; if (i > 0 && diff > 0) { mods[i - 1].Priority = mods[i].Priority; } else if (i < mods.Count - 1 && diff < 0) { mods[i + 1].Priority = mods[i].Priority; } mods[i].Priority = newPrio; GUI.color = prevCol; } EditorGUI.indentLevel -= 2; } }
public override void OnInspectorGUI() { DrawDefaultInspector(); var script = target as Seeker; Undo.RecordObject(script, "modify settings on Seeker"); // Show a dropdown selector for the tags that this seeker can traverse // A callback is necessary because Unity's GenericMenu uses callbacks EditorGUILayoutx.TagMaskField(new GUIContent("Valid Tags"), script.traversableTags, result => script.traversableTags = result); EditorGUI.indentLevel = 0; tagPenaltiesOpen = EditorGUILayout.Foldout(tagPenaltiesOpen, new GUIContent("Tag Penalties", "Penalties for each tag")); if (tagPenaltiesOpen) { EditorGUI.indentLevel = 2; string[] tagNames = AstarPath.FindTagNames(); for (int i = 0; i < script.tagPenalties.Length; i++) { int tmp = EditorGUILayout.IntField((i < tagNames.Length ? tagNames[i] : "Tag " + i), (int)script.tagPenalties[i]); if (tmp < 0) { tmp = 0; } // If the new value is different than the old one // Update the value and mark the script as dirty if (script.tagPenalties[i] != tmp) { script.tagPenalties[i] = tmp; EditorUtility.SetDirty(target); } } if (GUILayout.Button("Edit Tag Names...")) { AstarPathEditor.EditTags(); } } EditorGUI.indentLevel = 1; //Do some loading and checking if (!AstarPathEditor.stylesLoaded) { AstarPathEditor.LoadStyles(); } GUIStyle helpBox = GUI.skin.GetStyle("helpBox"); if (mods == null) { mods = new List <IPathModifier>(script.GetComponents <MonoModifier>() as IPathModifier[]); } else { mods.Clear(); mods.AddRange(script.GetComponents <MonoModifier>() as IPathModifier[]); } mods.Add(script.startEndModifier); bool changed = true; while (changed) { changed = false; for (int i = 0; i < mods.Count - 1; i++) { if (mods[i].Priority < mods[i + 1].Priority) { IPathModifier tmp = mods[i + 1]; mods[i + 1] = mods[i]; mods[i] = tmp; changed = true; } } } for (int i = 0; i < mods.Count; i++) { if (mods.Count - i != mods[i].Priority) { mods[i].Priority = mods.Count - i; GUI.changed = true; EditorUtility.SetDirty(target); SetModifierDirty(mods[i]); } } bool modifierErrors = false; IPathModifier prevMod = mods[0]; //Loops through all modifiers and checks if there are any errors in converting output between modifiers for (int i = 1; i < mods.Count; i++) { var monoMod = mods[i] as MonoModifier; if ((prevMod as MonoModifier) != null && !(prevMod as MonoModifier).enabled) { if (monoMod == null || monoMod.enabled) { prevMod = mods[i]; } continue; } if ((monoMod == null || monoMod.enabled) && prevMod != mods[i] && !ModifierConverter.CanConvert(prevMod.output, mods[i].input)) { modifierErrors = true; } if (monoMod == null || monoMod.enabled) { prevMod = mods[i]; } } EditorGUI.indentLevel = 0; modifiersOpen = EditorGUILayout.Foldout(modifiersOpen, "Modifiers Priorities" + (modifierErrors ? " - Errors in modifiers!" : "")); if (modifiersOpen) { if (GUILayout.Button("Modifiers attached to this gameObject are listed here.\nModifiers with a higher priority (higher up in the list) will be executed first.\nClick here for more info", helpBox)) { Application.OpenURL(AstarUpdateChecker.GetURL("modifiers")); } EditorGUILayout.HelpBox("Original or All can be converted to anything\n" + "NodePath can be converted to VectorPath\n" + "VectorPath can only be used as VectorPath\n" + "Vector takes both VectorPath and StrictVectorPath\n" + "Strict... can be converted to the non-strict variant", MessageType.None); prevMod = mods[0]; for (int i = 0; i < mods.Count; i++) { var monoMod = mods[i] as MonoModifier; Color prevCol = GUI.color; if (monoMod != null && !monoMod.enabled) { GUI.color *= new Color(1, 1, 1, 0.5F); } GUILayout.BeginVertical(GUI.skin.box); if (i > 0) { if ((prevMod as MonoModifier) != null && !(prevMod as MonoModifier).enabled) { prevMod = mods[i]; } else { if ((monoMod == null || monoMod.enabled) && !ModifierConverter.CanConvert(prevMod.output, mods[i].input)) { //GUILayout.BeginHorizontal (); //GUILayout.Space (28); GUIUtilityx.SetColor(new Color(0.8F, 0, 0)); GUILayout.Label("Cannot convert " + prevMod.GetType().Name + "'s output to " + mods[i].GetType().Name + "'s input\nRearranging the modifiers might help", EditorStyles.whiteMiniLabel); GUIUtilityx.ResetColor(); //GUILayout.EndHorizontal (); } if (monoMod == null || monoMod.enabled) { prevMod = mods[i]; } } } GUILayout.Label("Input: " + mods[i].input, EditorStyles.wordWrappedMiniLabel); int newPrio = EditorGUILayoutx.UpDownArrows(new GUIContent(ObjectNames.NicifyVariableName(mods[i].GetType().ToString())), mods[i].Priority, EditorStyles.label, AstarPathEditor.upArrow, AstarPathEditor.downArrow); GUILayout.Label("Output: " + mods[i].output, EditorStyles.wordWrappedMiniLabel); GUILayout.EndVertical(); int diff = newPrio - mods[i].Priority; if (i > 0 && diff > 0) { mods[i - 1].Priority = mods[i].Priority; SetModifierDirty(mods[i - 1]); } else if (i < mods.Count - 1 && diff < 0) { mods[i + 1].Priority = mods[i].Priority; SetModifierDirty(mods[i + 1]); } if (mods[i].Priority != newPrio) { mods[i].Priority = newPrio; SetModifierDirty(mods[i]); } GUI.color = prevCol; } EditorGUI.indentLevel -= 2; } if (GUI.changed) { EditorUtility.SetDirty(target); } }
public static void GetRecastData(Pathfinding.RecastGraph target, out int[] triangleArray, out Vector3[] vertexArray) { triangleArray = null; vertexArray = null; if (target == null) { return; } Pathfinding.RecastGraph.NavmeshTile[] tiles = target.GetTiles(); if (tiles == null) { if (EditorUtility.DisplayDialog("Scan graph before exporting?", "The graph does not contain any mesh data. Do you want to scan it?", "Ok", "Cancel")) { AstarPathEditor.MenuScan(); tiles = target.GetTiles(); if (tiles == null) { return; } } else { return; } } //string path = EditorUtility.SaveFilePanel("Export .obj", "", "navmesh.obj", "obj"); //if (path == "") return; //Generate .obj /*var sb = new System.Text.StringBuilder(); * * string name = System.IO.Path.GetFileNameWithoutExtension(path); * * sb.Append("g ").Append(name).AppendLine();*/ List <Vector3> vertList = new List <Vector3>(); List <int> triangleList = new List <int>(); //Vertices start from 1 int vCount = 0; //Define single texture coordinate to zero //sb.Append("vt 0 0\n"); for (int t = 0; t < tiles.Length; t++) { Pathfinding.RecastGraph.NavmeshTile tile = tiles[t]; if (tile == null) { continue; } Pathfinding.Int3[] vertices = tile.verts; //Write vertices for (int i = 0; i < vertices.Length; i++) { var v = (Vector3)vertices[i]; //sb.Append(string.Format("v {0} {1} {2}\n", -v.x, v.y, v.z)); vertList.Add(v); } //Write triangles Pathfinding.TriangleMeshNode[] nodes = tile.nodes; for (int i = 0; i < nodes.Length; i++) { Pathfinding.TriangleMeshNode node = nodes[i]; if (node == null) { Debug.LogError("Node was null or no TriangleMeshNode. Critical error. Graph type " + target.GetType().Name); return; } if (node.GetVertexArrayIndex(0) < 0 || node.GetVertexArrayIndex(0) >= vertices.Length) { throw new System.Exception("ERR"); } //sb.Append(string.Format("f {0}/1 {1}/1 {2}/1\n", (node.GetVertexArrayIndex(0) + vCount), (node.GetVertexArrayIndex(1) + vCount), (node.GetVertexArrayIndex(2) + vCount))); triangleList.Add(node.GetVertexArrayIndex(0) + vCount); triangleList.Add(node.GetVertexArrayIndex(1) + vCount); triangleList.Add(node.GetVertexArrayIndex(2) + vCount); } vCount += vertices.Length; } /*string obj = sb.ToString(); * * using (var sw = new System.IO.StreamWriter(path)) * { * sw.Write(obj); * }*/ triangleArray = triangleList.ToArray(); vertexArray = vertList.ToArray(); }
public override void OnInspectorGUI(NavGraph target) { RecastGraph graph = target as RecastGraph; bool preEnabled = GUI.enabled; //if (graph.forceBounds) { graph.useCRecast = GUILayout.Toolbar(graph.useCRecast ?1:0, new GUIContent[2] { new GUIContent("C# Recast", "I have translated a portion of Recast to C#, this can be used in a webplayer but is more limited than the C++ version"), new GUIContent("C++ Recast", "Use the original C++ version of Recast, faster scanning times and has more features than the C# version, but it can only be used in the editor or on standalone applications (note that you can still scan the graph in the editor and then cache the startup if you want to build for a webplayer)" + "\nTake a look in the docs on RecastGraph.useCRecast for more information on the special considerations when using this mode") }) == 1; if (graph.useCRecast) { BuildTarget bt = EditorUserBuildSettings.activeBuildTarget; if (bt != BuildTarget.StandaloneOSXIntel) { if (GUILayout.Button("Note that the C++ version of Recast does not work in your selected build target (" + bt + ")\n" + "Change build target to standalone (osx) if you want to be able to use C++\n" + "Click here for more info", AstarPathEditor.helpBox)) { Application.OpenURL(AstarPathEditor.GetURL("cRecastHelp")); } } else { if (GUILayout.Button("Note the special considerations when using C++ Recast\nClick here for more info", AstarPathEditor.helpBox)) { Application.OpenURL(AstarPathEditor.GetURL("cRecastHelp")); } } if (Application.platform == RuntimePlatform.WindowsEditor) { GUILayout.Label("C++ Recast can currently not be used on Windows", AstarPathEditor.helpBox); } } System.Int64 estWidth = Mathf.RoundToInt(Mathf.Ceil(graph.forcedBoundsSize.x / graph.cellSize)); System.Int64 estDepth = Mathf.RoundToInt(Mathf.Ceil(graph.forcedBoundsSize.z / graph.cellSize)); if (estWidth * estDepth >= 1024 * 1024 || estDepth >= 1024 * 1024 || estWidth >= 1024 * 1024) { GUIStyle helpBox = GUI.skin.FindStyle("HelpBox"); if (helpBox == null) { helpBox = GUI.skin.FindStyle("Box"); } Color preColor = GUI.color; if (estWidth * estDepth >= 2048 * 2048 || estDepth >= 2048 * 2048 || estWidth >= 2048 * 2048) { GUI.color = Color.red; } else { GUI.color = Color.yellow; } GUILayout.Label("Warning : Might take some time to calculate", helpBox); GUI.color = preColor; } GUI.enabled = false; EditorGUILayout.LabelField("Width (samples)", estWidth.ToString()); EditorGUILayout.LabelField("Depth (samples)", estDepth.ToString()); /*} else { * GUI.enabled = false; * EditorGUILayout.LabelField ("Width (samples)","undetermined"); * EditorGUILayout.LabelField ("Depth (samples)","undetermined"); * }*/ GUI.enabled = preEnabled; graph.cellSize = EditorGUILayout.FloatField(new GUIContent("Cell Size", "Size of one voxel in world units"), graph.cellSize); if (graph.cellSize < 0.001F) { graph.cellSize = 0.001F; } graph.cellHeight = EditorGUILayout.FloatField(new GUIContent("Cell Height", "Height of one voxel in world units"), graph.cellHeight); if (graph.cellHeight < 0.001F) { graph.cellHeight = 0.001F; } graph.walkableHeight = EditorGUILayout.FloatField(new GUIContent("Walkable Height", "Minimum distance to the roof for an area to be walkable"), graph.walkableHeight); graph.walkableClimb = EditorGUILayout.FloatField(new GUIContent("Walkable Climb", "How high can the character climb"), graph.walkableClimb); graph.characterRadius = EditorGUILayout.FloatField(new GUIContent("Character Radius", "Radius of the character, it's good to add some margin though"), graph.characterRadius); if (graph.useCRecast) { graph.regionMinSize = EditorGUILayout.IntField(new GUIContent("Min Region Size", "The lowest number of voxles in one area for it not to be deleted"), graph.regionMinSize); } graph.maxSlope = EditorGUILayout.Slider(new GUIContent("Max Slope", "Approximate maximum slope"), graph.maxSlope, 0F, 90F); graph.maxEdgeLength = EditorGUILayout.FloatField(new GUIContent("Max Edge Length", "Maximum length of one edge in the completed navmesh before it is split. A lower value can often yield better quality graphs"), graph.maxEdgeLength); graph.maxEdgeLength = graph.maxEdgeLength < graph.cellSize ? graph.cellSize : graph.maxEdgeLength; /*if (!graph.useCRecast) { * graph.erosionRadius = EditorGUILayout.IntSlider ("Erosion radius",graph.erosionRadius,0,256); * }*/ graph.contourMaxError = EditorGUILayout.FloatField(new GUIContent("Max edge error", "Amount of simplification to apply to edges"), graph.contourMaxError); graph.rasterizeTerrain = EditorGUILayout.Toggle(new GUIContent("Rasterize Terrain", "Should a rasterized terrain be included"), graph.rasterizeTerrain); if (graph.rasterizeTerrain) { EditorGUI.indentLevel++; graph.rasterizeTrees = EditorGUILayout.Toggle(new GUIContent("Rasterize Trees", "Rasterize tree colliders on terrains. " + "If the tree prefab has a collider, that collider will be rasterized. " + "Otherwise a simple box collider will be used and the script will " + "try to adjust it to the tree's scale, it might not do a very good job though so " + "an attached collider is preferable."), graph.rasterizeTrees); if (graph.rasterizeTrees) { EditorGUI.indentLevel++; graph.colliderRasterizeDetail = EditorGUILayout.FloatField(new GUIContent("Collider Detail", "Controls the detail of the generated collider meshes. Increasing does not necessarily yield better navmeshes, but lowering will speed up scan"), graph.colliderRasterizeDetail); EditorGUI.indentLevel--; } graph.terrainSampleSize = EditorGUILayout.IntField(new GUIContent("Terrain Sample Size", "Size of terrain samples. A lower value is better, but slower"), graph.terrainSampleSize); graph.terrainSampleSize = graph.terrainSampleSize < 1 ? 1 : graph.terrainSampleSize; //Clamp to at least 1 EditorGUI.indentLevel--; } graph.rasterizeMeshes = EditorGUILayout.Toggle(new GUIContent("Rasterize Meshes", "Should meshes be rasterized and used for building the navmesh"), graph.rasterizeMeshes); graph.rasterizeColliders = EditorGUILayout.Toggle(new GUIContent("Rasterize Colliders", "Should colliders be rasterized and used for building the navmesh"), graph.rasterizeColliders); if (graph.rasterizeColliders) { EditorGUI.indentLevel++; graph.colliderRasterizeDetail = EditorGUILayout.FloatField(new GUIContent("Collider Detail", "Controls the detail of the generated collider meshes. Increasing does not necessarily yield better navmeshes, but lowering will speed up scan"), graph.colliderRasterizeDetail); EditorGUI.indentLevel--; } graph.mask = EditorGUILayoutx.LayerMaskField("Layer Mask", graph.mask); graph.includeOutOfBounds = EditorGUILayout.Toggle(new GUIContent("Include out of bounds", "Should voxels out of bounds, on the Y axis below the graph, be included or not"), graph.includeOutOfBounds); Separator(); graph.forcedBoundsCenter = EditorGUILayout.Vector3Field("Center", graph.forcedBoundsCenter); graph.forcedBoundsSize = EditorGUILayout.Vector3Field("Size", graph.forcedBoundsSize); if (GUILayout.Button(new GUIContent("Snap bounds to scene", "Will snap the bounds of the graph to exactly contain all active meshes in the scene"))) { graph.SnapForceBoundsToScene(); GUI.changed = true; } Separator(); tagMaskFoldout = EditorGUILayoutx.UnityTagMaskList(new GUIContent("Tag Mask"), tagMaskFoldout, graph.tagMask); Separator(); graph.showMeshOutline = EditorGUILayout.Toggle(new GUIContent("Show mesh outline", "Toggles gizmos for drawing an outline of the mesh"), graph.showMeshOutline); graph.accurateNearestNode = EditorGUILayout.Toggle(new GUIContent("Accurate Nearest Node Queries", "More accurate nearest node queries. See docs for more info"), graph.accurateNearestNode); if (GUILayout.Button("Export to file")) { ExportToFile(graph); } /*graph.replaceMesh = (Mesh)ObjectField (new GUIContent ("Replacement Mesh","If you make edits to the mesh manually, you can drop the new mesh file here to import it"), graph.replaceMesh,typeof(Mesh),false); * * if (graph.replaceMesh != null) { * HelpBox ("Note: Graph will be replaced by the mesh"); * }*/ //graph.mask = 1 << EditorGUILayout.LayerField ("Mask",(int)Mathf.Log (graph.mask,2)); }
public override void OnInspectorGUI() { GraphUpdateScene script = target as GraphUpdateScene; if (script.points == null) { script.points = new Vector3[0]; } Vector3[] prePoints = script.points; DrawDefaultInspector(); EditorGUI.indentLevel = 1; if (prePoints != script.points) { script.RecalcConvex(); HandleUtility.Repaint(); } bool preConvex = script.convex; script.convex = EditorGUILayout.Toggle(new GUIContent("Convex", "Sets if only the convex hull of the points should be used or the whole polygon"), script.convex); if (script.convex != preConvex) { script.RecalcConvex(); HandleUtility.Repaint(); } script.minBoundsHeight = EditorGUILayout.FloatField(new GUIContent("Min Bounds Height", "Defines a minimum height to be used for the bounds of the GUO.\nUseful if you define points in 2D (which would give height 0)"), script.minBoundsHeight); script.applyOnStart = EditorGUILayout.Toggle("Apply On Start", script.applyOnStart); script.applyOnScan = EditorGUILayout.Toggle("Apply On Scan", script.applyOnScan); script.modifyWalkability = EditorGUILayout.Toggle("Modify walkability", script.modifyWalkability); if (script.modifyWalkability) { EditorGUI.indentLevel++; script.setWalkability = EditorGUILayout.Toggle("Walkability", script.setWalkability); EditorGUI.indentLevel--; } script.penaltyDelta = EditorGUILayout.IntField("Penalty Delta", script.penaltyDelta); if (script.penaltyDelta < 0) { GUILayout.Label("Be careful when lowering the penalty. Negative penalties are not supported and will instead underflow and get really high.", "HelpBox"); } bool worldSpace = EditorGUILayout.Toggle(new GUIContent("Use World Space", "Specify coordinates in world space or local space. When using local space you can move the GameObject around and the points will follow" ), script.useWorldSpace); if (worldSpace != script.useWorldSpace) { script.ToggleUseWorldSpace(); } script.modifyTag = EditorGUILayout.Toggle(new GUIContent("Modify Tags", "Should the tags of the nodes be modified"), script.modifyTag); if (script.modifyTag) { EditorGUI.indentLevel++; script.setTag = EditorGUILayout.Popup("Set Tag", script.setTag, AstarPath.FindTagNames()); EditorGUI.indentLevel--; } //GUI.color = Color.red; if (GUILayout.Button("Tags can be used to restrict which units can walk on what ground. Click here for more info", "HelpBox")) { Application.OpenURL(AstarPathEditor.GetURL("tags")); } //GUI.color = Color.white; EditorGUILayout.Separator(); //GUILayout.Space (0); //GUI.Toggle (r,script.lockToY,"","Button"); script.lockToY = EditorGUILayout.Toggle("Lock to Y", script.lockToY); if (script.lockToY) { EditorGUI.indentLevel++; script.lockToYValue = EditorGUILayout.FloatField("Lock to Y value", script.lockToYValue); EditorGUI.indentLevel--; script.LockToY(); } EditorGUILayout.Separator(); if (GUI.changed) { Undo.RegisterUndo(script, "Modify Settings on GraphUpdateObject"); EditorUtility.SetDirty(target); } if (GUILayout.Button("Clear all points")) { Undo.RegisterUndo(script, "Removed All Points"); script.points = new Vector3[0]; script.RecalcConvex(); } }