/** Recalculates single cell. * * \param x X coordinate of the cell * \param z Z coordinate of the cell * \param preserveExistingNodes If true, nodes will be reused, this can be used to preserve e.g penalty when recalculating * * \returns If new layers or nodes were added. If so, you need to call * AstarPath.active.DataUpdate() after this function to make sure pathfinding works correctly for them * (when doing a scan, that function does not need to be called however). * * \note Connections are not recalculated for the nodes. */ public bool RecalculateCell (int x, int z, bool preserveExistingNodes) { var llc = new LinkedLevelCell (); Vector3 pos = matrix.MultiplyPoint3x4 (new Vector3 (x+0.5F,0,z+0.5F)); RaycastHit[] hits = collision.CheckHeightAll (pos); for (int i=0;i<hits.Length/2;i++) { RaycastHit tmp = hits[i]; hits[i] = hits[hits.Length-1-i]; hits[hits.Length-1-i] = tmp; } bool addedNodes = false; if (hits.Length > 0) { LinkedLevelNode lln = null; for (int i=0;i<hits.Length;i++) { var tmp = new LinkedLevelNode (); tmp.position = hits[i].point; if (lln != null) { /** \todo Use hit.distance instead */ if (tmp.position.y - lln.position.y <= mergeSpanRange) { lln.position = tmp.position; lln.hit = hits[i]; lln.walkable = collision.Check (tmp.position); continue; } } tmp.walkable = collision.Check (tmp.position); tmp.hit = hits[i]; tmp.height = float.PositiveInfinity; if (llc.first == null) { llc.first = tmp; lln = tmp; } else { lln.next = tmp; lln.height = tmp.position.y - lln.position.y; lln = lln.next; } } } else { var lln = new LinkedLevelNode (); lln.position = pos; lln.height = float.PositiveInfinity; lln.walkable = !collision.unwalkableWhenNoGround; llc.first = lln; } //========= uint graphIndex = (uint)active.astarData.GetGraphIndex(this); { //llc LinkedLevelNode lln = llc.first; int count = 0; int layerIndex = 0; do { if (layerIndex >= layerCount) { if (layerIndex+1 > LevelGridNode.MaxLayerCount) { Debug.LogError ("Too many layers, a maximum of LevelGridNode.MaxLayerCount are allowed (required "+(layerIndex+1)+")"); return addedNodes; } AddLayers (1); addedNodes = true; } var node = nodes[z*width+x + width*depth*layerIndex]; if (node == null || !preserveExistingNodes) { //Create a new node nodes[z*width+x + width*depth*layerIndex] = new LevelGridNode(active); node = nodes[z*width+x + width*depth*layerIndex]; node.Penalty = initialPenalty; node.GraphIndex = graphIndex; addedNodes = true; } //node.connections = null; #if ASTAR_SET_LEVELGRIDNODE_HEIGHT node.height = lln.height; #endif node.SetPosition ((Int3)lln.position); node.Walkable = lln.walkable; node.WalkableErosion = node.Walkable; //Adjust penalty based on the surface slope if (lln.hit.normal != Vector3.zero) { //Take the dot product to find out the cosinus of the angle it has (faster than Vector3.Angle) float angle = Vector3.Dot (lln.hit.normal.normalized,collision.up); //Enqueue penalty based on normal if (penaltyAngle) { node.Penalty += (uint)Mathf.RoundToInt ((1F-angle)*penaltyAngleFactor); } //Max slope in cosinus float cosAngle = Mathf.Cos (maxSlope*Mathf.Deg2Rad); //Check if the slope is flat enough to stand on if (angle < cosAngle) { node.Walkable = false; } } node.NodeInGridIndex = z*width+x; if (lln.height < characterHeight) { node.Walkable = false; } count++; lln = lln.next; layerIndex++; } while (lln != null); for (;layerIndex<layerCount;layerIndex++) { nodes[z*width+x + width*depth*layerIndex] = null; } llc.count = count; } return addedNodes; }
public override void ScanInternal (OnScanStatus statusCallback) { if (nodeSize <= 0) { return; } GenerateMatrix (); if (width > 1024 || depth > 1024) { Debug.LogError ("One of the grid's sides is longer than 1024 nodes"); return; } lastScannedWidth = width; lastScannedDepth = depth; SetUpOffsetsAndCosts (); LevelGridNode.SetGridGraph (active.astarData.GetGraphIndex(this), this); maxClimb = Mathf.Clamp (maxClimb,0,characterHeight); var linkedCells = new LinkedLevelCell[width*depth]; collision = collision ?? new GraphCollision (); collision.Initialize (matrix,nodeSize); for (int z = 0; z < depth; z ++) { for (int x = 0; x < width; x++) { linkedCells[z*width+x] = new LinkedLevelCell (); LinkedLevelCell llc = linkedCells[z*width+x]; Vector3 pos = matrix.MultiplyPoint3x4 (new Vector3 (x+0.5F,0,z+0.5F)); RaycastHit[] hits = collision.CheckHeightAll (pos); for (int i=0;i<hits.Length/2;i++) { RaycastHit tmp = hits[i]; hits[i] = hits[hits.Length-1-i]; hits[hits.Length-1-i] = tmp; } if (hits.Length > 0) { LinkedLevelNode lln = null; for (int i=0;i<hits.Length;i++) { var tmp = new LinkedLevelNode (); tmp.position = hits[i].point; if (lln != null) { /** \todo Use hit.distance instead */ if (tmp.position.y - lln.position.y <= mergeSpanRange) { lln.position = tmp.position; lln.hit = hits[i]; lln.walkable = collision.Check (tmp.position); continue; } } tmp.walkable = collision.Check (tmp.position); tmp.hit = hits[i]; tmp.height = float.PositiveInfinity; if (llc.first == null) { llc.first = tmp; lln = tmp; } else { lln.next = tmp; lln.height = tmp.position.y - lln.position.y; lln = lln.next; } } } else { var lln = new LinkedLevelNode (); lln.position = pos; lln.height = float.PositiveInfinity; lln.walkable = !collision.unwalkableWhenNoGround; llc.first = lln; } } } int spanCount = 0; layerCount = 0; // Count the total number of nodes in the graph for (int z = 0; z < depth; z ++) { for (int x = 0; x < width; x++) { LinkedLevelCell llc = linkedCells[z*width+x]; LinkedLevelNode lln = llc.first; int cellCount = 0; // Loop through all nodes in this cell do { cellCount++; spanCount++; lln = lln.next; } while (lln != null); layerCount = cellCount > layerCount ? cellCount : layerCount; } } if (layerCount > LevelGridNode.MaxLayerCount) { Debug.LogError ("Too many layers, a maximum of LevelGridNode.MaxLayerCount are allowed (found "+layerCount+")"); return; } // Create all nodes nodes = new LevelGridNode[width*depth*layerCount]; for (int i=0;i<nodes.Length;i++) { nodes[i] = new LevelGridNode (active); nodes[i].Penalty = initialPenalty; } int nodeIndex = 0; // Max slope in cosinus float cosAngle = Mathf.Cos (maxSlope*Mathf.Deg2Rad); for (int z = 0; z < depth; z++) { for (int x = 0; x < width; x++) { LinkedLevelCell llc = linkedCells[z*width+x]; LinkedLevelNode lln = llc.first; llc.index = nodeIndex; int count = 0; int layerIndex = 0; do { var node = nodes[z*width+x + width*depth*layerIndex]; #if ASTAR_SET_LEVELGRIDNODE_HEIGHT node.height = lln.height; #endif node.SetPosition ((Int3)lln.position); node.Walkable = lln.walkable; // Adjust penalty based on the surface slope if (lln.hit.normal != Vector3.zero && (penaltyAngle || cosAngle < 1.0f)) { //Take the dot product to find out the cosinus of the angle it has (faster than Vector3.Angle) float angle = Vector3.Dot (lln.hit.normal.normalized,collision.up); // Enqueue penalty based on normal if (penaltyAngle) { node.Penalty += (uint)Mathf.RoundToInt ((1F-angle)*penaltyAngleFactor); } // Check if the slope is flat enough to stand on if (angle < cosAngle) { node.Walkable = false; } } node.NodeInGridIndex = z*width+x; if (lln.height < characterHeight) { node.Walkable = false; } node.WalkableErosion = node.Walkable; nodeIndex++; count++; lln = lln.next; layerIndex++; } while (lln != null); for (;layerIndex<layerCount;layerIndex++) { nodes[z*width+x + width*depth*layerIndex] = null; } llc.count = count; } } nodeIndex = 0; nodeCellIndices = new int[linkedCells.Length]; for (int z = 0; z < depth; z ++) { for (int x = 0; x < width; x++) { for (int i=0;i<layerCount;i++) { GraphNode node = nodes[z*width+x + width*depth*i]; CalculateConnections (nodes,node,x,z,i); } } } uint graphIndex = (uint)active.astarData.GetGraphIndex(this); for (int i=0;i<nodes.Length;i++) { var lgn = nodes[i]; if (lgn == null) continue; UpdatePenalty (lgn); lgn.GraphIndex = graphIndex; // Set the node to be unwalkable if it hasn't got any connections if (!lgn.HasAnyGridConnections ()) { lgn.Walkable = false; lgn.WalkableErosion = lgn.Walkable; } } ErodeWalkableArea (); }