int GetBox ( IntRect rect ) { if ( count >= arr.Length ) EnsureCapacity ( count+1 ); arr[count] = new BBTreeBox ( rect ); count++; return count-1; }
// Token: 0x0600251A RID: 9498 RVA: 0x0019D24C File Offset: 0x0019B44C public static void UpdateArea(GraphUpdateObject o, INavmeshHolder graph) { Bounds bounds = graph.transform.InverseTransform(o.bounds); IntRect irect = new IntRect(Mathf.FloorToInt(bounds.min.x * 1000f), Mathf.FloorToInt(bounds.min.z * 1000f), Mathf.CeilToInt(bounds.max.x * 1000f), Mathf.CeilToInt(bounds.max.z * 1000f)); Int3 a = new Int3(irect.xmin, 0, irect.ymin); Int3 b = new Int3(irect.xmin, 0, irect.ymax); Int3 c = new Int3(irect.xmax, 0, irect.ymin); Int3 d = new Int3(irect.xmax, 0, irect.ymax); int ymin = ((Int3)bounds.min).y; int ymax = ((Int3)bounds.max).y; graph.GetNodes(delegate(GraphNode _node) { TriangleMeshNode triangleMeshNode = _node as TriangleMeshNode; bool flag = false; int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; for (int i = 0; i < 3; i++) { Int3 vertexInGraphSpace = triangleMeshNode.GetVertexInGraphSpace(i); if (irect.Contains(vertexInGraphSpace.x, vertexInGraphSpace.z)) { flag = true; break; } if (vertexInGraphSpace.x < irect.xmin) { num++; } if (vertexInGraphSpace.x > irect.xmax) { num2++; } if (vertexInGraphSpace.z < irect.ymin) { num3++; } if (vertexInGraphSpace.z > irect.ymax) { num4++; } } if (!flag && (num == 3 || num2 == 3 || num3 == 3 || num4 == 3)) { return; } for (int j = 0; j < 3; j++) { int i2 = (j > 1) ? 0 : (j + 1); Int3 vertexInGraphSpace2 = triangleMeshNode.GetVertexInGraphSpace(j); Int3 vertexInGraphSpace3 = triangleMeshNode.GetVertexInGraphSpace(i2); if (VectorMath.SegmentsIntersectXZ(a, b, vertexInGraphSpace2, vertexInGraphSpace3)) { flag = true; break; } if (VectorMath.SegmentsIntersectXZ(a, c, vertexInGraphSpace2, vertexInGraphSpace3)) { flag = true; break; } if (VectorMath.SegmentsIntersectXZ(c, d, vertexInGraphSpace2, vertexInGraphSpace3)) { flag = true; break; } if (VectorMath.SegmentsIntersectXZ(d, b, vertexInGraphSpace2, vertexInGraphSpace3)) { flag = true; break; } } if (flag || triangleMeshNode.ContainsPointInGraphSpace(a) || triangleMeshNode.ContainsPointInGraphSpace(b) || triangleMeshNode.ContainsPointInGraphSpace(c) || triangleMeshNode.ContainsPointInGraphSpace(d)) { flag = true; } if (!flag) { return; } int num5 = 0; int num6 = 0; for (int k = 0; k < 3; k++) { Int3 vertexInGraphSpace4 = triangleMeshNode.GetVertexInGraphSpace(k); if (vertexInGraphSpace4.y < ymin) { num6++; } if (vertexInGraphSpace4.y > ymax) { num5++; } } if (num6 == 3 || num5 == 3) { return; } o.WillUpdateNode(triangleMeshNode); o.Apply(triangleMeshNode); }); }
/** Returns a new IntRect which is expanded to contain the point */ public IntRect ExpandToContain (int x, int y) { var r = new IntRect( System.Math.Min(xmin,x), System.Math.Min(ymin,y), System.Math.Max(xmax,x), System.Math.Max(ymax,y) ); return r; }
/** All nodes inside the shape or if null, the bounding box. * If a shape is supplied, it is assumed to be contained inside the bounding box. * \see GraphUpdateShape.GetBounds */ private List<GraphNode> GetNodesInArea (Bounds b, GraphUpdateShape shape) { if (nodes == null || width*depth != nodes.Length) { return null; } // Get a buffer we can use List<GraphNode> inArea = Pathfinding.Util.ListPool<GraphNode>.Claim(); // Take the bounds and transform it using the matrix // Then convert that to a rectangle which contains // all nodes that might be inside the bounds Vector3 min, max; GetBoundsMinMax(b, inverseMatrix, out min, out max); int minX = Mathf.RoundToInt(min.x-0.5F); int maxX = Mathf.RoundToInt(max.x-0.5F); int minZ = Mathf.RoundToInt(min.z-0.5F); int maxZ = Mathf.RoundToInt(max.z-0.5F); var originalRect = new IntRect(minX, minZ, maxX, maxZ); // Rect which covers the whole grid var gridRect = new IntRect(0, 0, width-1, depth-1); // Clamp the rect to the grid var rect = IntRect.Intersection(originalRect, gridRect); // Loop through all nodes in the rectangle for (int x = rect.xmin; x <= rect.xmax; x++) { for (int z = rect.ymin; z <= rect.ymax; z++) { int index = z*width+x; GraphNode node = nodes[index]; // If it is contained in the bounds (and optionally the shape) // then add it to the buffer if (b.Contains((Vector3)node.position) && (shape == null || shape.Contains((Vector3)node.position))) { inArea.Add(node); } } } return inArea; }
/** Returns the area of a rect */ static int RectArea (IntRect r) { return r.Width*r.Height; }
public BBTreeBox (MeshNode node) { this.node = node; var first = node.GetVertex(0); var min = new Int2(first.x,first.z); Int2 max = min; for (int i=1;i<node.GetVertexCount();i++) { var p = node.GetVertex(i); min.x = Math.Min (min.x,p.x); min.y = Math.Min (min.y,p.z); max.x = Math.Max (max.x,p.x); max.y = Math.Max (max.y,p.z); } rect = new IntRect (min.x,min.y,max.x,max.y); left = right = -1; }
/** Returns an XZ bounds object with the bounds of a group of tiles. * The bounds object is defined in world units. */ public Bounds GetTileBounds ( IntRect rect ) { return GetTileBounds (rect.xmin, rect.ymin, rect.Width, rect.Height); }
private static bool RectIntersectsCircle(IntRect r, Vector3 p, float radius) { if (float.IsPositiveInfinity(radius)) { return true; } Vector3 vector = p; p.x = Math.Max(p.x, (float)r.xmin * 0.001f); p.x = Math.Min(p.x, (float)r.xmax * 0.001f); p.z = Math.Max(p.z, (float)r.ymin * 0.001f); p.z = Math.Min(p.z, (float)r.ymax * 0.001f); return (p.x - vector.x) * (p.x - vector.x) + (p.z - vector.z) * (p.z - vector.z) < radius * radius; }
public static IntRect Union(IntRect a, IntRect b) { IntRect result = new IntRect(Math.Min(a.xmin, b.xmin), Math.Min(a.ymin, b.ymin), Math.Max(a.xmax, b.xmax), Math.Max(a.ymax, b.ymax)); return(result); }
public static bool Intersects(IntRect a, IntRect b) { return(a.xmin <= b.xmax && a.ymin <= b.ymax && a.xmax >= b.xmin && a.ymax >= b.ymin); }
public override bool Equals(object _b) { IntRect intRect = (IntRect)_b; return(this.xmin == intRect.xmin && this.xmax == intRect.xmax && this.ymin == intRect.ymin && this.ymax == intRect.ymax); }
public IntRect ExpandToContain(int x, int y) { IntRect result = new IntRect(Math.Min(this.xmin, x), Math.Min(this.ymin, y), Math.Max(this.xmax, x), Math.Max(this.ymax, y)); return(result); }
public BBTreeBox(IntRect rect) { this.node = null; this.rect = rect; this.left = (this.right = -1); }
private static int RectArea(IntRect r) { return(r.Width * r.Height); }
private static IntRect ExpandToContain(IntRect r, IntRect r2) { return(IntRect.Union(r, r2)); }
/** Returns if the two rectangles intersect each other */ public static bool Intersects(IntRect a, IntRect b) { return(!(a.xmin > b.xmax || a.ymin > b.ymax || a.xmax < b.xmin || a.ymax < b.ymin)); }
public static void UpdateArea (GraphUpdateObject o, INavmesh graph) { //System.DateTime startTime = System.DateTime.UtcNow; Bounds bounds = o.bounds; Rect r = Rect.MinMaxRect (bounds.min.x,bounds.min.z,bounds.max.x,bounds.max.z); var r2 = new IntRect( Mathf.FloorToInt(bounds.min.x*Int3.Precision), Mathf.FloorToInt(bounds.min.z*Int3.Precision), Mathf.FloorToInt(bounds.max.x*Int3.Precision), Mathf.FloorToInt(bounds.max.z*Int3.Precision) ); var a = new Int3(r2.xmin,0,r2.ymin); var b = new Int3(r2.xmin,0,r2.ymax); var c = new Int3(r2.xmax,0,r2.ymin); var d = new Int3(r2.xmax,0,r2.ymax); graph.GetNodes (_node => { var node = _node as TriangleMeshNode; bool inside = false; int allLeft = 0; int allRight = 0; int allTop = 0; int allBottom = 0; for (int v=0;v<3;v++) { Int3 p = node.GetVertex(v); var vert = (Vector3)p; if (r2.Contains (p.x,p.z)) { inside = true; break; } if (vert.x < r.xMin) allLeft++; if (vert.x > r.xMax) allRight++; if (vert.z < r.yMin) allTop++; if (vert.z > r.yMax) allBottom++; } if (!inside) { if (allLeft == 3 || allRight == 3 || allTop == 3 || allBottom == 3) { return true; } } for (int v=0;v<3;v++) { int v2 = v > 1 ? 0 : v+1; Int3 vert1 = node.GetVertex(v); Int3 vert2 = node.GetVertex(v2); if (Polygon.Intersects (a,b,vert1,vert2)) { inside = true; break; } if (Polygon.Intersects (a,c,vert1,vert2)) { inside = true; break; } if (Polygon.Intersects (c,d,vert1,vert2)) { inside = true; break; } if (Polygon.Intersects (d,b,vert1,vert2)) { inside = true; break; } } if (node.ContainsPoint (a) || node.ContainsPoint (b) || node.ContainsPoint (c) || node.ContainsPoint (d)) { inside = true; } if (!inside) { return true; } o.WillUpdateNode(node); o.Apply (node); return true; }); }
public override bool Equals(object _b) { IntRect rect = (IntRect)_b; return((((this.xmin == rect.xmin) && (this.xmax == rect.xmax)) && (this.ymin == rect.ymin)) && (this.ymax == rect.ymax)); }
public static bool Intersects(IntRect a, IntRect b) { return((((a.xmin <= b.xmax) && (a.ymin <= b.ymax)) && (a.xmax >= b.xmin)) && (a.ymax >= b.ymin)); }
public static IntRect Union(IntRect a, IntRect b) { return(new IntRect(Math.Min(a.xmin, b.xmin), Math.Min(a.ymin, b.ymin), Math.Max(a.xmax, b.xmax), Math.Max(a.ymax, b.ymax))); }
public void ForceUpdate() { if (this.handler == null) { throw new Exception("Cannot update graphs. No TileHandler. Do not call the ForceUpdate method in Awake."); } this.lastUpdateTime = Time.realtimeSinceStartup; if (!this.handler.isValid) { if (!this.handler.graph.exists) { this.UseSpecifiedHandler(null); return; } Debug.Log("TileHandler no longer matched the underlaying graph (possibly because of a graph scan). Recreating TileHandler..."); this.UseSpecifiedHandler(new TileHandler(this.handler.graph)); this.handler.CreateTileTypesFromGraph(); this.forcedReloadRects.Add(new IntRect(int.MinValue, int.MinValue, int.MaxValue, int.MaxValue)); } GridLookup <NavmeshClipper> .Root allItems = this.handler.cuts.AllItems; if (this.forcedReloadRects.Count == 0) { int num = 0; for (GridLookup <NavmeshClipper> .Root root = allItems; root != null; root = root.next) { if (root.obj.RequiresUpdate()) { num++; break; } } if (num == 0) { return; } } bool flag = this.handler.StartBatchLoad(); for (int i = 0; i < this.forcedReloadRects.Count; i++) { this.handler.ReloadInBounds(this.forcedReloadRects[i]); } this.forcedReloadRects.Clear(); for (GridLookup <NavmeshClipper> .Root root2 = allItems; root2 != null; root2 = root2.next) { if (root2.obj.RequiresUpdate()) { this.handler.ReloadInBounds(root2.previousBounds); Rect bounds = root2.obj.GetBounds(this.handler.graph.transform); IntRect touchingTilesInGraphSpace = this.handler.graph.GetTouchingTilesInGraphSpace(bounds); this.handler.cuts.Move(root2.obj, touchingTilesInGraphSpace); this.handler.ReloadInBounds(touchingTilesInGraphSpace); } } for (GridLookup <NavmeshClipper> .Root root3 = allItems; root3 != null; root3 = root3.next) { if (root3.obj.RequiresUpdate()) { root3.obj.NotifyUpdated(); } } if (flag) { this.handler.EndBatchLoad(); } }
/** Returns the difference in area between \a r and \a r expanded to contain \a r2 */ static int ExpansionRequired (IntRect r, IntRect r2) { int xMin = Math.Min (r.xmin,r2.xmin); int xMax = Math.Max (r.xmax,r2.xmax); int yMin = Math.Min (r.ymin,r2.ymin); int yMax = Math.Max (r.ymax,r2.ymax); return (xMax-xMin)*(yMax-yMin)-RectArea (r); }
// Token: 0x060024E4 RID: 9444 RVA: 0x0019B62C File Offset: 0x0019982C void IUpdatableGraph.UpdateArea(GraphUpdateObject o) { if (this.nodes == null || this.nodes.Length != this.width * this.depth * this.layerCount) { Debug.LogWarning("The Grid Graph is not scanned, cannot update area "); return; } IntRect a; IntRect a2; IntRect intRect; bool flag; int num; base.CalculateAffectedRegions(o, out a, out a2, out intRect, out flag, out num); bool flag2 = o is LayerGridGraphUpdate && ((LayerGridGraphUpdate)o).recalculateNodes; bool flag3 = (o is LayerGridGraphUpdate) ? ((LayerGridGraphUpdate)o).preserveExistingNodes : (!o.resetPenaltyOnPhysics); if (o.trackChangedNodes && flag2) { Debug.LogError("Cannot track changed nodes when creating or deleting nodes.\nWill not update LayerGridGraph"); return; } IntRect b = new IntRect(0, 0, this.width - 1, this.depth - 1); IntRect intRect2 = IntRect.Intersection(a2, b); if (!flag2) { for (int i = intRect2.xmin; i <= intRect2.xmax; i++) { for (int j = intRect2.ymin; j <= intRect2.ymax; j++) { for (int k = 0; k < this.layerCount; k++) { o.WillUpdateNode(this.nodes[k * this.width * this.depth + j * this.width + i]); } } } } if (o.updatePhysics && !o.modifyWalkability) { this.collision.Initialize(base.transform, this.nodeSize); intRect2 = IntRect.Intersection(intRect, b); for (int l = intRect2.xmin; l <= intRect2.xmax; l++) { for (int m = intRect2.ymin; m <= intRect2.ymax; m++) { this.RecalculateCell(l, m, !flag3, false); } } for (int n = intRect2.xmin; n <= intRect2.xmax; n++) { for (int num2 = intRect2.ymin; num2 <= intRect2.ymax; num2++) { this.CalculateConnections(n, num2); } } } intRect2 = IntRect.Intersection(a, b); for (int num3 = intRect2.xmin; num3 <= intRect2.xmax; num3++) { for (int num4 = intRect2.ymin; num4 <= intRect2.ymax; num4++) { for (int num5 = 0; num5 < this.layerCount; num5++) { int num6 = num5 * this.width * this.depth + num4 * this.width + num3; LevelGridNode levelGridNode = this.nodes[num6]; if (levelGridNode != null) { if (flag) { levelGridNode.Walkable = levelGridNode.WalkableErosion; if (o.bounds.Contains((Vector3)levelGridNode.position)) { o.Apply(levelGridNode); } levelGridNode.WalkableErosion = levelGridNode.Walkable; } else if (o.bounds.Contains((Vector3)levelGridNode.position)) { o.Apply(levelGridNode); } } } } } if (flag && num == 0) { intRect2 = IntRect.Intersection(a2, b); for (int num7 = intRect2.xmin; num7 <= intRect2.xmax; num7++) { for (int num8 = intRect2.ymin; num8 <= intRect2.ymax; num8++) { this.CalculateConnections(num7, num8); } } return; } if (flag && num > 0) { IntRect a3 = IntRect.Union(a, intRect).Expand(num); IntRect intRect3 = a3.Expand(num); a3 = IntRect.Intersection(a3, b); intRect3 = IntRect.Intersection(intRect3, b); for (int num9 = intRect3.xmin; num9 <= intRect3.xmax; num9++) { for (int num10 = intRect3.ymin; num10 <= intRect3.ymax; num10++) { for (int num11 = 0; num11 < this.layerCount; num11++) { int num12 = num11 * this.width * this.depth + num10 * this.width + num9; LevelGridNode levelGridNode2 = this.nodes[num12]; if (levelGridNode2 != null) { bool walkable = levelGridNode2.Walkable; levelGridNode2.Walkable = levelGridNode2.WalkableErosion; if (!a3.Contains(num9, num10)) { levelGridNode2.TmpWalkable = walkable; } } } } } for (int num13 = intRect3.xmin; num13 <= intRect3.xmax; num13++) { for (int num14 = intRect3.ymin; num14 <= intRect3.ymax; num14++) { this.CalculateConnections(num13, num14); } } base.ErodeWalkableArea(intRect3.xmin, intRect3.ymin, intRect3.xmax + 1, intRect3.ymax + 1); for (int num15 = intRect3.xmin; num15 <= intRect3.xmax; num15++) { for (int num16 = intRect3.ymin; num16 <= intRect3.ymax; num16++) { if (!a3.Contains(num15, num16)) { for (int num17 = 0; num17 < this.layerCount; num17++) { int num18 = num17 * this.width * this.depth + num16 * this.width + num15; LevelGridNode levelGridNode3 = this.nodes[num18]; if (levelGridNode3 != null) { levelGridNode3.Walkable = levelGridNode3.TmpWalkable; } } } } } for (int num19 = intRect3.xmin; num19 <= intRect3.xmax; num19++) { for (int num20 = intRect3.ymin; num20 <= intRect3.ymax; num20++) { this.CalculateConnections(num19, num20); } } } }
public void UpdateAreaInit (GraphUpdateObject o) { if (!o.updatePhysics) { return; } if (!dynamic) { throw new System.Exception ("Recast graph must be marked as dynamic to enable graph updates"); } AstarProfiler.Reset (); AstarProfiler.StartProfile ("UpdateAreaInit"); AstarProfiler.StartProfile ("CollectMeshes"); RelevantGraphSurface.UpdateAllPositions (); List<ExtraMesh> extraMeshes; Bounds b = o.bounds; b.center -= forcedBounds.min; //Calculate world bounds of all affected tiles IntRect r = new IntRect (Mathf.FloorToInt (b.min.x / (tileSizeX*cellSize)), Mathf.FloorToInt (b.min.z / (tileSizeZ*cellSize)), Mathf.FloorToInt (b.max.x / (tileSizeX*cellSize)), Mathf.FloorToInt (b.max.z / (tileSizeZ*cellSize))); //Clamp to bounds r = IntRect.Intersection (r, new IntRect (0,0,tileXCount-1,tileZCount-1)); Bounds tileBounds = new Bounds(); Vector3 forcedBoundsMin = forcedBounds.min; Vector3 forcedBoundsMax = forcedBounds.max; float tcsx = tileSizeX*cellSize; float tcsz = tileSizeZ*cellSize; tileBounds.SetMinMax(new Vector3 (r.xmin*tcsx, 0, r.ymin*tcsz) + forcedBoundsMin, new Vector3 ((r.xmax+1)*tcsx + forcedBoundsMin.x, forcedBoundsMax.y, (r.ymax+1)*tcsz + forcedBoundsMin.z) ); int voxelCharacterRadius = Mathf.CeilToInt (characterRadius/cellSize); int borderSize = voxelCharacterRadius + 3; //Expand borderSize voxels on each side tileBounds.Expand (new Vector3 (borderSize,0,borderSize)*cellSize*2); Debug.DrawLine (tileBounds.min, tileBounds.max); //Debug.Break (); if (!CollectMeshes (out extraMeshes, tileBounds)) { //return; } Voxelize vox = globalVox; if (vox == null) { //Create the voxelizer and set all settings vox = new Voxelize (cellHeight, cellSize, walkableClimb, walkableHeight, maxSlope); vox.maxEdgeLength = maxEdgeLength; if (dynamic) globalVox = vox; } vox.inputExtraMeshes = extraMeshes; AstarProfiler.EndProfile ("CollectMeshes"); AstarProfiler.EndProfile ("UpdateAreaInit"); }
public IntRect ExpandToContain(int x, int y) { IntRect result = new IntRect(Math.Min(this.xmin, x), Math.Min(this.ymin, y), Math.Max(this.xmax, x), Math.Max(this.ymax, y)); return result; }
/** Returns if the two rectangles intersect each other */ public static bool Intersects (IntRect a, IntRect b) { return !(a.xmin > b.xmax || a.ymin > b.ymax || a.xmax < b.xmin || a.ymax < b.ymin); }
public static bool Intersects(IntRect a, IntRect b) { return a.xmin <= b.xmax && a.ymin <= b.ymax && a.xmax >= b.xmin && a.ymax >= b.ymin; }
/** All nodes inside the shape or if null, the bounding box. * If a shape is supplied, it is assumed to be contained inside the bounding box. * \see GraphUpdateShape.GetBounds */ private List<GraphNode> GetNodesInArea (Bounds b, GraphUpdateShape shape) { if (nodes == null || width*depth != nodes.Length) { return null; } List<GraphNode> inArea = Pathfinding.Util.ListPool<GraphNode>.Claim (); Vector3 min, max; GetBoundsMinMax (b,inverseMatrix,out min, out max); int minX = Mathf.RoundToInt (min.x-0.5F); int maxX = Mathf.RoundToInt (max.x-0.5F); int minZ = Mathf.RoundToInt (min.z-0.5F); int maxZ = Mathf.RoundToInt (max.z-0.5F); IntRect originalRect = new IntRect(minX,minZ,maxX,maxZ); IntRect gridRect = new IntRect(0,0,width-1,depth-1); IntRect rect = IntRect.Intersection (originalRect, gridRect); for (int x = rect.xmin; x <= rect.xmax;x++) { for (int z = rect.ymin;z <= rect.ymax;z++) { int index = z*width+x; GraphNode node = nodes[index]; if (b.Contains ((Vector3)node.position) && (shape == null || shape.Contains ((Vector3)node.position))) { inArea.Add (node); } } } return inArea; }
public static IntRect Union(IntRect a, IntRect b) { IntRect result = new IntRect(Math.Min(a.xmin, b.xmin), Math.Min(a.ymin, b.ymin), Math.Max(a.xmax, b.xmax), Math.Max(a.ymax, b.ymax)); return result; }
public new void UpdateArea(GraphUpdateObject o) { if (this.nodes == null || this.nodes.Length != this.width * this.depth * this.layerCount) { Debug.LogWarning("The Grid Graph is not scanned, cannot update area "); return; } Bounds bounds = o.bounds; Vector3 a; Vector3 a2; GridGraph.GetBoundsMinMax(bounds, this.inverseMatrix, out a, out a2); int xmin = Mathf.RoundToInt(a.x - 0.5f); int xmax = Mathf.RoundToInt(a2.x - 0.5f); int ymin = Mathf.RoundToInt(a.z - 0.5f); int ymax = Mathf.RoundToInt(a2.z - 0.5f); IntRect intRect = new IntRect(xmin, ymin, xmax, ymax); IntRect intRect2 = intRect; IntRect b = new IntRect(0, 0, this.width - 1, this.depth - 1); IntRect intRect3 = intRect; bool flag = o.updatePhysics || o.modifyWalkability; bool flag2 = o is LayerGridGraphUpdate && ((LayerGridGraphUpdate)o).recalculateNodes; bool preserveExistingNodes = !(o is LayerGridGraphUpdate) || ((LayerGridGraphUpdate)o).preserveExistingNodes; int num = (!o.updateErosion) ? 0 : this.erodeIterations; if (o.trackChangedNodes && flag2) { Debug.LogError("Cannot track changed nodes when creating or deleting nodes.\nWill not update LayerGridGraph"); return; } if (o.updatePhysics && !o.modifyWalkability && this.collision.collisionCheck) { Vector3 a3 = new Vector3(this.collision.diameter, 0f, this.collision.diameter) * 0.5f; a -= a3 * 1.02f; a2 += a3 * 1.02f; intRect3 = new IntRect(Mathf.RoundToInt(a.x - 0.5f), Mathf.RoundToInt(a.z - 0.5f), Mathf.RoundToInt(a2.x - 0.5f), Mathf.RoundToInt(a2.z - 0.5f)); intRect2 = IntRect.Union(intRect3, intRect2); } if (flag || num > 0) { intRect2 = intRect2.Expand(num + 1); } IntRect intRect4 = IntRect.Intersection(intRect2, b); if (!flag2) { for (int i = intRect4.xmin; i <= intRect4.xmax; i++) { for (int j = intRect4.ymin; j <= intRect4.ymax; j++) { for (int k = 0; k < this.layerCount; k++) { o.WillUpdateNode(this.nodes[k * this.width * this.depth + j * this.width + i]); } } } } if (o.updatePhysics && !o.modifyWalkability) { this.collision.Initialize(this.matrix, this.nodeSize); intRect4 = IntRect.Intersection(intRect3, b); bool flag3 = false; for (int l = intRect4.xmin; l <= intRect4.xmax; l++) { for (int m = intRect4.ymin; m <= intRect4.ymax; m++) { flag3 |= this.RecalculateCell(l, m, preserveExistingNodes); } } for (int n = intRect4.xmin; n <= intRect4.xmax; n++) { for (int num2 = intRect4.ymin; num2 <= intRect4.ymax; num2++) { for (int num3 = 0; num3 < this.layerCount; num3++) { int num4 = num3 * this.width * this.depth + num2 * this.width + n; LevelGridNode levelGridNode = this.nodes[num4]; if (levelGridNode != null) { this.CalculateConnections(this.nodes, levelGridNode, n, num2, num3); } } } } } intRect4 = IntRect.Intersection(intRect, b); for (int num5 = intRect4.xmin; num5 <= intRect4.xmax; num5++) { for (int num6 = intRect4.ymin; num6 <= intRect4.ymax; num6++) { for (int num7 = 0; num7 < this.layerCount; num7++) { int num8 = num7 * this.width * this.depth + num6 * this.width + num5; LevelGridNode levelGridNode2 = this.nodes[num8]; if (levelGridNode2 != null) { if (flag) { levelGridNode2.Walkable = levelGridNode2.WalkableErosion; if (o.bounds.Contains((Vector3)levelGridNode2.position)) { o.Apply(levelGridNode2); } levelGridNode2.WalkableErosion = levelGridNode2.Walkable; } else if (o.bounds.Contains((Vector3)levelGridNode2.position)) { o.Apply(levelGridNode2); } } } } } if (flag && num == 0) { intRect4 = IntRect.Intersection(intRect2, b); for (int num9 = intRect4.xmin; num9 <= intRect4.xmax; num9++) { for (int num10 = intRect4.ymin; num10 <= intRect4.ymax; num10++) { for (int num11 = 0; num11 < this.layerCount; num11++) { int num12 = num11 * this.width * this.depth + num10 * this.width + num9; LevelGridNode levelGridNode3 = this.nodes[num12]; if (levelGridNode3 != null) { this.CalculateConnections(this.nodes, levelGridNode3, num9, num10, num11); } } } } } else if (flag && num > 0) { IntRect a4 = IntRect.Union(intRect, intRect3).Expand(num); IntRect a5 = a4.Expand(num); a4 = IntRect.Intersection(a4, b); a5 = IntRect.Intersection(a5, b); for (int num13 = a5.xmin; num13 <= a5.xmax; num13++) { for (int num14 = a5.ymin; num14 <= a5.ymax; num14++) { for (int num15 = 0; num15 < this.layerCount; num15++) { int num16 = num15 * this.width * this.depth + num14 * this.width + num13; LevelGridNode levelGridNode4 = this.nodes[num16]; if (levelGridNode4 != null) { bool walkable = levelGridNode4.Walkable; levelGridNode4.Walkable = levelGridNode4.WalkableErosion; if (!a4.Contains(num13, num14)) { levelGridNode4.TmpWalkable = walkable; } } } } } for (int num17 = a5.xmin; num17 <= a5.xmax; num17++) { for (int num18 = a5.ymin; num18 <= a5.ymax; num18++) { for (int num19 = 0; num19 < this.layerCount; num19++) { int num20 = num19 * this.width * this.depth + num18 * this.width + num17; LevelGridNode levelGridNode5 = this.nodes[num20]; if (levelGridNode5 != null) { this.CalculateConnections(this.nodes, levelGridNode5, num17, num18, num19); } } } } this.ErodeWalkableArea(a5.xmin, a5.ymin, a5.xmax + 1, a5.ymax + 1); for (int num21 = a5.xmin; num21 <= a5.xmax; num21++) { for (int num22 = a5.ymin; num22 <= a5.ymax; num22++) { if (!a4.Contains(num21, num22)) { for (int num23 = 0; num23 < this.layerCount; num23++) { int num24 = num23 * this.width * this.depth + num22 * this.width + num21; LevelGridNode levelGridNode6 = this.nodes[num24]; if (levelGridNode6 != null) { levelGridNode6.Walkable = levelGridNode6.TmpWalkable; } } } } } for (int num25 = a5.xmin; num25 <= a5.xmax; num25++) { for (int num26 = a5.ymin; num26 <= a5.ymax; num26++) { for (int num27 = 0; num27 < this.layerCount; num27++) { int num28 = num27 * this.width * this.depth + num26 * this.width + num25; LevelGridNode levelGridNode7 = this.nodes[num28]; if (levelGridNode7 != null) { this.CalculateConnections(this.nodes, levelGridNode7, num25, num26, num27); } } } } } }
public static void UpdateArea(GraphUpdateObject o, INavmesh graph) { //System.DateTime startTime = System.DateTime.UtcNow; Bounds bounds = o.bounds; Rect r = Rect.MinMaxRect(bounds.min.x, bounds.min.z, bounds.max.x, bounds.max.z); var r2 = new IntRect( Mathf.FloorToInt(bounds.min.x * Int3.Precision), Mathf.FloorToInt(bounds.min.z * Int3.Precision), Mathf.FloorToInt(bounds.max.x * Int3.Precision), Mathf.FloorToInt(bounds.max.z * Int3.Precision) ); var a = new Int3(r2.xmin, 0, r2.ymin); var b = new Int3(r2.xmin, 0, r2.ymax); var c = new Int3(r2.xmax, 0, r2.ymin); var d = new Int3(r2.xmax, 0, r2.ymax); graph.GetNodes(_node => { var node = _node as TriangleMeshNode; bool inside = false; int allLeft = 0; int allRight = 0; int allTop = 0; int allBottom = 0; for (int v = 0; v < 3; v++) { Int3 p = node.GetVertex(v); var vert = (Vector3)p; if (r2.Contains(p.x, p.z)) { inside = true; break; } if (vert.x < r.xMin) { allLeft++; } if (vert.x > r.xMax) { allRight++; } if (vert.z < r.yMin) { allTop++; } if (vert.z > r.yMax) { allBottom++; } } if (!inside) { if (allLeft == 3 || allRight == 3 || allTop == 3 || allBottom == 3) { return(true); } } for (int v = 0; v < 3; v++) { int v2 = v > 1 ? 0 : v + 1; Int3 vert1 = node.GetVertex(v); Int3 vert2 = node.GetVertex(v2); if (Polygon.Intersects(a, b, vert1, vert2)) { inside = true; break; } if (Polygon.Intersects(a, c, vert1, vert2)) { inside = true; break; } if (Polygon.Intersects(c, d, vert1, vert2)) { inside = true; break; } if (Polygon.Intersects(d, b, vert1, vert2)) { inside = true; break; } } if (node.ContainsPoint(a) || node.ContainsPoint(b) || node.ContainsPoint(c) || node.ContainsPoint(d)) { inside = true; } if (!inside) { return(true); } o.WillUpdateNode(node); o.Apply(node); return(true); }); }
public static void UpdateArea (GraphUpdateObject o, INavmesh graph) { Bounds bounds = o.bounds; // Bounding rectangle with floating point coordinates Rect r = Rect.MinMaxRect (bounds.min.x,bounds.min.z,bounds.max.x,bounds.max.z); // Bounding rectangle with int coordinates var r2 = new IntRect( Mathf.FloorToInt(bounds.min.x*Int3.Precision), Mathf.FloorToInt(bounds.min.z*Int3.Precision), Mathf.FloorToInt(bounds.max.x*Int3.Precision), Mathf.FloorToInt(bounds.max.z*Int3.Precision) ); // Corners of the bounding rectangle var a = new Int3(r2.xmin,0,r2.ymin); var b = new Int3(r2.xmin,0,r2.ymax); var c = new Int3(r2.xmax,0,r2.ymin); var d = new Int3(r2.xmax,0,r2.ymax); var ymin = ((Int3)bounds.min).y; var ymax = ((Int3)bounds.max).y; // Loop through all nodes graph.GetNodes (_node => { var node = _node as TriangleMeshNode; bool inside = false; int allLeft = 0; int allRight = 0; int allTop = 0; int allBottom = 0; // Check bounding box rect in XZ plane for (int v=0;v<3;v++) { Int3 p = node.GetVertex(v); var vert = (Vector3)p; if (r2.Contains (p.x,p.z)) { inside = true; break; } if (vert.x < r.xMin) allLeft++; if (vert.x > r.xMax) allRight++; if (vert.z < r.yMin) allTop++; if (vert.z > r.yMax) allBottom++; } if (!inside) { if (allLeft == 3 || allRight == 3 || allTop == 3 || allBottom == 3) { return true; } } // Check if the polygon edges intersect the bounding rect for (int v = 0; v < 3; v++) { int v2 = v > 1 ? 0 : v+1; Int3 vert1 = node.GetVertex(v); Int3 vert2 = node.GetVertex(v2); if (Polygon.Intersects (a,b,vert1,vert2)) { inside = true; break; } if (Polygon.Intersects (a,c,vert1,vert2)) { inside = true; break; } if (Polygon.Intersects (c,d,vert1,vert2)) { inside = true; break; } if (Polygon.Intersects (d,b,vert1,vert2)) { inside = true; break; } } // Check if the node contains any corner of the bounding rect if (inside || node.ContainsPoint (a) || node.ContainsPoint (b) || node.ContainsPoint (c) || node.ContainsPoint (d)) { inside = true; } if (!inside) { return true; } int allAbove = 0; int allBelow = 0; // Check y coordinate for (int v = 0; v < 3; v++) { Int3 p = node.GetVertex(v); var vert = (Vector3)p; if (vert.y < ymin) allBelow++; if (vert.y > ymax) allAbove++; } // Polygon is either completely above the bounding box or completely below it if (allBelow == 3 || allAbove == 3) return true; // Triangle is inside the bounding box! // Update it! o.WillUpdateNode(node); o.Apply (node); return true; }); }
/// <summary>Creates a list for every tile and adds every mesh that touches a tile to the corresponding list</summary> List <RasterizationMesh>[] PutMeshesIntoTileBuckets(List <RasterizationMesh> meshes, IntRect tileBuckets) { var bucketCount = tileBuckets.Width * tileBuckets.Height; var result = new List <RasterizationMesh> [bucketCount]; var borderExpansion = new Vector3(1, 0, 1) * TileBorderSizeInWorldUnits * 2; for (int i = 0; i < result.Length; i++) { result[i] = ListPool <RasterizationMesh> .Claim(); } var offset = new Int2(-tileBuckets.xmin, -tileBuckets.ymin); var clamp = new IntRect(0, 0, tileBuckets.Width - 1, tileBuckets.Height - 1); for (int i = 0; i < meshes.Count; i++) { var mesh = meshes[i]; var bounds = mesh.bounds; // Expand borderSize voxels on each side bounds.Expand(borderExpansion); var rect = GetTouchingTiles(bounds); rect = IntRect.Intersection(rect.Offset(offset), clamp); for (int z = rect.ymin; z <= rect.ymax; z++) { for (int x = rect.xmin; x <= rect.xmax; x++) { result[x + z * tileBuckets.Width].Add(mesh); } } } return(result); }
private static int ExpansionRequired(IntRect r, IntRect r2) { int num = Math.Min(r.xmin, r2.xmin); int num2 = Math.Max(r.xmax, r2.xmax); int num3 = Math.Min(r.ymin, r2.ymin); int num4 = Math.Max(r.ymax, r2.ymax); return (num2 - num) * (num4 - num3) - BBTree.RectArea(r); }
public static void UpdateArea(GraphUpdateObject o, INavmesh graph) { //System.DateTime startTime = System.DateTime.UtcNow; Bounds bounds = o.bounds; Rect r = Rect.MinMaxRect(bounds.min.x, bounds.min.z, bounds.max.x, bounds.max.z); IntRect r2 = new IntRect( Mathf.FloorToInt(bounds.min.x * Int3.Precision), Mathf.FloorToInt(bounds.min.z * Int3.Precision), Mathf.FloorToInt(bounds.max.x * Int3.Precision), Mathf.FloorToInt(bounds.max.z * Int3.Precision) ); /*Vector3 a = new Vector3 (r.xMin,0,r.yMin);// -1 -1 * Vector3 b = new Vector3 (r.xMin,0,r.yMax);// -1 1 * Vector3 c = new Vector3 (r.xMax,0,r.yMin);// 1 -1 * Vector3 d = new Vector3 (r.xMax,0,r.yMax);// 1 1 */ Int3 a = new Int3(r2.xmin, 0, r2.ymin); Int3 b = new Int3(r2.xmin, 0, r2.ymax); Int3 c = new Int3(r2.xmax, 0, r2.ymin); Int3 d = new Int3(r2.xmax, 0, r2.ymax); Int3 ia = (Int3)a; Int3 ib = (Int3)b; Int3 ic = (Int3)c; Int3 id = (Int3)d; //for (int i=0;i<nodes.Length;i++) { graph.GetNodes(delegate(GraphNode _node) { TriangleMeshNode node = _node as TriangleMeshNode; bool inside = false; int allLeft = 0; int allRight = 0; int allTop = 0; int allBottom = 0; for (int v = 0; v < 3; v++) { Int3 p = node.GetVertex(v); Vector3 vert = (Vector3)p; //Vector2 vert2D = new Vector2 (vert.x,vert.z); if (r2.Contains(p.x, p.z)) { //Debug.DrawRay (vert,Vector3.up*10,Color.yellow); inside = true; break; } if (vert.x < r.xMin) { allLeft++; } if (vert.x > r.xMax) { allRight++; } if (vert.z < r.yMin) { allTop++; } if (vert.z > r.yMax) { allBottom++; } //if (!bounds.Contains (node[v]) { // inside = false; // break; //} } if (!inside) { if (allLeft == 3 || allRight == 3 || allTop == 3 || allBottom == 3) { return(true); } } //Debug.DrawLine ((Vector3)node.GetVertex(0),(Vector3)node.GetVertex(1),Color.yellow); //Debug.DrawLine ((Vector3)node.GetVertex(1),(Vector3)node.GetVertex(2),Color.yellow); //Debug.DrawLine ((Vector3)node.GetVertex(2),(Vector3)node.GetVertex(0),Color.yellow); for (int v = 0; v < 3; v++) { int v2 = v > 1 ? 0 : v + 1; Int3 vert1 = node.GetVertex(v); Int3 vert2 = node.GetVertex(v2); if (Polygon.Intersects(a, b, vert1, vert2)) { inside = true; break; } if (Polygon.Intersects(a, c, vert1, vert2)) { inside = true; break; } if (Polygon.Intersects(c, d, vert1, vert2)) { inside = true; break; } if (Polygon.Intersects(d, b, vert1, vert2)) { inside = true; break; } } if (node.ContainsPoint(ia) || node.ContainsPoint(ib) || node.ContainsPoint(ic) || node.ContainsPoint(id)) { inside = true; } if (!inside) { return(true); } o.WillUpdateNode(node); o.Apply(node); /*Debug.DrawLine ((Vector3)node.GetVertex(0),(Vector3)node.GetVertex(1),Color.blue); * Debug.DrawLine ((Vector3)node.GetVertex(1),(Vector3)node.GetVertex(2),Color.blue); * Debug.DrawLine ((Vector3)node.GetVertex(2),(Vector3)node.GetVertex(0),Color.blue); * Debug.Break ();*/ return(true); }); //System.DateTime endTime = System.DateTime.UtcNow; //float theTime = (endTime-startTime).Ticks*0.0001F; //Debug.Log ("Intersecting bounds with navmesh took "+theTime.ToString ("0.000")+" ms"); }
private int GetBox(IntRect rect) { if (this.count >= this.arr.Length) { this.EnsureCapacity(this.count + 1); } this.arr[this.count] = new BBTree.BBTreeBox(rect); this.count++; return this.count - 1; }
public void AddNeighboursRec(List <QuadtreeNode> arr, QuadtreeNodeHolder holder, int depth, int x, int y, IntRect bounds, QuadtreeNode dontInclude) { int num = 1 << Math.Min(this.editorHeightLog2, this.editorWidthLog2) - depth; IntRect a = new IntRect(x, y, x + num, y + num); if (!IntRect.Intersects(a, bounds)) { return; } if (holder.node != null) { if (holder.node != dontInclude) { arr.Add(holder.node); } } else { this.AddNeighboursRec(arr, holder.c0, depth + 1, x, y, bounds, dontInclude); this.AddNeighboursRec(arr, holder.c1, depth + 1, x + num / 2, y, bounds, dontInclude); this.AddNeighboursRec(arr, holder.c2, depth + 1, x + num / 2, y + num / 2, bounds, dontInclude); this.AddNeighboursRec(arr, holder.c3, depth + 1, x, y + num / 2, bounds, dontInclude); } }
public BBTreeBox(MeshNode node) { this.node = node; Int3 vertex = node.GetVertex(0); Int2 @int = new Int2(vertex.x, vertex.z); Int2 int2 = @int; for (int i = 1; i < node.GetVertexCount(); i++) { Int3 vertex2 = node.GetVertex(i); @int.x = Math.Min(@int.x, vertex2.x); @int.y = Math.Min(@int.y, vertex2.z); int2.x = Math.Max(int2.x, vertex2.x); int2.y = Math.Max(int2.y, vertex2.z); } this.rect = new IntRect(@int.x, @int.y, int2.x, int2.y); this.left = (this.right = -1); }
public BBTreeBox(IntRect rect) { this.nodeOffset = -1; this.rect = rect; this.left = (this.right = -1); }
/** Returns a rect containing the indices of all tiles by rounding the specified bounds to tile borders */ public IntRect GetTouchingTilesRound ( Bounds b ) { b.center -= forcedBounds.min; //Calculate world bounds of all affected tiles var r = new IntRect (Mathf.RoundToInt (b.min.x / (tileSizeX*cellSize)), Mathf.RoundToInt (b.min.z / (tileSizeZ*cellSize)), Mathf.RoundToInt (b.max.x / (tileSizeX*cellSize))-1, Mathf.RoundToInt (b.max.z / (tileSizeZ*cellSize))-1); //Clamp to bounds r = IntRect.Intersection (r, new IntRect (0,0,tileXCount-1,tileZCount-1)); return r; }
public static void UpdateArea(GraphUpdateObject o, INavmeshHolder graph) { Bounds bounds = graph.transform.InverseTransform(o.bounds); // Bounding rectangle with integer coordinates var irect = new IntRect( Mathf.FloorToInt(bounds.min.x * Int3.Precision), Mathf.FloorToInt(bounds.min.z * Int3.Precision), Mathf.CeilToInt(bounds.max.x * Int3.Precision), Mathf.CeilToInt(bounds.max.z * Int3.Precision) ); // Corners of the bounding rectangle var a = new Int3(irect.xmin, 0, irect.ymin); var b = new Int3(irect.xmin, 0, irect.ymax); var c = new Int3(irect.xmax, 0, irect.ymin); var d = new Int3(irect.xmax, 0, irect.ymax); var ymin = ((Int3)bounds.min).y; var ymax = ((Int3)bounds.max).y; // Loop through all nodes and check if they intersect the bounding box graph.GetNodes(_node => { var node = _node as TriangleMeshNode; bool inside = false; int allLeft = 0; int allRight = 0; int allTop = 0; int allBottom = 0; // Check bounding box rect in XZ plane for (int v = 0; v < 3; v++) { Int3 p = node.GetVertexInGraphSpace(v); if (irect.Contains(p.x, p.z)) { inside = true; break; } if (p.x < irect.xmin) { allLeft++; } if (p.x > irect.xmax) { allRight++; } if (p.z < irect.ymin) { allTop++; } if (p.z > irect.ymax) { allBottom++; } } if (!inside && (allLeft == 3 || allRight == 3 || allTop == 3 || allBottom == 3)) { return; } // Check if the polygon edges intersect the bounding rect for (int v = 0; v < 3; v++) { int v2 = v > 1 ? 0 : v + 1; Int3 vert1 = node.GetVertexInGraphSpace(v); Int3 vert2 = node.GetVertexInGraphSpace(v2); if (VectorMath.SegmentsIntersectXZ(a, b, vert1, vert2)) { inside = true; break; } if (VectorMath.SegmentsIntersectXZ(a, c, vert1, vert2)) { inside = true; break; } if (VectorMath.SegmentsIntersectXZ(c, d, vert1, vert2)) { inside = true; break; } if (VectorMath.SegmentsIntersectXZ(d, b, vert1, vert2)) { inside = true; break; } } // Check if the node contains any corner of the bounding rect if (inside || node.ContainsPointInGraphSpace(a) || node.ContainsPointInGraphSpace(b) || node.ContainsPointInGraphSpace(c) || node.ContainsPointInGraphSpace(d)) { inside = true; } if (!inside) { return; } int allAbove = 0; int allBelow = 0; // Check y coordinate for (int v = 0; v < 3; v++) { Int3 p = node.GetVertexInGraphSpace(v); if (p.y < ymin) { allBelow++; } if (p.y > ymax) { allAbove++; } } // Polygon is either completely above the bounding box or completely below it if (allBelow == 3 || allAbove == 3) { return; } // Triangle is inside the bounding box! // Update it! o.WillUpdateNode(node); o.Apply(node); }); }
public BBTreeBox (IntRect rect) { node = null; this.rect = rect; left = right = -1; }
/// <summary>Async method for moving the graph</summary> IEnumerator UpdateGraphCoroutine() { // Find the direction that we want to move the graph in. // Calcuculate this in graph space (where a distance of one is the size of one node) Vector3 dir = PointToGraphSpace(target.position) - PointToGraphSpace(graph.center); // Snap to a whole number of nodes dir.x = Mathf.Round(dir.x); dir.z = Mathf.Round(dir.z); dir.y = 0; // Nothing do to if (dir == Vector3.zero) { yield break; } // Number of nodes to offset in each direction Int2 offset = new Int2(-Mathf.RoundToInt(dir.x), -Mathf.RoundToInt(dir.z)); // Move the center (this is in world units, so we need to convert it back from graph space) graph.center += graph.transform.TransformVector(dir); graph.UpdateTransform(); // Cache some variables for easier access int width = graph.width; int depth = graph.depth; GridNodeBase[] nodes; // Layers are required when handling LayeredGridGraphs int layers = graph.LayerCount; nodes = graph.nodes; // Create a temporary buffer required for the calculations if (buffer == null || buffer.Length != width * depth) { buffer = new GridNodeBase[width * depth]; } // Check if we have moved less than a whole graph width all directions // If we have moved more than this we can just as well recalculate the whole graph if (Mathf.Abs(offset.x) <= width && Mathf.Abs(offset.y) <= depth) { IntRect recalculateRect = new IntRect(0, 0, offset.x, offset.y); // If offset.x < 0, adjust the rect if (recalculateRect.xmin > recalculateRect.xmax) { int tmp2 = recalculateRect.xmax; recalculateRect.xmax = width + recalculateRect.xmin; recalculateRect.xmin = width + tmp2; } // If offset.y < 0, adjust the rect if (recalculateRect.ymin > recalculateRect.ymax) { int tmp2 = recalculateRect.ymax; recalculateRect.ymax = depth + recalculateRect.ymin; recalculateRect.ymin = depth + tmp2; } // Connections need to be recalculated for the neighbours as well, so we need to expand the rect by 1 var connectionRect = recalculateRect.Expand(1); // Makes sure the rect stays inside the grid connectionRect = IntRect.Intersection(connectionRect, new IntRect(0, 0, width, depth)); // Offset each node by the #offset variable // nodes which would end up outside the graph // will wrap around to the other side of it for (int l = 0; l < layers; l++) { int layerOffset = l * width * depth; for (int z = 0; z < depth; z++) { int pz = z * width; int tz = ((z + offset.y + depth) % depth) * width; for (int x = 0; x < width; x++) { buffer[tz + ((x + offset.x + width) % width)] = nodes[layerOffset + pz + x]; } } yield return(null); // Copy the nodes back to the graph // and set the correct indices for (int z = 0; z < depth; z++) { int pz = z * width; for (int x = 0; x < width; x++) { int newIndex = pz + x; var node = buffer[newIndex]; if (node != null) { node.NodeInGridIndex = newIndex; } nodes[layerOffset + newIndex] = node; } // Calculate the limits for the region that has been wrapped // to the other side of the graph int xmin, xmax; if (z >= recalculateRect.ymin && z < recalculateRect.ymax) { xmin = 0; xmax = depth; } else { xmin = recalculateRect.xmin; xmax = recalculateRect.xmax; } for (int x = xmin; x < xmax; x++) { var node = buffer[pz + x]; if (node != null) { // Clear connections on all nodes that are wrapped and placed on the other side of the graph. // This is both to clear any custom connections (which do not really make sense after moving the node) // and to prevent possible exceptions when the node will later (possibly) be destroyed because it was // not needed anymore (only for layered grid graphs). node.ClearConnections(false); } } } yield return(null); } // The calculation will only update approximately this number of // nodes per frame. This is used to keep CPU load per frame low int yieldEvery = 1000; // To avoid the update taking too long, make yieldEvery somewhat proportional to the number of nodes that we are going to update int approxNumNodesToUpdate = Mathf.Max(Mathf.Abs(offset.x), Mathf.Abs(offset.y)) * Mathf.Max(width, depth); yieldEvery = Mathf.Max(yieldEvery, approxNumNodesToUpdate / 10); int counter = 0; // Recalculate the nodes // Take a look at the image in the docs for the UpdateGraph method // to see which nodes are being recalculated. for (int z = 0; z < depth; z++) { int xmin, xmax; if (z >= recalculateRect.ymin && z < recalculateRect.ymax) { xmin = 0; xmax = width; } else { xmin = recalculateRect.xmin; xmax = recalculateRect.xmax; } for (int x = xmin; x < xmax; x++) { graph.RecalculateCell(x, z, false, false); } counter += (xmax - xmin); if (counter > yieldEvery) { counter = 0; yield return(null); } } for (int z = 0; z < depth; z++) { int xmin, xmax; if (z >= connectionRect.ymin && z < connectionRect.ymax) { xmin = 0; xmax = width; } else { xmin = connectionRect.xmin; xmax = connectionRect.xmax; } for (int x = xmin; x < xmax; x++) { graph.CalculateConnections(x, z); } counter += (xmax - xmin); if (counter > yieldEvery) { counter = 0; yield return(null); } } yield return(null); // Calculate all connections for the nodes along the boundary // of the graph, these always need to be updated /// <summary>TODO: Optimize to not traverse all nodes in the graph, only those at the edges</summary> for (int z = 0; z < depth; z++) { for (int x = 0; x < width; x++) { if (x == 0 || z == 0 || x == width - 1 || z == depth - 1) { graph.CalculateConnections(x, z); } } } } else { // The calculation will only update approximately this number of // nodes per frame. This is used to keep CPU load per frame low int yieldEvery = Mathf.Max(depth * width / 20, 1000); int counter = 0; // Just update all nodes for (int z = 0; z < depth; z++) { for (int x = 0; x < width; x++) { graph.RecalculateCell(x, z); } counter += width; if (counter > yieldEvery) { counter = 0; yield return(null); } } // Recalculate the connections of all nodes for (int z = 0; z < depth; z++) { for (int x = 0; x < width; x++) { graph.CalculateConnections(x, z); } counter += width; if (counter > yieldEvery) { counter = 0; yield return(null); } } } }
/** Returns true if \a p is within \a radius from \a r. * Correctly handles cases where \a radius is positive infinity. */ static bool RectIntersectsCircle (IntRect r, Vector3 p, float radius) { if (float.IsPositiveInfinity(radius)) return true; Vector3 po = p; p.x = Math.Max (p.x, r.xmin*Int3.PrecisionFactor); p.x = Math.Min (p.x, r.xmax*Int3.PrecisionFactor); p.z = Math.Max (p.z, r.ymin*Int3.PrecisionFactor); p.z = Math.Min (p.z, r.ymax*Int3.PrecisionFactor); // XZ squared magnitude comparison return (p.x-po.x)*(p.x-po.x) + (p.z-po.z)*(p.z-po.z) < radius*radius; }
public static void UpdateArea(GraphUpdateObject o, INavmesh graph) { Bounds bounds = o.bounds; // Bounding rectangle with floating point coordinates Rect r = Rect.MinMaxRect(bounds.min.x, bounds.min.z, bounds.max.x, bounds.max.z); // Bounding rectangle with int coordinates var r2 = new IntRect( Mathf.FloorToInt(bounds.min.x * Int3.Precision), Mathf.FloorToInt(bounds.min.z * Int3.Precision), Mathf.FloorToInt(bounds.max.x * Int3.Precision), Mathf.FloorToInt(bounds.max.z * Int3.Precision) ); // Corners of the bounding rectangle var a = new Int3(r2.xmin, 0, r2.ymin); var b = new Int3(r2.xmin, 0, r2.ymax); var c = new Int3(r2.xmax, 0, r2.ymin); var d = new Int3(r2.xmax, 0, r2.ymax); var ymin = ((Int3)bounds.min).y; var ymax = ((Int3)bounds.max).y; // Loop through all nodes graph.GetNodes(_node => { var node = _node as TriangleMeshNode; bool inside = false; int allLeft = 0; int allRight = 0; int allTop = 0; int allBottom = 0; // Check bounding box rect in XZ plane for (int v = 0; v < 3; v++) { Int3 p = node.GetVertex(v); var vert = (Vector3)p; if (r2.Contains(p.x, p.z)) { inside = true; break; } if (vert.x < r.xMin) { allLeft++; } if (vert.x > r.xMax) { allRight++; } if (vert.z < r.yMin) { allTop++; } if (vert.z > r.yMax) { allBottom++; } } if (!inside) { if (allLeft == 3 || allRight == 3 || allTop == 3 || allBottom == 3) { return(true); } } // Check if the polygon edges intersect the bounding rect for (int v = 0; v < 3; v++) { int v2 = v > 1 ? 0 : v + 1; Int3 vert1 = node.GetVertex(v); Int3 vert2 = node.GetVertex(v2); if (VectorMath.SegmentsIntersectXZ(a, b, vert1, vert2)) { inside = true; break; } if (VectorMath.SegmentsIntersectXZ(a, c, vert1, vert2)) { inside = true; break; } if (VectorMath.SegmentsIntersectXZ(c, d, vert1, vert2)) { inside = true; break; } if (VectorMath.SegmentsIntersectXZ(d, b, vert1, vert2)) { inside = true; break; } } // Check if the node contains any corner of the bounding rect if (inside || node.ContainsPoint(a) || node.ContainsPoint(b) || node.ContainsPoint(c) || node.ContainsPoint(d)) { inside = true; } if (!inside) { return(true); } int allAbove = 0; int allBelow = 0; // Check y coordinate for (int v = 0; v < 3; v++) { Int3 p = node.GetVertex(v); if (p.y < ymin) { allBelow++; } if (p.y > ymax) { allAbove++; } } // Polygon is either completely above the bounding box or completely below it if (allBelow == 3 || allAbove == 3) { return(true); } // Triangle is inside the bounding box! // Update it! o.WillUpdateNode(node); o.Apply(node); return(true); }); }
/** Returns a new rect which contains both \a r and \a r2 */ static IntRect ExpandToContain (IntRect r, IntRect r2) { return IntRect.Union(r,r2); }
public BBTreeBox(IntRect rect) { nodeOffset = -1; this.rect = rect; left = right = -1; }
public void AddNeighboursRec (List<QuadtreeNode> arr, QuadtreeNodeHolder holder, int depth, int x, int y, IntRect bounds, QuadtreeNode dontInclude) { var width = 1 << (Math.Min (editorHeightLog2,editorWidthLog2)-depth); var r = new IntRect(x,y,x+width,y+width); if (!IntRect.Intersects (r,bounds)) return; if (holder.node != null) { if (holder.node != dontInclude) { arr.Add (holder.node); } } else { AddNeighboursRec (arr, holder.c0, depth+1,x , y , bounds, dontInclude); AddNeighboursRec (arr, holder.c1, depth+1,x+width/2, y , bounds, dontInclude); AddNeighboursRec (arr, holder.c2, depth+1,x+width/2, y + width/2, bounds, dontInclude); AddNeighboursRec (arr, holder.c3, depth+1,x , y + width/2, bounds, dontInclude); } }
public BBTreeBox(int nodeOffset, IntRect rect) { this.nodeOffset = nodeOffset; this.rect = rect; left = right = -1; }
public void UpdateArea (GraphUpdateObject guo) { Bounds b = guo.bounds; b.center -= forcedBounds.min; //Figure out which tiles are affected IntRect r = new IntRect (Mathf.FloorToInt (b.min.x / (tileSizeX*cellSize)), Mathf.FloorToInt (b.min.z / (tileSizeZ*cellSize)), Mathf.FloorToInt (b.max.x / (tileSizeX*cellSize)), Mathf.FloorToInt (b.max.z / (tileSizeZ*cellSize))); //Clamp to bounds r = IntRect.Intersection (r, new IntRect (0,0,tileXCount-1,tileZCount-1)); if (!guo.updatePhysics) { for ( int z=r.ymin;z<=r.ymax;z++) { for ( int x=r.xmin;x<=r.xmax;x++) { NavmeshTile tile = tiles[z*tileXCount + x]; tile.flag = true; } } for ( int z=r.ymin;z<=r.ymax;z++) { for ( int x=r.xmin;x<=r.xmax;x++) { NavmeshTile tile = tiles[z*tileXCount + x]; if ( tile.flag ) { tile.flag = false; NavMeshGraph.UpdateArea (guo, tile); } } } return; } if (!dynamic) { throw new System.Exception ("Recast graph must be marked as dynamic to enable graph updates with updatePhysics = true"); } Voxelize vox = globalVox; if (vox == null) { throw new System.InvalidOperationException ("No Voxelizer object. UpdateAreaInit should have been called before this function."); } AstarProfiler.StartProfile ("Init"); /** \bug No bounds checking */ //r.DebugDraw (Matrix4x4.TRS (forcedBounds.min, Quaternion.identity, new Vector3 (tileSize*cellSize, 1, tileSize*cellSize)), Color.red); //Debug.Break (); AstarProfiler.StartProfile ("RemoveConnections"); for (int x=r.xmin;x<=r.xmax;x++) { for (int z=r.ymin;z<=r.ymax;z++) { RemoveConnectionsFromTile (tiles[x + z*tileXCount]); } } AstarProfiler.EndProfile ("RemoveConnections"); AstarProfiler.StartProfile ("Build Tiles"); for (int x=r.xmin;x<=r.xmax;x++) { for (int z=r.ymin;z<=r.ymax;z++) { BuildTileMesh (vox, x,z); } } AstarProfiler.EndProfile ("Build Tiles"); AstarProfiler.StartProfile ("ConnectTiles"); uint graphIndex = (uint)AstarPath.active.astarData.GetGraphIndex (this); for (int x=r.xmin;x<=r.xmax;x++) { for (int z=r.ymin;z<=r.ymax;z++) { NavmeshTile tile = tiles[x + z*tileXCount]; GraphNode[] nodes = tile.nodes; for (int i=0;i<nodes.Length;i++) nodes[i].GraphIndex = graphIndex; } } //Connect the newly create tiles with the old tiles and with each other r = r.Expand (1); //Clamp to bounds r = IntRect.Intersection (r, new IntRect (0,0,tileXCount-1,tileZCount-1)); for (int x=r.xmin;x<=r.xmax;x++) { for (int z=r.ymin;z<=r.ymax;z++) { if (x < tileXCount-1 && r.Contains (x+1, z)) { ConnectTiles (tiles[x + z*tileXCount], tiles[x+1 + z*tileXCount]); } if (z < tileZCount-1 && r.Contains (x, z+1)) { ConnectTiles (tiles[x + z*tileXCount], tiles[x + (z+1)*tileXCount]); } } } AstarProfiler.EndProfile ("ConnectTiles"); AstarProfiler.PrintResults (); }
public static void UpdateArea(GraphUpdateObject o, INavmesh graph) { Bounds bounds = o.bounds; Rect r = Rect.MinMaxRect(bounds.min.x, bounds.min.z, bounds.max.x, bounds.max.z); IntRect r2 = new IntRect(Mathf.FloorToInt(bounds.min.x * 1000f), Mathf.FloorToInt(bounds.min.z * 1000f), Mathf.FloorToInt(bounds.max.x * 1000f), Mathf.FloorToInt(bounds.max.z * 1000f)); VInt3 a = new VInt3(r2.xmin, 0, r2.ymin); VInt3 b = new VInt3(r2.xmin, 0, r2.ymax); VInt3 c = new VInt3(r2.xmax, 0, r2.ymin); VInt3 d = new VInt3(r2.xmax, 0, r2.ymax); VInt3 ia = a; VInt3 ib = b; VInt3 ic = c; VInt3 id = d; graph.GetNodes(delegate(GraphNode _node) { TriangleMeshNode triangleMeshNode = _node as TriangleMeshNode; bool flag = false; int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; for (int i = 0; i < 3; i++) { VInt3 vertex = triangleMeshNode.GetVertex(i); Vector3 vector = (Vector3)vertex; if (r2.Contains(vertex.x, vertex.z)) { flag = true; break; } if (vector.x < r.xMin) { num++; } if (vector.x > r.xMax) { num2++; } if (vector.z < r.yMin) { num3++; } if (vector.z > r.yMax) { num4++; } } if (!flag && (num == 3 || num2 == 3 || num3 == 3 || num4 == 3)) { return(true); } for (int j = 0; j < 3; j++) { int i2 = (j > 1) ? 0 : (j + 1); VInt3 vertex2 = triangleMeshNode.GetVertex(j); VInt3 vertex3 = triangleMeshNode.GetVertex(i2); if (Polygon.Intersects(a, b, vertex2, vertex3)) { flag = true; break; } if (Polygon.Intersects(a, c, vertex2, vertex3)) { flag = true; break; } if (Polygon.Intersects(c, d, vertex2, vertex3)) { flag = true; break; } if (Polygon.Intersects(d, b, vertex2, vertex3)) { flag = true; break; } } if (triangleMeshNode.ContainsPoint(ia) || triangleMeshNode.ContainsPoint(ib) || triangleMeshNode.ContainsPoint(ic) || triangleMeshNode.ContainsPoint(id)) { flag = true; } if (!flag) { return(true); } o.WillUpdateNode(triangleMeshNode); o.Apply(triangleMeshNode); return(true); }); }
public static void UpdateArea (GraphUpdateObject o, INavmesh graph) { //System.DateTime startTime = System.DateTime.UtcNow; Bounds bounds = o.bounds; Rect r = Rect.MinMaxRect (bounds.min.x,bounds.min.z,bounds.max.x,bounds.max.z); IntRect r2 = new IntRect( Mathf.FloorToInt(bounds.min.x*Int3.Precision), Mathf.FloorToInt(bounds.min.z*Int3.Precision), Mathf.FloorToInt(bounds.max.x*Int3.Precision), Mathf.FloorToInt(bounds.max.z*Int3.Precision) ); /*Vector3 a = new Vector3 (r.xMin,0,r.yMin);// -1 -1 Vector3 b = new Vector3 (r.xMin,0,r.yMax);// -1 1 Vector3 c = new Vector3 (r.xMax,0,r.yMin);// 1 -1 Vector3 d = new Vector3 (r.xMax,0,r.yMax);// 1 1 */ Int3 a = new Int3(r2.xmin,0,r2.ymin); Int3 b = new Int3(r2.xmin,0,r2.ymax); Int3 c = new Int3(r2.xmax,0,r2.ymin); Int3 d = new Int3(r2.xmax,0,r2.ymax); Int3 ia = (Int3)a; Int3 ib = (Int3)b; Int3 ic = (Int3)c; Int3 id = (Int3)d; #if ASTARDEBUG Debug.DrawLine (a,b,Color.white); Debug.DrawLine (a,c,Color.white); Debug.DrawLine (c,d,Color.white); Debug.DrawLine (d,b,Color.white); #endif //for (int i=0;i<nodes.Length;i++) { graph.GetNodes (delegate (GraphNode _node) { TriangleMeshNode node = _node as TriangleMeshNode; bool inside = false; int allLeft = 0; int allRight = 0; int allTop = 0; int allBottom = 0; for (int v=0;v<3;v++) { Int3 p = node.GetVertex(v); Vector3 vert = (Vector3)p; //Vector2 vert2D = new Vector2 (vert.x,vert.z); if (r2.Contains (p.x,p.z)) { //Debug.DrawRay (vert,Vector3.up*10,Color.yellow); inside = true; break; } if (vert.x < r.xMin) allLeft++; if (vert.x > r.xMax) allRight++; if (vert.z < r.yMin) allTop++; if (vert.z > r.yMax) allBottom++; //if (!bounds.Contains (node[v]) { // inside = false; // break; //} } if (!inside) { if (allLeft == 3 || allRight == 3 || allTop == 3 || allBottom == 3) { return true; } } //Debug.DrawLine ((Vector3)node.GetVertex(0),(Vector3)node.GetVertex(1),Color.yellow); //Debug.DrawLine ((Vector3)node.GetVertex(1),(Vector3)node.GetVertex(2),Color.yellow); //Debug.DrawLine ((Vector3)node.GetVertex(2),(Vector3)node.GetVertex(0),Color.yellow); for (int v=0;v<3;v++) { int v2 = v > 1 ? 0 : v+1; Int3 vert1 = node.GetVertex(v); Int3 vert2 = node.GetVertex(v2); if (Polygon.Intersects (a,b,vert1,vert2)) { inside = true; break; } if (Polygon.Intersects (a,c,vert1,vert2)) { inside = true; break; } if (Polygon.Intersects (c,d,vert1,vert2)) { inside = true; break; } if (Polygon.Intersects (d,b,vert1,vert2)) { inside = true; break; } } if (node.ContainsPoint (ia) || node.ContainsPoint (ib) || node.ContainsPoint (ic) || node.ContainsPoint (id)) { inside = true; } if (!inside) { return true; } o.WillUpdateNode(node); o.Apply (node); /*Debug.DrawLine ((Vector3)node.GetVertex(0),(Vector3)node.GetVertex(1),Color.blue); Debug.DrawLine ((Vector3)node.GetVertex(1),(Vector3)node.GetVertex(2),Color.blue); Debug.DrawLine ((Vector3)node.GetVertex(2),(Vector3)node.GetVertex(0),Color.blue); Debug.Break ();*/ return true; }); //System.DateTime endTime = System.DateTime.UtcNow; //float theTime = (endTime-startTime).Ticks*0.0001F; //Debug.Log ("Intersecting bounds with navmesh took "+theTime.ToString ("0.000")+" ms"); }
public static void UpdateArea(GraphUpdateObject o, INavmesh graph) { Bounds bounds = o.bounds; Rect rect = Rect.MinMaxRect(bounds.min.x, bounds.min.z, bounds.max.x, bounds.max.z); IntRect irect = new IntRect(Mathf.FloorToInt(bounds.min.x * 1000f), Mathf.FloorToInt(bounds.min.z * 1000f), Mathf.FloorToInt(bounds.max.x * 1000f), Mathf.FloorToInt(bounds.max.z * 1000f)); Int3 a = new Int3(irect.xmin, 0, irect.ymin); Int3 b = new Int3(irect.xmin, 0, irect.ymax); Int3 c = new Int3(irect.xmax, 0, irect.ymin); Int3 d = new Int3(irect.xmax, 0, irect.ymax); int ymin = ((Int3)bounds.min).y; int ymax = ((Int3)bounds.max).y; graph.GetNodes(delegate(GraphNode _node) { TriangleMeshNode triangleMeshNode = _node as TriangleMeshNode; bool flag = false; int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; for (int i = 0; i < 3; i++) { Int3 vertex = triangleMeshNode.GetVertex(i); Vector3 vector = (Vector3)vertex; if (irect.Contains(vertex.x, vertex.z)) { flag = true; break; } if (vector.x < rect.xMin) { num++; } if (vector.x > rect.xMax) { num2++; } if (vector.z < rect.yMin) { num3++; } if (vector.z > rect.yMax) { num4++; } } if (!flag && (num == 3 || num2 == 3 || num3 == 3 || num4 == 3)) { return; } for (int j = 0; j < 3; j++) { int i2 = (j <= 1) ? (j + 1) : 0; Int3 vertex2 = triangleMeshNode.GetVertex(j); Int3 vertex3 = triangleMeshNode.GetVertex(i2); if (VectorMath.SegmentsIntersectXZ(a, b, vertex2, vertex3)) { flag = true; break; } if (VectorMath.SegmentsIntersectXZ(a, c, vertex2, vertex3)) { flag = true; break; } if (VectorMath.SegmentsIntersectXZ(c, d, vertex2, vertex3)) { flag = true; break; } if (VectorMath.SegmentsIntersectXZ(d, b, vertex2, vertex3)) { flag = true; break; } } if (flag || triangleMeshNode.ContainsPoint(a) || triangleMeshNode.ContainsPoint(b) || triangleMeshNode.ContainsPoint(c) || triangleMeshNode.ContainsPoint(d)) { flag = true; } if (!flag) { return; } int num5 = 0; int num6 = 0; for (int k = 0; k < 3; k++) { Int3 vertex4 = triangleMeshNode.GetVertex(k); if (vertex4.y < ymin) { num6++; } if (vertex4.y > ymax) { num5++; } } if (num6 == 3 || num5 == 3) { return; } o.WillUpdateNode(triangleMeshNode); o.Apply(triangleMeshNode); }); }
/** Returns a new rect which contains both input rects. * This rectangle may contain areas outside both input rects as well in some cases. */ public static IntRect Union (IntRect a, IntRect b) { var r = new IntRect( System.Math.Min(a.xmin,b.xmin), System.Math.Min(a.ymin,b.ymin), System.Math.Max(a.xmax,b.xmax), System.Math.Max(a.ymax,b.ymax) ); return r; }
public override bool Equals(System.Object _b) { IntRect b = (IntRect)_b; return(xmin == b.xmin && xmax == b.xmax && ymin == b.ymin && ymax == b.ymax); }
public new void UpdateArea(GraphUpdateObject o) { if (nodes == null || nodes.Length != width*depth*layerCount) { Debug.LogWarning ("The Grid Graph is not scanned, cannot update area "); //Not scanned return; } //Copy the bounds Bounds b = o.bounds; //Matrix inverse //node.position = matrix.MultiplyPoint3x4 (new Vector3 (x+0.5F,0,z+0.5F)); Vector3 min, max; GetBoundsMinMax (b,inverseMatrix,out min, out max); int minX = Mathf.RoundToInt (min.x-0.5F); int maxX = Mathf.RoundToInt (max.x-0.5F); int minZ = Mathf.RoundToInt (min.z-0.5F); int maxZ = Mathf.RoundToInt (max.z-0.5F); //We now have coordinates in local space (i.e 1 unit = 1 node) IntRect originalRect = new IntRect(minX,minZ,maxX,maxZ); IntRect affectRect = originalRect; IntRect gridRect = new IntRect(0,0,width-1,depth-1); IntRect physicsRect = originalRect; Matrix4x4 debugMatrix = matrix; debugMatrix *= Matrix4x4.TRS (new Vector3(0.5f,0,0.5f),Quaternion.identity,Vector3.one); #if ASTARDEBUG originalRect.DebugDraw (debugMatrix,Color.red); #endif bool willChangeWalkability = o.updatePhysics || o.modifyWalkability; bool willChangeNodeInstances = (o is LayerGridGraphUpdate ? ((LayerGridGraphUpdate)o).recalculateNodes : false); bool preserveExistingNodes = (o is LayerGridGraphUpdate ? ((LayerGridGraphUpdate)o).preserveExistingNodes : true); if (o.trackChangedNodes && willChangeNodeInstances) { Debug.LogError ("Cannot track changed nodes when creating or deleting nodes.\nWill not update LayerGridGraph"); return; } //Calculate the largest bounding box which might be affected if (o.updatePhysics && !o.modifyWalkability) { //Add the collision.diameter margin for physics calls if (collision.collisionCheck) { Vector3 margin = new Vector3 (collision.diameter,0,collision.diameter)*0.5F; min -= margin*1.02F;//0.02 safety margin, physics is rarely very accurate max += margin*1.02F; physicsRect = new IntRect( Mathf.RoundToInt (min.x-0.5F), Mathf.RoundToInt (min.z-0.5F), Mathf.RoundToInt (max.x-0.5F), Mathf.RoundToInt (max.z-0.5F) ); affectRect = IntRect.Union (physicsRect, affectRect); } } if (willChangeWalkability && erodeIterations > 0) { //Add affect radius for erosion. +1 for updating connectivity info at the border affectRect = affectRect.Expand (erodeIterations+1); } IntRect clampedRect = IntRect.Intersection (affectRect,gridRect); //Mark nodes that might be changed if (!willChangeNodeInstances) { for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) { for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) { for (int y=0;y<layerCount;y++) { o.WillUpdateNode (nodes[y*width*depth + z*width+x]); } } } } //Update Physics if (o.updatePhysics && !o.modifyWalkability) { collision.Initialize (matrix,nodeSize); clampedRect = IntRect.Intersection (physicsRect,gridRect); bool addedNodes = false; for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) { for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) { /** \todo FIX */ addedNodes |= RecalculateCell (x,z,preserveExistingNodes); } } for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) { for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) { for (int y=0;y<layerCount;y++) { int index = y*width*depth + z*width+x; LevelGridNode node = nodes[index] as LevelGridNode; if (node == null) continue; CalculateConnections (nodes,node,x,z,y); } } } if (addedNodes) { AstarPath.active.DataUpdate(); } } //Apply GUO clampedRect = IntRect.Intersection (originalRect, gridRect); for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) { for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) { for (int y=0;y<layerCount;y++) { int index = y*width*depth + z*width+x; LevelGridNode node = nodes[index] as LevelGridNode; if (node == null) continue; if (willChangeWalkability) { node.walkable = node.Bit15; o.Apply (node); node.Bit15 = node.walkable; } else { o.Apply (node); } } } } #if ASTARDEBUG physicsRect.DebugDraw (debugMatrix,Color.blue); affectRect.DebugDraw (debugMatrix,Color.black); #endif //Recalculate connections if (willChangeWalkability && erodeIterations == 0) { clampedRect = IntRect.Intersection (affectRect, gridRect); for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) { for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) { for (int y=0;y<layerCount;y++) { int index = y*width*depth + z*width+x; LevelGridNode node = nodes[index] as LevelGridNode; if (node == null) continue; CalculateConnections (nodes,node,x,z,y); } } } } else if (willChangeWalkability && erodeIterations > 0) { clampedRect = IntRect.Union (originalRect, physicsRect); IntRect erosionRect1 = clampedRect.Expand (erodeIterations); IntRect erosionRect2 = erosionRect1.Expand (erodeIterations); erosionRect1 = IntRect.Intersection (erosionRect1,gridRect); erosionRect2 = IntRect.Intersection (erosionRect2,gridRect); #if ASTARDEBUG erosionRect1.DebugDraw (debugMatrix,Color.magenta); erosionRect2.DebugDraw (debugMatrix,Color.cyan); #endif /* all nodes inside clampedRect might have had their walkability changed all nodes inside erosionRect1 might get affected by erosion from clampedRect and erosionRect2 all nodes inside erosionRect2 (but outside erosionRect1) will be reset to previous walkability after calculation since their erosion might not be correctly calculated (nodes outside erosionRect2 would maybe have effect) */ for (int x = erosionRect2.xmin; x <= erosionRect2.xmax;x++) { for (int z = erosionRect2.ymin;z <= erosionRect2.ymax;z++) { for (int y=0;y<layerCount;y++) { int index = y*width*depth + z*width+x; LevelGridNode node = nodes[index] as LevelGridNode; if (node == null) continue; bool tmp = node.walkable; node.walkable = node.Bit15; if (!erosionRect1.Contains (x,z)) { //Save the border's walkabilty data in bit 16 (will be reset later) node.Bit16 = tmp; } } } } for (int x = erosionRect2.xmin; x <= erosionRect2.xmax;x++) { for (int z = erosionRect2.ymin;z <= erosionRect2.ymax;z++) { for (int y=0;y<layerCount;y++) { int index = y*width*depth + z*width+x; LevelGridNode node = nodes[index] as LevelGridNode; if (node == null) continue; #if ASTARDEBUG if (!node.walkable) Debug.DrawRay ((Vector3)node.position, Vector3.up*2,Color.red); #endif CalculateConnections (nodes,node,x,z,y); } } } //Erode the walkable area ErodeWalkableArea (erosionRect2.xmin,erosionRect2.ymin,erosionRect2.xmax+1,erosionRect2.ymax+1); for (int x = erosionRect2.xmin; x <= erosionRect2.xmax;x++) { for (int z = erosionRect2.ymin;z <= erosionRect2.ymax;z++) { if (erosionRect1.Contains (x,z)) continue; for (int y=0;y<layerCount;y++) { int index = y*width*depth + z*width+x; LevelGridNode node = nodes[index] as LevelGridNode; if (node == null) continue; //Restore temporarily stored data node.walkable = node.Bit16; } } } //Recalculate connections of all affected nodes for (int x = erosionRect2.xmin; x <= erosionRect2.xmax;x++) { for (int z = erosionRect2.ymin;z <= erosionRect2.ymax;z++) { for (int y=0;y<layerCount;y++) { int index = y*width*depth + z*width+x; LevelGridNode node = nodes[index] as LevelGridNode; if (node == null) continue; CalculateConnections (nodes,node,x,z,y); } } } } //Debug.LogError ("No support for Graph Updates to Layered Grid Graphs"); }
public void AddNeighboursRec(List <QuadtreeNode> arr, QuadtreeNodeHolder holder, int depth, int x, int y, IntRect bounds, QuadtreeNode dontInclude) { int width = 1 << (System.Math.Min(editorHeightLog2, editorWidthLog2) - depth); var r = new IntRect(x, y, x + width, y + width); if (!IntRect.Intersects(r, bounds)) { return; } if (holder.node != null) { if (holder.node != dontInclude) { arr.Add(holder.node); } } else { AddNeighboursRec(arr, holder.c0, depth + 1, x, y, bounds, dontInclude); AddNeighboursRec(arr, holder.c1, depth + 1, x + width / 2, y, bounds, dontInclude); AddNeighboursRec(arr, holder.c2, depth + 1, x + width / 2, y + width / 2, bounds, dontInclude); AddNeighboursRec(arr, holder.c3, depth + 1, x, y + width / 2, bounds, dontInclude); } }
/** Internal function to update an area of the graph. */ public void UpdateArea (GraphUpdateObject o) { if (nodes == null || nodes.Length != width*depth) { Debug.LogWarning ("The Grid Graph is not scanned, cannot update area "); //Not scanned return; } //Copy the bounds Bounds b = o.bounds; Vector3 min, max; GetBoundsMinMax (b,inverseMatrix,out min, out max); int minX = Mathf.RoundToInt (min.x-0.5F); int maxX = Mathf.RoundToInt (max.x-0.5F); int minZ = Mathf.RoundToInt (min.z-0.5F); int maxZ = Mathf.RoundToInt (max.z-0.5F); //We now have coordinates in local space (i.e 1 unit = 1 node) IntRect originalRect = new IntRect(minX,minZ,maxX,maxZ); IntRect affectRect = originalRect; IntRect gridRect = new IntRect(0,0,width-1,depth-1); IntRect physicsRect = originalRect; int erosion = o.updateErosion ? erodeIterations : 0; #if ASTARDEBUG Matrix4x4 debugMatrix = matrix; debugMatrix *= Matrix4x4.TRS (new Vector3(0.5f,0,0.5f),Quaternion.identity,Vector3.one); originalRect.DebugDraw (debugMatrix,Color.red); #endif bool willChangeWalkability = o.updatePhysics || o.modifyWalkability; //Calculate the largest bounding box which might be affected if (o.updatePhysics && !o.modifyWalkability) { //Add the collision.diameter margin for physics calls if (collision.collisionCheck) { Vector3 margin = new Vector3 (collision.diameter,0,collision.diameter)*0.5F; min -= margin*1.02F;//0.02 safety margin, physics is rarely very accurate max += margin*1.02F; physicsRect = new IntRect( Mathf.RoundToInt (min.x-0.5F), Mathf.RoundToInt (min.z-0.5F), Mathf.RoundToInt (max.x-0.5F), Mathf.RoundToInt (max.z-0.5F) ); affectRect = IntRect.Union (physicsRect, affectRect); } } if (willChangeWalkability || erosion > 0) { //Add affect radius for erosion. +1 for updating connectivity info at the border affectRect = affectRect.Expand (erosion + 1); } IntRect clampedRect = IntRect.Intersection (affectRect,gridRect); //Mark nodes that might be changed for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) { for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) { o.WillUpdateNode (nodes[z*width+x]); } } //Update Physics if (o.updatePhysics && !o.modifyWalkability) { collision.Initialize (matrix,nodeSize); clampedRect = IntRect.Intersection (physicsRect,gridRect); for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) { for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) { int index = z*width+x; GridNode node = nodes[index]; UpdateNodePositionCollision (node,x,z, o.resetPenaltyOnPhysics); } } } //Apply GUO clampedRect = IntRect.Intersection (originalRect, gridRect); for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) { for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) { int index = z*width+x; GridNode node = nodes[index]; if (willChangeWalkability) { node.Walkable = node.WalkableErosion; if (o.bounds.Contains ((Vector3)node.position)) o.Apply (node); node.WalkableErosion = node.Walkable; } else { if (o.bounds.Contains ((Vector3)node.position)) o.Apply (node); } } } #if ASTARDEBUG physicsRect.DebugDraw (debugMatrix,Color.blue); affectRect.DebugDraw (debugMatrix,Color.black); #endif //Recalculate connections if (willChangeWalkability && erosion == 0) { clampedRect = IntRect.Intersection (affectRect, gridRect); for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) { for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) { int index = z*width+x; GridNode node = nodes[index]; CalculateConnections (nodes,x,z,node); } } } else if (willChangeWalkability && erosion > 0) { clampedRect = IntRect.Union (originalRect, physicsRect); IntRect erosionRect1 = clampedRect.Expand (erosion); IntRect erosionRect2 = erosionRect1.Expand (erosion); erosionRect1 = IntRect.Intersection (erosionRect1,gridRect); erosionRect2 = IntRect.Intersection (erosionRect2,gridRect); #if ASTARDEBUG erosionRect1.DebugDraw (debugMatrix,Color.magenta); erosionRect2.DebugDraw (debugMatrix,Color.cyan); #endif /* all nodes inside clampedRect might have had their walkability changed all nodes inside erosionRect1 might get affected by erosion from clampedRect and erosionRect2 all nodes inside erosionRect2 (but outside erosionRect1) will be reset to previous walkability after calculation since their erosion might not be correctly calculated (nodes outside erosionRect2 would maybe have effect) */ for (int x = erosionRect2.xmin; x <= erosionRect2.xmax;x++) { for (int z = erosionRect2.ymin;z <= erosionRect2.ymax;z++) { int index = z*width+x; GridNode node = nodes[index]; bool tmp = node.Walkable; node.Walkable = node.WalkableErosion; if (!erosionRect1.Contains (x,z)) { //Save the border's walkabilty data (will be reset later) node.TmpWalkable = tmp; } } } for (int x = erosionRect2.xmin; x <= erosionRect2.xmax;x++) { for (int z = erosionRect2.ymin;z <= erosionRect2.ymax;z++) { int index = z*width+x; GridNode node = nodes[index]; #if ASTARDEBUG if (!node.Walkable) Debug.DrawRay ((Vector3)node.position, Vector3.up*2,Color.red); #endif CalculateConnections (nodes,x,z,node); } } //Erode the walkable area ErodeWalkableArea (erosionRect2.xmin,erosionRect2.ymin,erosionRect2.xmax+1,erosionRect2.ymax+1); for (int x = erosionRect2.xmin; x <= erosionRect2.xmax;x++) { for (int z = erosionRect2.ymin;z <= erosionRect2.ymax;z++) { if (erosionRect1.Contains (x,z)) continue; int index = z*width+x; GridNode node = nodes[index]; //Restore temporarily stored data node.Walkable = node.TmpWalkable; } } //Recalculate connections of all affected nodes for (int x = erosionRect2.xmin; x <= erosionRect2.xmax;x++) { for (int z = erosionRect2.ymin;z <= erosionRect2.ymax;z++) { int index = z*width+x; GridNode node = nodes[index]; CalculateConnections (nodes,x,z,node); } } } }
public BBTreeBox(IntRect rect) { node = null; this.rect = rect; left = right = -1; }