/// <summary> /// Gets the path. /// </summary> /// <returns>The path.</returns> /// <param name="startingPos">Starting position.</param> /// <param name="goalPos">Goal position.</param> /// <param name="needsGround"><see cref="CubicPath.needsGround"/></param> public CubicPath GetPath(Vector3 startingPos, Vector3 goalPos, bool needsGround = false) { CubicPath pathObject = new CubicPath (startingPos, goalPos); pathObject.needsGround = needsGround; // Enqueue path lock (this.pathQueueLock) { this.pathQueue.Enqueue(pathObject); } return pathObject; }
/// <summary> /// Gets the path. /// </summary> /// <returns>The path.</returns> /// <param name="startingPos">Starting position.</param> /// <param name="goalPos">Goal position.</param> /// <param name="needsGround"><see cref="CubicPath.needsGround"/></param> public CubicPath GetPath(Vector3 startingPos, Vector3 goalPos, bool needsGround = false) { CubicPath pathObject = new CubicPath(startingPos, goalPos); pathObject.needsGround = needsGround; // Enqueue path lock (this.pathQueueLock) { this.pathQueue.Enqueue(pathObject); } return(pathObject); }
private void OnEnable() { _path = target as CubicPath; _state = EditorState.LoadOrCreateFor(target); _loop = serializedObject.FindProperty("_loop"); _points = serializedObject.FindProperty("_points"); _handlesIcon = EditorGUIUtility.IconContent(SHOW_HANDLES_ICON).image; _separatorLineStyle = new GUIStyle(); _separatorLineStyle.normal.background = EditorGUIUtility.whiteTexture; _separatorLineStyle.margin = new RectOffset(0, 0, 4, 4); _separatorLineStyle.fixedHeight = 1; if (!_state.PropertyExists <int>(SUBS_KEY)) { _state.SetProperty(SUBS_KEY, MIN_SUBDIVISIONS); } if (!_state.PropertyExists <bool>(EDIT_INTERP_KEY)) { _state.SetProperty(EDIT_INTERP_KEY, false); } if (!_state.PropertyExists <bool>(SHOW_HANDLES_KEY)) { _state.SetProperty(SHOW_HANDLES_KEY, false); } if (!_state.PropertyExists <bool>(POINTS_COLLAPSED_KEY)) { _state.SetProperty(POINTS_COLLAPSED_KEY, false); } if (!_state.PropertyExists <Space>(COORDS_SYSTEM_KEY)) { _state.SetProperty(COORDS_SYSTEM_KEY, Space.Self); } PreparePointsList(); }
/// <summary> /// Finds the path path. /// </summary> /// <param name="path">Path.</param> private void FindPath(CubicPath path) { // List definitions Dictionary <Vector3, PathNode> openList = new Dictionary <Vector3, PathNode>(); List <Vector3> closedList = new List <Vector3> (); // Start pathfinding PathNode startNode = new PathNode(path.startPos, null, 0, path.goalPos); startNode.owner = startNode; PathNode currentNode = startNode; bool pathFound = false; bool noPath = false; int movementCost = 0; // Measure time System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); stopWatch.Start(); try { while (!pathFound && !noPath) { // Calculate block direction positions Vector3[] positions = new Vector3[] { // Front currentNode.position + Vector3.forward, // Back currentNode.position + Vector3.back, // Left currentNode.position + Vector3.left, // Right currentNode.position + Vector3.right, // Front right currentNode.position + Vector3.forward + Vector3.right, // Front left currentNode.position + Vector3.forward + Vector3.left, // Back right currentNode.position + Vector3.back + Vector3.right, // Back left currentNode.position + Vector3.back + Vector3.left, // Up Front currentNode.position + Vector3.forward + Vector3.up, // Up Back currentNode.position + Vector3.back + Vector3.up, // Up Left currentNode.position + Vector3.left + Vector3.up, // Up Right currentNode.position + Vector3.right + Vector3.up, // Down Front currentNode.position + Vector3.forward + Vector3.down, // Down Back currentNode.position + Vector3.back + Vector3.down, // Down Left currentNode.position + Vector3.left + Vector3.down, // Down Right currentNode.position + Vector3.right + Vector3.down, }; // Analyze surrounding path nodes PathNode[] nodes = new PathNode[positions.Length]; PathNode lowestCostNode = null; // Check which ones are walkable and add them to the nodes-array for (int i = 0; i < positions.Length; i++) { // Movement cost from this to the surrounding block int currentMovementCost = (int)(Vector3.Distance(positions[i], currentNode.position) * 10); // Check if this node is walkable if (!closedList.Contains(positions[i]) && !this.terrain.HasBlock((int)positions[i].x, (int)positions[i].y, (int)positions[i].z) && // Walkable check (!path.needsGround || this.terrain.HasBlock((int)positions[i].x, (int)positions[i].y - 1, (int)positions[i].z))) { // Add node to the nodes-array if (openList.ContainsKey(positions[i])) { nodes[i] = openList[positions[i]]; } else { nodes[i] = new PathNode(positions[i], currentNode, movementCost + currentMovementCost, path.goalPos); openList.Add(positions[i], nodes[i]); } } // Check for lowest cost if (nodes[i] != null && (lowestCostNode == null || nodes[i].completeCost < lowestCostNode.completeCost)) { lowestCostNode = nodes[i]; } } // Failed? o_O if (lowestCostNode == null) { noPath = true; break; } if (currentNode.position == path.goalPos) { pathFound = true; } // Put the lowest cost node on the closed list if (currentNode.owner.position == lowestCostNode.owner.position) { currentNode.owner.nextNode = lowestCostNode; } else { currentNode.nextNode = lowestCostNode; } closedList.Add(currentNode.position); currentNode = lowestCostNode; } } catch (System.Exception exception) { // :( noPath = true; } stopWatch.Stop(); // No path found? if (noPath) { // :'( path.SetPathData(null); } else { // :^) // This is needed because in the closedlist there can be movements which are like // front, right // this should be done in one step frontright and this gets achieved by generating an array from the path node's linked list. List <Vector3> pathData = new List <Vector3>(); PathNode cNode = startNode; while (cNode != null) { pathData.Add(cNode.position); cNode = cNode.nextNode; } path.SetPathData(pathData.ToArray()); } // Set runtime path.runtime = (float)stopWatch.Elapsed.TotalMilliseconds; }
public void Update() { bool firstPoint = Input.GetKeyDown (KeyCode.P); bool lastPoint = Input.GetKeyDown (KeyCode.L); bool definePoint = firstPoint || lastPoint; if (this.path != null) { if (this.path.isReady) { Debug.Log ("Path found in " + path.runtime + " milliseconds!"); foreach (Vector3 blockPos in this.path.pathData) { CubicTerrain.GetInstance().SetBlock((int)blockPos.x, (int)blockPos.y-1, (int)blockPos.z, -1); } this.path = null; } else if (!this.path.foundPath) { Debug.Log ("Path not found :-( after search for " + path.runtime + " milliseconds!"); } } // Right mouse button. if (definePoint) { if (CubicTerrain.GetInstance().useMeshColliders) { // Get ready to perform the raycast. RaycastHit hitInfo = new RaycastHit(); Ray cameraRay = this.playerCamera.GetComponent<Camera>().ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2)); Debug.DrawRay(cameraRay.origin, cameraRay.direction, Color.red, 100.0f); // Perform the raycast if (Physics.Raycast(cameraRay, out hitInfo, 5, this.detectionMask.value)) { if (hitInfo.collider == null) return; // get collider parent Transform chunkTransform = hitInfo.collider.transform.parent; if (chunkTransform != null) { // Chunk hit? CubicTerrainChunk chunk = chunkTransform.GetComponent<CubicTerrainChunk>(); if (chunk != null && !chunk.isDirty) { // Yes, chunk hit! BlockHitInfo blockHitInfo = chunk.GetBlockHitInfo(hitInfo); int x = (int)blockHitInfo.hitBlock.x; int y = (int)blockHitInfo.hitBlock.y; int z = (int)blockHitInfo.hitBlock.z; // Which face was hit? calculate target position for the new block switch (blockHitInfo.hitFace) { case BlockFace.LEFT: x-=1; break; case BlockFace.RIGHT: x+=1; break; case BlockFace.TOP: y+=1; break; case BlockFace.BOTTOM: y-=1; break; case BlockFace.FRONT: z+=1; break; case BlockFace.BACK: z-=1; break; } Vector3 chunkPos = chunk.chunkPosition; // Get chunk we want to place the block on if (x < 0) { chunkPos.x-= 1; x=chunk.master.chunkWidth-1; } if (x >= chunk.master.chunkWidth) { chunkPos.x+= 1; x=0; } if (z < 0) { chunkPos.z-= 1; z=chunk.master.chunkDepth-1; } if (z >= chunk.master.chunkDepth) { chunkPos.z+= 1; z=0; } // Finally place the object GameObject chunkObject = chunk.master.GetChunkObject((int) chunkPos.x, (int)chunkPos.y, (int) chunkPos.z); chunk = chunkObject.GetComponent<CubicTerrainChunk>(); // Get absolute position Vector3 absoluteVoxelspace = chunk.GetAbsolutePosition(new Vector3(x,y,z)); Debug.Log ("Point: " + absoluteVoxelspace); if (firstPoint) startPoint = absoluteVoxelspace; else if (lastPoint) goalPoint = absoluteVoxelspace; } } } } else { // Cubic World Physics way CubicRaycastHitInfo hitInfo = new CubicRaycastHitInfo(); if (CubicPhysics.TerrainRaycastUnprecise(this.playerCamera.GetComponent<Camera>().ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2)), 5.0f, out hitInfo)) { // Debug.Log ("Hit: " + hitInfo.hitPoint + ", Block: " + hitInfo.blockHit + ", Face: " + hitInfo.faceHit); // Hit block Vector3 topBlock = hitInfo.blockHit + Vector3.up; Debug.Log ("Top Block: " + topBlock); if (firstPoint) startPoint = topBlock; else if (lastPoint) goalPoint = topBlock; } } } if (startPoint != Vector3.zero && goalPoint != Vector3.zero) { Debug.Log ("Starting A* path finding. Distance: " + Vector3.Distance(startPoint, goalPoint)); // Start pathfinding CubicPathfinding pathfinder = CubicPathfinding.GetInstance(); this.path = pathfinder.GetPath(startPoint, goalPoint, true); startPoint = Vector3.zero; goalPoint = Vector3.zero; } }
public void Update() { bool firstPoint = Input.GetKeyDown(KeyCode.P); bool lastPoint = Input.GetKeyDown(KeyCode.L); bool definePoint = firstPoint || lastPoint; if (this.path != null) { if (this.path.isReady) { Debug.Log("Path found in " + path.runtime + " milliseconds!"); foreach (Vector3 blockPos in this.path.pathData) { CubicTerrain.GetInstance().SetBlock((int)blockPos.x, (int)blockPos.y - 1, (int)blockPos.z, -1); } this.path = null; } else if (!this.path.foundPath) { Debug.Log("Path not found :-( after search for " + path.runtime + " milliseconds!"); } } // Right mouse button. if (definePoint) { if (CubicTerrain.GetInstance().useMeshColliders) { // Get ready to perform the raycast. RaycastHit hitInfo = new RaycastHit(); Ray cameraRay = this.playerCamera.GetComponent <Camera>().ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2)); Debug.DrawRay(cameraRay.origin, cameraRay.direction, Color.red, 100.0f); // Perform the raycast if (Physics.Raycast(cameraRay, out hitInfo, 5, this.detectionMask.value)) { if (hitInfo.collider == null) { return; } // get collider parent Transform chunkTransform = hitInfo.collider.transform.parent; if (chunkTransform != null) { // Chunk hit? CubicTerrainChunk chunk = chunkTransform.GetComponent <CubicTerrainChunk>(); if (chunk != null && !chunk.isDirty) { // Yes, chunk hit! BlockHitInfo blockHitInfo = chunk.GetBlockHitInfo(hitInfo); int x = (int)blockHitInfo.hitBlock.x; int y = (int)blockHitInfo.hitBlock.y; int z = (int)blockHitInfo.hitBlock.z; // Which face was hit? calculate target position for the new block switch (blockHitInfo.hitFace) { case BlockFace.LEFT: x -= 1; break; case BlockFace.RIGHT: x += 1; break; case BlockFace.TOP: y += 1; break; case BlockFace.BOTTOM: y -= 1; break; case BlockFace.FRONT: z += 1; break; case BlockFace.BACK: z -= 1; break; } Vector3 chunkPos = chunk.chunkPosition; // Get chunk we want to place the block on if (x < 0) { chunkPos.x -= 1; x = chunk.master.chunkWidth - 1; } if (x >= chunk.master.chunkWidth) { chunkPos.x += 1; x = 0; } if (z < 0) { chunkPos.z -= 1; z = chunk.master.chunkDepth - 1; } if (z >= chunk.master.chunkDepth) { chunkPos.z += 1; z = 0; } // Finally place the object GameObject chunkObject = chunk.master.GetChunkObject((int)chunkPos.x, (int)chunkPos.y, (int)chunkPos.z); chunk = chunkObject.GetComponent <CubicTerrainChunk>(); // Get absolute position Vector3 absoluteVoxelspace = chunk.GetAbsolutePosition(new Vector3(x, y, z)); Debug.Log("Point: " + absoluteVoxelspace); if (firstPoint) { startPoint = absoluteVoxelspace; } else if (lastPoint) { goalPoint = absoluteVoxelspace; } } } } } else { // Cubic World Physics way CubicRaycastHitInfo hitInfo = new CubicRaycastHitInfo(); if (CubicPhysics.TerrainRaycastUnprecise(this.playerCamera.GetComponent <Camera>().ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2)), 5.0f, out hitInfo)) { // Debug.Log ("Hit: " + hitInfo.hitPoint + ", Block: " + hitInfo.blockHit + ", Face: " + hitInfo.faceHit); // Hit block Vector3 topBlock = hitInfo.blockHit + Vector3.up; Debug.Log("Top Block: " + topBlock); if (firstPoint) { startPoint = topBlock; } else if (lastPoint) { goalPoint = topBlock; } } } } if (startPoint != Vector3.zero && goalPoint != Vector3.zero) { Debug.Log("Starting A* path finding. Distance: " + Vector3.Distance(startPoint, goalPoint)); // Start pathfinding CubicPathfinding pathfinder = CubicPathfinding.GetInstance(); this.path = pathfinder.GetPath(startPoint, goalPoint, true); startPoint = Vector3.zero; goalPoint = Vector3.zero; } }
/// <summary> /// Finds the path path. /// </summary> /// <param name="path">Path.</param> private void FindPath(CubicPath path) { // List definitions Dictionary<Vector3, PathNode> openList = new Dictionary<Vector3, PathNode>(); List<Vector3> closedList = new List<Vector3> (); // Start pathfinding PathNode startNode = new PathNode(path.startPos, null, 0, path.goalPos); startNode.owner=startNode; PathNode currentNode = startNode; bool pathFound = false; bool noPath = false; int movementCost = 0; // Measure time System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch (); stopWatch.Start (); try { while (!pathFound && !noPath) { // Calculate block direction positions Vector3[] positions = new Vector3[] { // Front currentNode.position + Vector3.forward, // Back currentNode.position + Vector3.back, // Left currentNode.position + Vector3.left, // Right currentNode.position + Vector3.right, // Front right currentNode.position + Vector3.forward + Vector3.right, // Front left currentNode.position + Vector3.forward + Vector3.left, // Back right currentNode.position + Vector3.back + Vector3.right, // Back left currentNode.position + Vector3.back + Vector3.left, // Up Front currentNode.position + Vector3.forward + Vector3.up, // Up Back currentNode.position + Vector3.back + Vector3.up, // Up Left currentNode.position + Vector3.left + Vector3.up, // Up Right currentNode.position + Vector3.right + Vector3.up, // Down Front currentNode.position + Vector3.forward + Vector3.down, // Down Back currentNode.position + Vector3.back + Vector3.down, // Down Left currentNode.position + Vector3.left + Vector3.down, // Down Right currentNode.position + Vector3.right + Vector3.down, }; // Analyze surrounding path nodes PathNode[] nodes = new PathNode[positions.Length]; PathNode lowestCostNode = null; // Check which ones are walkable and add them to the nodes-array for (int i = 0; i < positions.Length; i++) { // Movement cost from this to the surrounding block int currentMovementCost = (int)(Vector3.Distance(positions[i], currentNode.position)*10); // Check if this node is walkable if (!closedList.Contains(positions[i]) && !this.terrain.HasBlock((int)positions[i].x, (int)positions[i].y, (int)positions[i].z) && // Walkable check (!path.needsGround || this.terrain.HasBlock((int)positions[i].x, (int)positions[i].y-1, (int)positions[i].z))) { // Add node to the nodes-array if (openList.ContainsKey(positions[i])) { nodes[i]=openList[positions[i]]; } else { nodes[i] = new PathNode(positions[i], currentNode, movementCost+currentMovementCost, path.goalPos); openList.Add (positions[i], nodes[i]); } } // Check for lowest cost if (nodes[i] != null && (lowestCostNode == null || nodes[i].completeCost < lowestCostNode.completeCost)) { lowestCostNode = nodes[i]; } } // Failed? o_O if (lowestCostNode == null) { noPath = true; break; } if (currentNode.position == path.goalPos) pathFound=true; // Put the lowest cost node on the closed list if (currentNode.owner.position == lowestCostNode.owner.position) { currentNode.owner.nextNode=lowestCostNode; } else currentNode.nextNode = lowestCostNode; closedList.Add (currentNode.position); currentNode = lowestCostNode; } } catch (System.Exception exception) { // :( noPath=true; } stopWatch.Stop (); // No path found? if (noPath) { // :'( path.SetPathData(null); } else { // :^) // This is needed because in the closedlist there can be movements which are like // front, right // this should be done in one step frontright and this gets achieved by generating an array from the path node's linked list. List<Vector3> pathData = new List<Vector3>(); PathNode cNode = startNode; while (cNode != null) { pathData.Add (cNode.position); cNode = cNode.nextNode; } path.SetPathData(pathData.ToArray()); } // Set runtime path.runtime = (float)stopWatch.Elapsed.TotalMilliseconds; }