protected override void DrawCollisionEditor (GraphCollision collision) { base.DrawCollisionEditor(collision); if (collision.thickRaycast) { EditorGUILayout.HelpBox("Note: Thick raycast cannot be used with this graph type", MessageType.Error); } }
public override void Scan() { scans++; if (nodeSize <= 0) { return; } GenerateMatrix (); if (width > 1024 || depth > 1024) { Debug.LogError ("One of the grid's sides is longer than 1024 nodes"); return; } //GenerateBounds (); /*neighbourOffsets = new int[8] { -width-1,-width,-width+1, -1,1, width-1,width,width+1 }*/ SetUpOffsetsAndCosts (); //GridNode.RemoveGridGraph (this); int gridIndex = LevelGridNode.SetGridGraph (this); //graphNodes = new LevelGridNode[width*depth]; //nodes = CreateNodes (width*depth); //graphNodes = nodes as LevelGridNode[]; maxClimb = Mathf.Clamp (maxClimb,0,characterHeight); LinkedLevelCell[] linkedCells = new LinkedLevelCell[width*depth]; if (collision == null) { 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]; //GridNode node = graphNodes[z*width+x];//new LevelGridNode (); //node.SetIndex (z*width+x); Vector3 pos = matrix.MultiplyPoint3x4 (new Vector3 (x+0.5F,0,z+0.5F)); RaycastHit[] hits = collision.CheckHeightAll (pos); //Sort the hits based on distance with bubble sort (fast enough) //Furthest away first (i.e lowest nodes in the graph) /*bool changed = true; while (changed) { changed = false; for (int i=0;i<hits.Length-1;i++) { if (hits[i].distance < hits[i+1].distance) { RaycastHit tmp = hits[i]; hits[i] = hits[i+1]; hits[i+1] = tmp; changed = true; } } }*/ 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) { //lln.position = hits[0].point; //lln.walkable = collision.Check (lln.position); /*LinkedLevelNode lln = new LinkedLevelNode (); lln.position = hits[0].point; lln.walkable = collision.Check (lln.position); llc.first = lln;*/ LinkedLevelNode lln = null; for (int i=0;i<hits.Length;i++) { LinkedLevelNode tmp = new LinkedLevelNode (); tmp.position = hits[i].point; if (lln != null) { /** \todo Use hit.distance instead */ if (tmp.position.y - lln.position.y <= mergeSpanRange) { //if (tmp.position.y > lln.position.y) { 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 { LinkedLevelNode lln = new LinkedLevelNode (); lln.position = pos; lln.height = float.PositiveInfinity; lln.walkable = !collision.unwalkableWhenNoGround; llc.first = lln; } //node.penalty = 0;//Mathf.RoundToInt (Random.value*100); //node.walkable = collision.Check (node.position); //node.SetGridIndex (gridIndex); } } 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 = CreateNodes (width*depth*layerCount); 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 { LevelGridNode node = nodes[z*width+x + width*depth*layerIndex] as LevelGridNode; #if ASTAR_SET_LEVELGRIDNODE_HEIGHT node.height = lln.height; #endif node.position = (Int3)lln.position; node.walkable = lln.walkable; node.Bit15 = node.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); //Add 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.SetIndex (z*width+x); //node.nodeOffset = count; if (lln.height < characterHeight) { node.walkable = false; } 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++) { /*LinkedLevelCell llc = linkedCells[z*width+x]; LinkedLevelNode lln = llc.first; nodeCellIndices[z*width+x] = llc.index; do { LevelGridNode node = (LevelGridNode)nodes[nodeIndex]; CalculateConnections (nodes,linkedCells,node,x,z,n); nodeIndex++; lln = lln.next; } while (lln != null);*/ for (int i=0;i<layerCount;i++) { Node node = nodes[z*width+x + width*depth*i]; CalculateConnections (nodes,node,x,z,i); } } } for (int i=0;i<nodes.Length;i++) { LevelGridNode lgn = nodes[i] as LevelGridNode; if (lgn == null) continue; UpdatePenalty (lgn); lgn.SetGridIndex (gridIndex); //Set the node to be unwalkable if it hasn't got any connections if (!lgn.HasAnyGridConnections ()) { lgn.walkable = false; } } /*GridNode node = graphNodes[z*width+x]; CalculateConnections (graphNodes,x,z,node); if (z == 5 && x == 5) { int index = z*width+x; Debug.DrawRay (node.position,(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.red); Debug.DrawRay (node.position,(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.green); Debug.DrawRay (node.position,(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.blue); Debug.DrawRay (node.position,(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.yellow); Debug.DrawRay (node.position,(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.cyan); Debug.DrawRay (node.position,(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.magenta); Debug.DrawRay (node.position,(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.black); Debug.DrawRay (node.position,(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.white); }*/ //} //} ErodeWalkableArea (0,0,width,depth); }
public void DeSerializeSettings(AstarSerializer serializer) { //width = (int)serializer.GetValue ("Width",typeof(int)); //depth = (int)serializer.GetValue ("Depth",typeof(int)); //height = (float)serializer.GetValue ("Height",typeof(float)); unclampedSize = (Vector2)serializer.GetValue ("unclampedSize",typeof(Vector2)); cutCorners = (bool)serializer.GetValue ("cutCorners",typeof(bool)); neighbours = (NumNeighbours)serializer.GetValue ("neighbours",typeof(int)); rotation = (Vector3)serializer.GetValue ("rotation",typeof(Vector3)); nodeSize = (float)serializer.GetValue ("nodeSize",typeof(float)); collision = (GraphCollision)serializer.GetValue ("collision",typeof(GraphCollision)); center = (Vector3)serializer.GetValue ("center",typeof(Vector3)); maxClimb = (float)serializer.GetValue ("maxClimb",typeof(float)); maxClimbAxis = (int)serializer.GetValue ("maxClimbAxis",typeof(int),1); maxSlope = (float)serializer.GetValue ("maxSlope",typeof(float),90.0F); erodeIterations = (int)serializer.GetValue ("erodeIterations",typeof(int)); penaltyAngle = (bool)serializer.GetValue ("penaltyAngle",typeof(bool)); penaltyAngleFactor = (float)serializer.GetValue ("penaltyAngleFactor",typeof(float)); penaltyPosition = (bool)serializer.GetValue ("penaltyPosition",typeof(bool)); penaltyPositionOffset = (float)serializer.GetValue ("penaltyPositionOffset",typeof(float)); penaltyPositionFactor = (float)serializer.GetValue ("penaltyPositionFactor",typeof(float)); aspectRatio = (float)serializer.GetValue ("aspectRatio",typeof(float),1F); textureData = serializer.GetValue ("textureData",typeof(TextureData)) as TextureData; if (textureData == null) textureData = new TextureData (); #if UNITY_EDITOR Matrix4x4 oldMatrix = matrix; #endif GenerateMatrix (); SetUpOffsetsAndCosts (); #if UNITY_EDITOR if (serializer.onlySaveSettings) { if (oldMatrix != matrix && nodes != null) { AstarPath.active.AutoScan (); } } #endif //Debug.Log ((string)serializer.GetValue ("SomeString",typeof(string))); //Debug.Log ((Bounds)serializer.GetValue ("SomeBounds",typeof(Bounds))); }
/** Draws the inspector for a \link Pathfinding.GraphCollision GraphCollision class \endlink */ public void DrawCollisionEditor(GraphCollision collision) { if (collision == null) { collision = new GraphCollision (); } /*GUILayout.Space (5); Rect r = EditorGUILayout.BeginVertical (AstarPathEditor.graphBoxStyle); GUI.Box (r,"",AstarPathEditor.graphBoxStyle); GUILayout.Space (2);*/ Separator (); /*GUILayout.BeginHorizontal (); GUIStyle boxHeader = AstarPathEditor.astarSkin.FindStyle ("CollisionHeader"); GUILayout.Label ("Collision testing",boxHeader); collision.collisionCheck = GUILayout.Toggle (collision.collisionCheck,""); bool preEnabledRoot = GUI.enabled; GUI.enabled = collision.collisionCheck; GUILayout.EndHorizontal ();*/ collision.collisionCheck = ToggleGroup ("Collision testing",collision.collisionCheck); bool preEnabledRoot = GUI.enabled; GUI.enabled = collision.collisionCheck; //GUILayout.BeginHorizontal (); collision.type = (ColliderType)EditorGUILayout.EnumPopup("Collider type",collision.type); //new string[3] {"Sphere","Capsule","Ray"} bool preEnabled = GUI.enabled; if (collision.type != ColliderType.Capsule && collision.type != ColliderType.Sphere) { GUI.enabled = false; } collision.diameter = EditorGUILayout.FloatField (new GUIContent ("Diameter","Diameter of the capsule of sphere where 1 equals one node"),collision.diameter); GUI.enabled = preEnabled; if (collision.type != ColliderType.Capsule && collision.type != ColliderType.Ray) { GUI.enabled = false; } collision.height = EditorGUILayout.FloatField (new GUIContent ("Height/Length","Height of cylinder of length of ray in world units"),collision.height); GUI.enabled = preEnabled; collision.collisionOffset = EditorGUILayout.FloatField (new GUIContent("Offset","Offset upwards from the node. Can be used so obstacles can be used as ground and as obstacles for lower nodes"),collision.collisionOffset); //collision.mask = 1 << EditorGUILayout.LayerField ("Mask",Mathf.Clamp ((int)Mathf.Log (collision.mask,2),0,31)); collision.mask = EditorGUILayoutx.LayerMaskField ("Mask",collision.mask); GUILayout.Space (2); GUI.enabled = preEnabledRoot; collision.heightCheck = ToggleGroup ("Height testing",collision.heightCheck); GUI.enabled = collision.heightCheck && GUI.enabled; /*GUILayout.BeginHorizontal (); GUILayout.Label ("Height testing",boxHeader); collision.heightCheck = GUILayout.Toggle (collision.heightCheck,""); GUI.enabled = collision.heightCheck; GUILayout.EndHorizontal ();*/ collision.fromHeight = EditorGUILayout.FloatField (new GUIContent ("Ray length","The height from which to check for ground"),collision.fromHeight); collision.heightMask = EditorGUILayoutx.LayerMaskField ("Mask",collision.heightMask); //collision.heightMask = 1 << EditorGUILayout.LayerField ("Mask",Mathf.Clamp ((int)Mathf.Log (collision.heightMask,2),0,31)); collision.thickRaycast = EditorGUILayout.Toggle (new GUIContent ("Thick Raycast", "Use a thick line instead of a thin line"),collision.thickRaycast); editor.GUILayoutx.BeginFadeArea (collision.thickRaycast,"thickRaycastDiameter"); if (editor.GUILayoutx.DrawID ("thickRaycastDiameter")) { EditorGUI.indentLevel++; collision.thickRaycastDiameter = EditorGUILayout.FloatField (new GUIContent ("Diameter","Diameter of the thick raycast"),collision.thickRaycastDiameter); EditorGUI.indentLevel--; } editor.GUILayoutx.EndFadeArea (); collision.unwalkableWhenNoGround = EditorGUILayout.Toggle (new GUIContent ("Unwalkable when no ground","Make nodes unwalkable when no ground was found with the height raycast. If height raycast is turned off, this doesn't affect anything"), collision.unwalkableWhenNoGround); GUI.enabled = preEnabledRoot; //GUILayout.Space (2); //EditorGUILayout.EndVertical (); //GUILayout.Space (5); }
public override void ScanInternal (OnScanStatus statusCallback) { AstarPath.OnPostScan += new OnScanDelegate(OnPostScan); if (nodeSize <= 0) { return; } // Make sure the matrix is up to date GenerateMatrix(); if (width > 1024 || depth > 1024) { Debug.LogError("One of the grid's sides is longer than 1024 nodes"); return; } SetUpOffsetsAndCosts(); // Get the graph index of this graph int graphIndex = AstarPath.active.astarData.GetGraphIndex(this); // Set a global reference to this graph so that nodes can find it GridNode.SetGridGraph(graphIndex, this); // Create all nodes nodes = new GridNode[width*depth]; for (int i = 0; i < nodes.Length; i++) { nodes[i] = new GridNode(active); nodes[i].GraphIndex = (uint)graphIndex; } // Create and initialize the collision class if (collision == null) { collision = new GraphCollision(); } collision.Initialize(matrix, nodeSize); for (int z = 0; z < depth; z++) { for (int x = 0; x < width; x++) { var node = nodes[z*width+x]; node.NodeInGridIndex = z*width+x; // Updates the position of the node // and a bunch of other things UpdateNodePositionCollision(node, x, z); } } for (int z = 0; z < depth; z++) { for (int x = 0; x < width; x++) { var node = nodes[z*width + x]; // Recalculate connections to other nodes CalculateConnections(x, z, node); } } // Apply erosion ErodeWalkableArea(); }
protected virtual void DrawUse2DPhysics (GraphCollision collision) { collision.use2D = EditorGUILayout.Toggle (new GUIContent ("Use 2D Physics", "Use the Physics2D API for collision checking"), collision.use2D ); }
/** Draws the inspector for a \link Pathfinding.GraphCollision GraphCollision class \endlink */ protected virtual void DrawCollisionEditor (GraphCollision collision) { collision = collision ?? new GraphCollision (); DrawUse2DPhysics (collision); collision.collisionCheck = ToggleGroup ("Collision testing",collision.collisionCheck); EditorGUI.BeginDisabledGroup(!collision.collisionCheck); collision.type = (ColliderType)EditorGUILayout.EnumPopup("Collider type",collision.type); EditorGUI.BeginDisabledGroup(collision.type != ColliderType.Capsule && collision.type != ColliderType.Sphere); collision.diameter = EditorGUILayout.FloatField (new GUIContent ("Diameter","Diameter of the capsule or sphere. 1 equals one node width"),collision.diameter); EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup(collision.type != ColliderType.Capsule && collision.type != ColliderType.Ray); collision.height = EditorGUILayout.FloatField (new GUIContent ("Height/Length","Height of cylinder or length of ray in world units"),collision.height); EditorGUI.EndDisabledGroup(); collision.collisionOffset = EditorGUILayout.FloatField (new GUIContent("Offset","Offset upwards from the node. Can be used so that obstacles can be used as ground and at the same time as obstacles for lower positioned nodes"),collision.collisionOffset); collision.mask = EditorGUILayoutx.LayerMaskField ("Mask",collision.mask); EditorGUI.EndDisabledGroup(); GUILayout.Space (2); EditorGUI.BeginDisabledGroup(collision.use2D); collision.heightCheck = ToggleGroup ("Height testing",collision.heightCheck); EditorGUI.BeginDisabledGroup(!collision.heightCheck); collision.fromHeight = EditorGUILayout.FloatField (new GUIContent ("Ray length","The height from which to check for ground"),collision.fromHeight); collision.heightMask = EditorGUILayoutx.LayerMaskField ("Mask",collision.heightMask); collision.thickRaycast = EditorGUILayout.Toggle (new GUIContent ("Thick Raycast", "Use a thick line instead of a thin line"),collision.thickRaycast); if (collision.thickRaycast) { EditorGUI.indentLevel++; collision.thickRaycastDiameter = EditorGUILayout.FloatField (new GUIContent ("Diameter","Diameter of the thick raycast"),collision.thickRaycastDiameter); EditorGUI.indentLevel--; } collision.unwalkableWhenNoGround = EditorGUILayout.Toggle (new GUIContent ("Unwalkable when no ground","Make nodes unwalkable when no ground was found with the height raycast. If height raycast is turned off, this doesn't affect anything"), collision.unwalkableWhenNoGround); EditorGUI.EndDisabledGroup(); EditorGUI.EndDisabledGroup(); }
protected virtual void DrawUse2DPhysics(GraphCollision collision) { collision.use2D = EditorGUILayout.Toggle(new GUIContent("Use 2D Physics", "Use the Physics2D API for collision checking"), collision.use2D); }
public override IEnumerable<Progress> ScanInternal () { AstarPath.OnPostScan += new OnScanDelegate (OnPostScan); if (nodeSize <= 0) { yield break; } // Make sure the matrix is up to date GenerateMatrix (); if (width > 1024 || depth > 1024) { Debug.LogError ("One of the grid's sides is longer than 1024 nodes"); yield break; } SetUpOffsetsAndCosts (); // Get the graph index of this graph int graphIndex = AstarPath.active.astarData.GetGraphIndex(this); // Set a global reference to this graph so that nodes can find it GridNode.SetGridGraph (graphIndex,this); yield return new Progress(0.05f, "Creating nodes"); // Create all nodes nodes = new GridNode[width*depth]; for (int i = 0; i < nodes.Length; i++) { nodes[i] = new GridNode(active); nodes[i].GraphIndex = (uint)graphIndex; } // Create and initialize the collision class if (collision == null) { collision = new GraphCollision (); } collision.Initialize (matrix,nodeSize); int progressCounter = 0; const int YieldEveryNNodes = 1000; for (int z = 0; z < depth; z ++) { // Yield with a progress value at most every N nodes if (progressCounter >= YieldEveryNNodes) { progressCounter = 0; yield return new Progress(Mathf.Lerp(0.1f,0.7f,z/(float)depth), "Calculating positions"); } progressCounter += width; for (int x = 0; x < width; x++) { var node = nodes[z*width+x]; node.NodeInGridIndex = z*width+x; // Updates the position of the node // and a bunch of other things UpdateNodePositionCollision (node,x,z); } } for (int z = 0; z < depth; z++) { // Yield with a progress value at most every N nodes if (progressCounter >= YieldEveryNNodes) { progressCounter = 0; yield return new Progress(Mathf.Lerp(0.1f,0.7f,z/(float)depth), "Calculating connections"); } for (int x = 0; x < width; x++) { var node = nodes[z*width + x]; // Recalculate connections to other nodes CalculateConnections(x, z, node); } } yield return new Progress(0.95f, "Calculating erosion"); // Apply erosion ErodeWalkableArea (); }
protected override void DrawUse2DPhysics (GraphCollision collision) { // 2D physics does not make sense for a layered grid graph collision.use2D = false; }
public override void Scan() { AstarPath.OnPostScan += new OnScanDelegate (OnPostScan); scanns++; if (nodeSize <= 0) { return; } GenerateMatrix (); if (width > 1024 || depth > 1024) { Debug.LogError ("One of the grid's sides is longer than 1024 nodes"); return; } //GenerateBounds (); /*neighbourOffsets = new int[8] { -width-1,-width,-width+1, -1,1, width-1,width,width+1 }*/ SetUpOffsetsAndCosts (); //GridNode.RemoveGridGraph (this); int gridIndex = GridNode.SetGridGraph (this); //graphNodes = new GridNode[width*depth]; nodes = CreateNodes (width*depth); graphNodes = nodes as GridNode[]; if (collision == null) { collision = new GraphCollision (); } collision.Initialize (matrix,nodeSize); //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++) { GridNode node = graphNodes[z*width+x];//new GridNode (); node.SetIndex (z*width+x); UpdateNodePositionCollision (node,x,z); /*node.position = matrix.MultiplyPoint3x4 (new Vector3 (x+0.5F,0,z+0.5F)); RaycastHit hit; bool walkable = true; node.position = collision.CheckHeight (node.position, out hit, out walkable); node.penalty = 0;//Mathf.RoundToInt (Random.value*100); //Check if the node is on a slope steeper than permitted if (walkable && useRaycastNormal && collision.heightCheck) { if (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 (hit.normal.normalized,Vector3.up); if (angle < cosAngle) { walkable = false; } } } //If the walkable flag has already been set to false, there is no point in checking for it again if (walkable) { node.walkable = collision.Check (node.position); } else { node.walkable = walkable; }*/ node.SetGridIndex (gridIndex); } } for (int z = 0; z < depth; z ++) { for (int x = 0; x < width; x++) { GridNode node = graphNodes[z*width+x]; CalculateConnections (graphNodes,x,z,node); } } ErodeWalkableArea (); //Assign the nodes to the main storage //startIndex = AstarPath.active.AssignNodes (graphNodes); //endIndex = startIndex+graphNodes.Length; }
public override void ScanInternal (OnScanStatus statusCallback) { AstarPath.OnPostScan += new OnScanDelegate (OnPostScan); scans++; if (nodeSize <= 0) { return; } GenerateMatrix (); if (width > 1024 || depth > 1024) { Debug.LogError ("One of the grid's sides is longer than 1024 nodes"); return; } #if !ASTAR_JPS if (this.useJumpPointSearch) { Debug.LogError ("Trying to use Jump Point Search, but support for it is not enabled. Please enable it in the inspector (Grid Graph settings)."); } #endif SetUpOffsetsAndCosts (); int graphIndex = AstarPath.active.astarData.GetGraphIndex(this); GridNode.SetGridGraph (graphIndex,this); nodes = new GridNode[width*depth]; for (int i=0;i<nodes.Length;i++) { nodes[i] = new GridNode(active); nodes[i].GraphIndex = (uint)graphIndex; } if (collision == null) { collision = new GraphCollision (); } collision.Initialize (matrix,nodeSize); textureData.Initialize (); for (int z = 0; z < depth; z ++) { for (int x = 0; x < width; x++) { GridNode node = nodes[z*width+x]; node.NodeInGridIndex = z*width+x; UpdateNodePositionCollision (node,x,z); textureData.Apply (node,x,z); } } for (int z = 0; z < depth; z ++) { for (int x = 0; x < width; x++) { GridNode node = nodes[z*width+x]; CalculateConnections (nodes,x,z,node); #if ASTARDEBUG if (z == 5 && x == 5) { int index = z*width+x; Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.red); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.green); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.blue); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.yellow); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.cyan); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.magenta); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.black); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.white); } #endif } } ErodeWalkableArea (); }
// sets up pathfinding // To get walking/flying working with dynamic room generation, some complexity was required public void AddGraph() { AstarData data = AstarPath.active.astarData; // This creates a Grid Graph GridGraph gg = data.AddGraph(typeof(GridGraph)) as GridGraph; // Setup a grid graph with some values gg.width = 50; gg.depth = 40; gg.center = transform.position + new Vector3(0, -5, 0); // Updates internal size from the above values gg.UpdateSizeFromWidthDepth(); GraphCollision gc = new GraphCollision(); gc.collisionCheck = true; gc.heightCheck = true; gc.diameter = 2F; gc.heightMask = LayerMask.GetMask(new string[] {"Rock","Room","Floor"}); gc.mask = LayerMask.GetMask(new string[] {"Rock","Room"}); gg.maxClimb = 8F; gg.collision = gc; }
/// <summary>Draws the inspector for a \link Pathfinding.GraphCollision GraphCollision class \endlink</summary> protected virtual void DrawCollisionEditor(GraphCollision collision) { collision = collision ?? new GraphCollision(); DrawUse2DPhysics(collision); collision.collisionCheck = ToggleGroup("Collision testing", collision.collisionCheck); if (collision.collisionCheck) { string[] colliderOptions = collision.use2D ? new [] { "Circle", "Point" } : new [] { "Sphere", "Capsule", "Ray" }; int[] colliderValues = collision.use2D ? new [] { 0, 2 } : new [] { 0, 1, 2 }; // In 2D the Circle (Sphere) mode will replace both the Sphere and the Capsule modes // However make sure that the original value is still stored in the grid graph in case the user changes back to the 3D mode in the inspector. var tp = collision.type; if (tp == ColliderType.Capsule && collision.use2D) { tp = ColliderType.Sphere; } EditorGUI.BeginChangeCheck(); tp = (ColliderType)EditorGUILayout.IntPopup("Collider type", (int)tp, colliderOptions, colliderValues); if (EditorGUI.EndChangeCheck()) { collision.type = tp; } // Only spheres and capsules have a diameter if (collision.type == ColliderType.Capsule || collision.type == ColliderType.Sphere) { collision.diameter = EditorGUILayout.FloatField(new GUIContent("Diameter", "Diameter of the capsule or sphere. 1 equals one node width"), collision.diameter); } if (!collision.use2D) { if (collision.type == ColliderType.Capsule || collision.type == ColliderType.Ray) { collision.height = EditorGUILayout.FloatField(new GUIContent("Height/Length", "Height of cylinder or length of ray in world units"), collision.height); } collision.collisionOffset = EditorGUILayout.FloatField(new GUIContent("Offset", "Offset upwards from the node. Can be used so that obstacles can be used as ground and at the same time as obstacles for lower positioned nodes"), collision.collisionOffset); } collision.mask = EditorGUILayoutx.LayerMaskField("Obstacle Layer Mask", collision.mask); DrawCollisionPreview(collision); } GUILayout.Space(2); if (collision.use2D) { EditorGUI.BeginDisabledGroup(collision.use2D); ToggleGroup("Height testing", false); EditorGUI.EndDisabledGroup(); } else { collision.heightCheck = ToggleGroup("Height testing", collision.heightCheck); if (collision.heightCheck) { collision.fromHeight = EditorGUILayout.FloatField(new GUIContent("Ray length", "The height from which to check for ground"), collision.fromHeight); collision.heightMask = EditorGUILayoutx.LayerMaskField("Mask", collision.heightMask); collision.thickRaycast = EditorGUILayout.Toggle(new GUIContent("Thick Raycast", "Use a thick line instead of a thin line"), collision.thickRaycast); if (collision.thickRaycast) { EditorGUI.indentLevel++; collision.thickRaycastDiameter = EditorGUILayout.FloatField(new GUIContent("Diameter", "Diameter of the thick raycast"), collision.thickRaycastDiameter); EditorGUI.indentLevel--; } collision.unwalkableWhenNoGround = EditorGUILayout.Toggle(new GUIContent("Unwalkable when no ground", "Make nodes unwalkable when no ground was found with the height raycast. If height raycast is turned off, this doesn't affect anything"), collision.unwalkableWhenNoGround); } } }
public GridGraph () { unclampedSize = new Vector2 (10,10); nodeSize = 1F; collision = new GraphCollision (); }
public override void ScanInternal (OnScanStatus statusCallback) { AstarPath.OnPostScan += new OnScanDelegate (OnPostScan); scans++; if (nodeSize <= 0) { return; } GenerateMatrix (); if (width > 1024 || depth > 1024) { Debug.LogError ("One of the grid's sides is longer than 1024 nodes"); return; } SetUpOffsetsAndCosts (); int graphIndex = AstarPath.active.astarData.GetGraphIndex(this); GridNode.SetGridGraph (graphIndex,this); nodes = new GridNode[width*depth]; for (int i=0;i<nodes.Length;i++) { nodes[i] = new GridNode(active); nodes[i].GraphIndex = (uint)graphIndex; } if (collision == null) { collision = new GraphCollision (); } collision.Initialize (matrix,nodeSize); for (int z = 0; z < depth; z ++) { for (int x = 0; x < width; x++) { GridNode node = nodes[z*width+x]; node.NodeInGridIndex = z*width+x; UpdateNodePositionCollision (node,x,z); } } for (int z = 0; z < depth; z ++) { for (int x = 0; x < width; x++) { GridNode node = nodes[z*width+x]; CalculateConnections (nodes,x,z,node); } } ErodeWalkableArea (); }
public override void ScanInternal (OnScanStatus statusCallback) { AstarPath.OnPostScan += new OnScanDelegate (OnPostScan); scans++; if (nodeSize <= 0) { return; } GenerateMatrix (); if (width > 1024 || depth > 1024) { Debug.LogError ("One of the grid's sides is longer than 1024 nodes"); return; } //GenerateBounds (); /*neighbourOffsets = new int[8] { -width-1,-width,-width+1, -1,1, width-1,width,width+1 }*/ SetUpOffsetsAndCosts (); //GridNode.RemoveGridGraph (this); int graphIndex = AstarPath.active.astarData.GetGraphIndex(this); GridNode.SetGridGraph (graphIndex,this); //graphNodes = new GridNode[width*depth]; //nodes = CreateNodes (width*depth); nodes = new GridNode[width*depth]; for (int i=0;i<nodes.Length;i++) { nodes[i] = new GridNode(active); nodes[i].GraphIndex = (uint)graphIndex; } if (collision == null) { collision = new GraphCollision (); } collision.Initialize (matrix,nodeSize); textureData.Initialize (); //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++) { GridNode node = nodes[z*width+x];//new GridNode (); node.NodeInGridIndex = z*width+x; UpdateNodePositionCollision (node,x,z); textureData.Apply (node,x,z); /*node.position = matrix.MultiplyPoint3x4 (new Vector3 (x+0.5F,0,z+0.5F)); RaycastHit hit; bool walkable = true; node.position = collision.CheckHeight (node.position, out hit, out walkable); node.penalty = 0;//Mathf.RoundToInt (Random.value*100); //Check if the node is on a slope steeper than permitted if (walkable && useRaycastNormal && collision.heightCheck) { if (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 (hit.normal.normalized,Vector3.up); if (angle < cosAngle) { walkable = false; } } } //If the walkable flag has already been set to false, there is no point in checking for it again if (walkable) { node.walkable = collision.Check (node.position); } else { node.walkable = walkable; }*/ } } for (int z = 0; z < depth; z ++) { for (int x = 0; x < width; x++) { GridNode node = nodes[z*width+x]; CalculateConnections (nodes,x,z,node); #if ASTARDEBUG if (z == 5 && x == 5) { int index = z*width+x; Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.red); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.green); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.blue); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.yellow); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.cyan); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.magenta); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.black); Debug.DrawRay ((Vector3)node.position,(Vector3)(nodes[index+neighbourOffsets[0]].position-node.position)*0.5F,Color.white); } #endif } } ErodeWalkableArea (); //Assign the nodes to the main storage //startIndex = AstarPath.active.AssignNodes (graphNodes); //endIndex = startIndex+graphNodes.Length; }
protected override void DrawUse2DPhysics(GraphCollision collision) { // 2D physics does not make sense for a layered grid graph collision.use2D = false; }