diff --git a/Source/SharpNav.Examples/ExampleWindow.cs b/Source/SharpNav.Examples/ExampleWindow.cs index 40dc3890..303d3342 100644 --- a/Source/SharpNav.Examples/ExampleWindow.cs +++ b/Source/SharpNav.Examples/ExampleWindow.cs @@ -609,7 +609,8 @@ private void GeneratePathfinding() List visited = new List(16); NavPoint startPoint = new NavPoint(path[0], iterPos); navMeshQuery.MoveAlongSurface(ref startPoint, ref moveTgt, out result, visited); - npolys = FixupCorridor(path, MAX_POLYS, visited); + path.FixupCorridor(visited); + npolys = path.Count; float h = 0; navMeshQuery.GetPolyHeight(path[0], result, ref h); result.Y = h; @@ -649,39 +650,39 @@ private void VMad(ref SVector3 dest, SVector3 v1, SVector3 v2, float s) dest.Z = v1.Z + v2.Z * s; } - private bool GetSteerTarget(NavMeshQuery navMeshQuery, SVector3 startPos, SVector3 endPos, float minTargetDist, SharpNav.Pathfinding.Path path, - ref SVector3 steerPos, ref StraightPathFlags steerPosFlag, ref NavPolyId steerPosRef) - { - StraightPath steerPath = new StraightPath(); - navMeshQuery.FindStraightPath(startPos, endPos, path, steerPath, 0); - int nsteerPath = steerPath.Count; - if (nsteerPath == 0) - return false; - - //find vertex far enough to steer to - int ns = 0; - while (ns < nsteerPath) - { - if ((steerPath[ns].Flags & StraightPathFlags.OffMeshConnection) != 0 || - !InRange(steerPath[ns].Point.Position, startPos, minTargetDist, 1000.0f)) - break; - - ns++; - } - - //failed to find good point to steer to - if (ns >= nsteerPath) - return false; - - steerPos = steerPath[ns].Point.Position; - steerPos.Y = startPos.Y; - steerPosFlag = steerPath[ns].Flags; - if (steerPosFlag == StraightPathFlags.None && ns == (nsteerPath - 1)) - steerPosFlag = StraightPathFlags.End; // otherwise seeks path infinitely!!! - steerPosRef = steerPath[ns].Point.Polygon; - - return true; - } + private bool GetSteerTarget(NavMeshQuery navMeshQuery, SVector3 startPos, SVector3 endPos, float minTargetDist, SharpNav.Pathfinding.Path path, + ref SVector3 steerPos, ref StraightPathFlags steerPosFlag, ref NavPolyId steerPosRef) + { + StraightPath steerPath = new StraightPath(); + navMeshQuery.FindStraightPath(startPos, endPos, path, steerPath, 0); + int nsteerPath = steerPath.Count; + if (nsteerPath == 0) + return false; + + //find vertex far enough to steer to + int ns = 0; + while (ns < nsteerPath) + { + if ((steerPath[ns].Flags & StraightPathFlags.OffMeshConnection) != 0 || + !InRange(steerPath[ns].Point.Position, startPos, minTargetDist, 1000.0f)) + break; + + ns++; + } + + //failed to find good point to steer to + if (ns >= nsteerPath) + return false; + + steerPos = steerPath[ns].Point.Position; + steerPos.Y = startPos.Y; + steerPosFlag = steerPath[ns].Flags; + if (steerPosFlag == StraightPathFlags.None && ns == (nsteerPath - 1)) + steerPosFlag = StraightPathFlags.End; // otherwise seeks path infinitely!!! + steerPosRef = steerPath[ns].Point.Polygon; + + return true; + } private bool InRange(SVector3 v1, SVector3 v2, float r, float h) { @@ -691,50 +692,6 @@ private bool InRange(SVector3 v1, SVector3 v2, float r, float h) return (dx * dx + dz * dz) < (r * r) && Math.Abs(dy) < h; } - private int FixupCorridor(Path path, int maxPath, List visited) - { - int furthestPath = -1; - int furthestVisited = -1; - - //find furhtest common polygon - for (int i = path.Count - 1; i >= 0; i--) - { - bool found = false; - for (int j = visited.Count - 1; j >= 0; j--) - { - if (path[i] == visited[j]) - { - furthestPath = i; - furthestVisited = j; - found = true; - } - } - - if (found) - break; - } - - //if no intersection found, return current path - if (furthestPath == -1 || furthestVisited == -1) - return path.Count; - - //concatenate paths - //adjust beginning of the buffer to include the visited - int req = visited.Count - furthestVisited; - int orig = Math.Min(furthestPath + 1, path.Count); - int size = Math.Max(0, path.Count - orig); - if (req + size > maxPath) - size = maxPath - req; - for (int i = 0; i < size; i++) - path[req + i] = path[orig + i]; - - //store visited - for (int i = 0; i < req; i++) - path[i] = visited[(visited.Count - 1) - i]; - - return req + size; - } - private void GenerateCrowd() { if (!hasGenerated || navMeshQuery == null) diff --git a/Source/SharpNav.Examples/PlyModel.cs b/Source/SharpNav.Examples/PlyModel.cs deleted file mode 100644 index a3cb814f..00000000 --- a/Source/SharpNav.Examples/PlyModel.cs +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright (c) 2013, 2015 Robert Rouhani and other contributors (see CONTRIBUTORS file). -// Licensed under the MIT License - https://raw.github.com/Robmaister/SharpNav/master/LICENSE - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using SharpNav; -using SharpNav.Geometry; - -#if OPENTK -using OpenTK; -#endif - -//Doesn't compile if in an unsupported configuration -#if STANDALONE || OPENTK - -namespace SharpNav.Examples -{ - public class PlyModel - { - string[] type_name = new string[] - { - "invalid", - "int8", - "int16", - "int32", - "uint8", - "uint16", - "uint32", - "float32", - "float64", - "list", - "char", - "uchar", - }; - string[] old_type_name = new string[] - { - "invalid", - "char", "short", "int", "uchar", "ushort", "uint", "float", "double", - }; - - int[] ply_type_size = new int[] - { - 0, 1, 2, 4, 1, 2, 4, 4, 8 - }; - -// string type_vertex = "int"; -// string type_face = "int"; -// string type_size_face = "int"; - private static readonly char[] lineSplitChars = { ' ' }; - - private List tris; -// private List norms; -// -// private Vector3 bboxOffset; - - public PlyModel (string path) - { - tris = new List(); - //norms = new List(); - List tempVerts = new List(); - //List tempNorms = new List(); - - using (StreamReader reader = new StreamReader (path)) - { - string file = reader.ReadToEnd(); - int sizeofFaces = 0; - int sizeofVerts = 0; - foreach (string l in file.Split('\n')) - { - string tl = l; - tl = tl.Trim (); - string[] line = tl.Split(lineSplitChars, StringSplitOptions.RemoveEmptyEntries); - Vector3 v; - float x; //X-coordinate - float s; - if (line [0] == "element") { - switch (line [1]) { - case "vertex": //when the word after element is vertex - if (line.Length < 3) - continue; - if (!int.TryParse (line [2], out sizeofVerts)) - continue; - break; - case "face": //when the word after element is face - if (line.Length < 3) - continue; - if (!int.TryParse (line [2], out sizeofFaces)) - continue; - break; - default: - Console.WriteLine ("Not a valid word"); - break; - } - continue; - } -// else if (line [0] == "property") -// { -// switch (line [1]) -// { -// case type_name[1]: -// type_vertex = "int"; -// break; -// case type_name[2]: -// type_vertex = "int"; -// break; -// case type_name[3]: -// type_vertex = "int"; -// break; -// case type_name[4]: -// type_vertex = "uint"; -// break; -// case type_name[5]: -// type_vertex = "uint"; -// break; -// case type_name[6]: -// type_vertex = "uint"; -// break; -// case type_name[7]: -// type_vertex = "float"; -// break; -// case type_name[8]: -// type_vertex = "float"; -// break; -// case type_name[9]: -// break; -// default: -// Console.WriteLine ("Not a valid input"); -// break; -// } - - //TODO:figure out the size of polygon -// switch (line [2]) -// { -// case type_name[1]: -// type_size_face = "int"; -// break; -// case type_name[2]: -// type_size_face = "int"; -// break; -// case type_name[3]: -// type_size_face = "int"; -// break; -// case type_name[4]: -// type_size_face = "uint"; -// break; -// case type_name[5]: -// type_size_face = "uint"; -// break; -// case type_name[6]: -// type_size_face = "uint"; -// break; -// case type_name[7]: -// type_size_face = "float"; -// break; -// case type_name[8]: -// type_size_face = "float"; -// break; -// case type_name[9]: -// break; -// default: -// Console.WriteLine ("Not a valid input"); -// break; -// } - -// switch (line [3]) -// { -// -// } -// } - else if (float.TryParse (line [0], out x) && line.Length == 3) { - if (TryParseVec (line, 0, 1, 2, out v)) { - tempVerts.Add (v); - } - continue; - } - else if (float.TryParse (line [0], out s) && s == sizeofFaces && line.Length > 3) - { - if (line.Length == 4) { - int v0, v1, v2; - if (!int.TryParse (line [1], out v0)) - continue; - if (!int.TryParse (line [2], out v1)) - continue; - if (!int.TryParse (line [3], out v2)) - continue; - tris.Add (new Triangle3 (tempVerts [v0], tempVerts [v1], tempVerts [v2])); - } - else if (line.Length > 4) - { - int v0; - if (!int.TryParse(line[1], out v0)) continue; - - for (int i = 2; i < line.Length - 1; i++) - { - int vi, vii; - if (!int.TryParse(line[i], out vi)) continue; - if (!int.TryParse(line[i + 1], out vii)) continue; - - - - tris.Add(new Triangle3(tempVerts[v0], tempVerts[vi], tempVerts[vii])); - } - } - } - - } - } - } - - - /// - /// Tries the parse vec. - /// - /// true, if parse vec_float was tryed, false otherwise. - /// Values. - /// The x coordinate. - /// The y coordinate. - /// The z coordinate. - /// V. - private bool TryParseVec(string[] values, int x, int y, int z, out Vector3 v) - { - v = Vector3.Zero; - - if (!float.TryParse(values[x], NumberStyles.Any, CultureInfo.InvariantCulture, out v.X)) - return false; - if (!float.TryParse(values[y], NumberStyles.Any, CultureInfo.InvariantCulture, out v.Y)) - return false; - if (!float.TryParse(values[z], NumberStyles.Any, CultureInfo.InvariantCulture, out v.Z)) - return false; - - return true; - } - } -} - -#endif diff --git a/Source/SharpNav.Examples/SharpNav.Examples.csproj b/Source/SharpNav.Examples/SharpNav.Examples.csproj index 4ce43983..d5dbcf71 100644 --- a/Source/SharpNav.Examples/SharpNav.Examples.csproj +++ b/Source/SharpNav.Examples/SharpNav.Examples.csproj @@ -80,7 +80,6 @@ - diff --git a/Source/SharpNav/Collections/BVTree.cs b/Source/SharpNav/Collections/BVTree.cs index 4933df36..529bd0ac 100644 --- a/Source/SharpNav/Collections/BVTree.cs +++ b/Source/SharpNav/Collections/BVTree.cs @@ -73,6 +73,16 @@ public BVTree(PolyVertex[] verts, PolyMesh.Polygon[] polys, int nvp, float cellS Subdivide(items, 0, items.Count, 0); } + /// + /// Creates a copy of the tree from a group of enumerable nodes. + /// + /// The nodes to copy from. + public BVTree(IEnumerable nodes) + { + //TODO verify that the nodes passed in are a valid tree? + this.nodes = nodes.ToArray(); + } + /// /// Gets the number of nodes in the tree. /// diff --git a/Source/SharpNav/IO/Json/NavMeshJsonSerializer.cs b/Source/SharpNav/IO/Json/NavMeshJsonSerializer.cs index 99416e84..c3ffc0bc 100644 --- a/Source/SharpNav/IO/Json/NavMeshJsonSerializer.cs +++ b/Source/SharpNav/IO/Json/NavMeshJsonSerializer.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Runtime.Serialization; using Newtonsoft.Json; @@ -33,7 +32,6 @@ public class NavMeshJsonSerializer : NavMeshSerializer { private JsonSerializer serializer; - //TODO maybe a better system? //increase this once every time the file format changes. private static readonly int FormatVersion = 3; @@ -67,10 +65,7 @@ public override void Serialize(string path, TiledNavMesh mesh) root.Add("maxPolys", JToken.FromObject(mesh.MaxPolys, serializer)); var tilesArray = new JArray(); - - var tiles = (List) GetPrivateField(mesh, typeof(TiledNavMesh), "tileList"); - var tileRefs = (Dictionary)GetPrivateField(mesh, typeof(TiledNavMesh), "tileRefs"); - foreach (NavTile tile in tiles) + foreach (NavTile tile in mesh.Tiles) { NavPolyId id = mesh.GetTileRef(tile); tilesArray.Add(SerializeMeshTile(tile, id)); @@ -123,9 +118,11 @@ private JObject SerializeMeshTile(NavTile tile, NavPolyId id) result.Add("detailTris", JToken.FromObject(tile.DetailTris, serializer)); result.Add("offMeshConnections", JToken.FromObject(tile.OffMeshConnections, serializer)); - var treeNodes = (BVTree.Node[])GetPrivateField(tile.BVTree, "nodes"); JObject treeObject = new JObject(); - treeObject.Add("nodes", JToken.FromObject(treeNodes, serializer)); + JArray treeNodes = new JArray(); + for (int i = 0; i < tile.BVTree.Count; i++) + treeNodes.Add(JToken.FromObject(tile.BVTree[i], serializer)); + treeObject.Add("nodes", treeNodes); result.Add("bvTree", treeObject); result.Add("bvQuantFactor", JToken.FromObject(tile.BvQuantFactor, serializer)); @@ -156,12 +153,10 @@ private NavTile DeserializeMeshTile(JToken token, NavPolyIdManager manager, out result.BvQuantFactor = token["bvQuantFactor"].ToObject(serializer); result.WalkableClimb = token["walkableClimb"].ToObject(serializer); - var tree = (BVTree) FormatterServices.GetUninitializedObject(typeof(BVTree)); var treeObject = (JObject) token["bvTree"]; var nodes = treeObject.GetValue("nodes").ToObject(); - SetPrivateField(tree, "nodes", nodes); - result.BVTree = tree; + result.BVTree = new BVTree(nodes); return result; } diff --git a/Source/SharpNav/IO/NavMeshSerializer.cs b/Source/SharpNav/IO/NavMeshSerializer.cs index b31d2c8c..2c6268c1 100644 --- a/Source/SharpNav/IO/NavMeshSerializer.cs +++ b/Source/SharpNav/IO/NavMeshSerializer.cs @@ -27,53 +27,5 @@ public abstract class NavMeshSerializer /// file to deserialize from /// deserialized mesh public abstract TiledNavMesh Deserialize(string path); - - /// - /// Get value of private field using reflection - /// - /// object - /// name of field - /// value of field - protected object GetPrivateField(object obj, string name) - { - return GetPrivateField(obj, obj.GetType(), name); - } - - /// - /// Get value of private field using reflection - /// - /// object - /// type of object - /// name of field - /// value of field - protected object GetPrivateField(object obj, Type type, string name) - { - var field = type.GetField(name, BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance); - return field.GetValue(obj); - } - - /// - /// Set value of private field - /// - /// object - /// name of field - /// value to set - protected void SetPrivateField(object obj, string name, object value) - { - SetPrivateField(obj, obj.GetType(), name, value); - } - - /// - /// Set value of private field - /// - /// object - /// type of object - /// name of field - /// value to set - protected void SetPrivateField(object obj, Type type, string name, object value) - { - var field = type.GetField(name, BindingFlags.NonPublic | BindingFlags.SetField | BindingFlags.Instance); - field.SetValue(obj, value); - } } } diff --git a/Source/SharpNav/Pathfinding/Path.cs b/Source/SharpNav/Pathfinding/Path.cs index 9e2b1a75..be81741a 100644 --- a/Source/SharpNav/Pathfinding/Path.cs +++ b/Source/SharpNav/Pathfinding/Path.cs @@ -1,25 +1,26 @@ // Copyright (c) 2016 Robert Rouhani and other contributors (see CONTRIBUTORS file). // Licensed under the MIT License - https://raw.github.com/Robmaister/SharpNav/master/LICENSE +using System; using System.Collections.Generic; namespace SharpNav.Pathfinding { public class Path { - private List Polys; + private List polys; private float cost; public Path() { - Polys = new List(); + polys = new List(); cost = 0; } public Path(Path otherPath) : this() { - Polys.AddRange(otherPath.Polys); + polys.AddRange(otherPath.polys); cost = otherPath.Cost; } @@ -27,37 +28,37 @@ public NavPolyId this[int i] { get { - return Polys[i]; + return polys[i]; } set { - Polys[i] = value; + polys[i] = value; } } - public int Count { get { return Polys.Count; } } + public int Count { get { return polys.Count; } } public float Cost { get { return cost; } } public void Clear() { - Polys.Clear(); + polys.Clear(); cost = 0; } public void Add(NavPolyId poly) { - Polys.Add(poly); + polys.Add(poly); } public void AddRange(IEnumerable polys) { - Polys.AddRange(polys); + this.polys.AddRange(polys); } public void AppendPath(Path other) { - Polys.AddRange(other.Polys); + polys.AddRange(other.polys); } public void AddCost(float cost) @@ -67,32 +68,81 @@ public void AddCost(float cost) public void Reverse() { - Polys.Reverse(); + polys.Reverse(); } public void RemoveTrackbacks() { - for (int j = 0; j < Polys.Count; j++) + for (int i = 0; i < polys.Count; i++) { - if (j - 1 >= 0 && j + 1 < Polys.Count) + if (i - 1 >= 0 && i + 1 < polys.Count) { - if (Polys[j - 1] == Polys[j + 1]) + if (polys[i - 1] == polys[i + 1]) { - Polys.RemoveRange(j - 1, 2); - j -= 2; + polys.RemoveRange(i - 1, 2); + i -= 2; } } } } + public void FixupCorridor(List visited) + { + int furthestPath = -1; + int furthestVisited = -1; + + //find furhtest common polygon + bool found = false; + for (int i = polys.Count - 1; i >= 0; i--) + { + for (int j = visited.Count - 1; j >= 0; j--) + { + if (polys[i] == visited[j]) + { + furthestPath = i; + furthestVisited = j; + found = true; + break; + } + } + + if (found) + break; + } + + //no intersection in visited path + if (furthestPath == -1 || furthestVisited == -1) + return; + + //concatenate paths + //adjust beginning of the buffer to include the visited + int req = visited.Count - furthestVisited; + int orig = Math.Min(furthestPath + 1, polys.Count); + int size = Math.Max(0, polys.Count - orig); + + //remove everything before visited + polys.RemoveRange(0, orig); + + //for (int i = 0; i < size; i++) + //polys[req + i] = polys[orig + i]; + + //store visited + for (int i = 0; i < req; i++) + //polys[i] = visited[(visited.Count - 1) - i]; + polys.Insert(i, visited[(visited.Count - 1) - i]); + + //return req + size; + return; + } + public void RemoveAt(int index) { - Polys.RemoveAt(index); + polys.RemoveAt(index); } public void RemoveRange(int index, int count) { - Polys.RemoveRange(index, count); + polys.RemoveRange(index, count); } } } diff --git a/Source/SharpNav/Pathfinding/PathfindingCommon.cs b/Source/SharpNav/Pathfinding/PathfindingCommon.cs index c6ef157e..af5da5b8 100644 --- a/Source/SharpNav/Pathfinding/PathfindingCommon.cs +++ b/Source/SharpNav/Pathfinding/PathfindingCommon.cs @@ -26,8 +26,6 @@ public class PathfindingCommon /// Generate an accurate sample of random points in the convex polygon and pick a point. /// /// The polygon's points data - /// The number of points - /// The triangle areas /// A random float /// Another random float /// The resulting point diff --git a/Source/SharpNav/TiledNavMesh.cs b/Source/SharpNav/TiledNavMesh.cs index e273a575..2ad4e4b5 100644 --- a/Source/SharpNav/TiledNavMesh.cs +++ b/Source/SharpNav/TiledNavMesh.cs @@ -170,6 +170,14 @@ public NavTile this[NavPolyId id] } } + public ReadOnlyCollection Tiles + { + get + { + return new ReadOnlyCollection(tileList); + } + } + /// /// Gets or sets user data for this navmesh. ///