/// <summary> /// Recursively travel up the 'parent' chain and construct a list of integer coordinates that form a path. /// </summary> /// <param name="endCell">End of path</param> /// <param name="startCell">Start of path</param> /// <returns>A list of integer axial coordinate arrays that form a path</returns> private List <int[]> ReconstructPath(PathCell endCell, PathCell startCell) { //Create the return list List <int[]> returnList = new List <int[]>(); //If the end cell is the same as the start cell, return an empty list (no path) if (endCell.Equals(startCell)) { return(returnList); } //Create a temporary cell PathCell temp = endCell; do { //Add temp to the return list returnList.Add(new int[] { temp.q, temp.r, temp.h }); //Set temp to it's parent temp = temp.parent; //repeat //Loop while temp has not been set to the start cell } while (!temp.Equals(startCell)); //Finally, add the start cell to the list and return the path returnList.Add(new int[] { startCell.q, startCell.r, startCell.h }); return(returnList); }
/// <summary> /// Update the UI for player movement and item usage /// </summary> /// <returns>Returns true when movement has happened</returns> public bool MovePlayer() { //Check to see if the player is standing on a hex; if so show all valid moves on the minimap. //If the player is standing on a hex (not falling, jumping) if (levelController[q, r, h] != null) { //Get the neighbors of the current hex movable = aiController.ReachableInSteps(new int[] { q, r, h }, 2, actionPoints); //Give all valid neighbors the neighbor material uiController.ShowValidMoves(movable); //Give the current hex the current hex material uiController[q, r, h].gameObject.GetComponent <Renderer>().material = currenthexmaterial; } //Non VR Movement if (!vrActive) { //Get the cell the player is looking at Vector3 lineOfSight = playerCamera.transform.forward * 1000; RaycastHit hit; UICellObj hitObj = null; if (Physics.Raycast(playerCamera.transform.position, lineOfSight, out hit)) { //Get the UI hex cell the player is looking at hitObj = hit.transform.gameObject.GetComponent <UICellObj>() as UICellObj; } //if it isn't null if (hitObj != null) { //get the selected cell PathCell lookedCell = aiController[hitObj.q, hitObj.r, hitObj.h]; PathCell startCell = aiController[q, r, h]; //loop through all cells we're close enough to reach for (int i = 0; i < movable.Count; i++) { foreach (PathCell m in movable[i]) { if (lookedCell.Equals(m) && !lookedCell.Equals(startCell)) { //set the material hitObj.gameObject.GetComponent <Renderer>().material = highlightMaterial; //If the player clicked the mouse if (Input.GetMouseButtonUp(0)) { //Move the player transform.parent.transform.position = levelController[hitObj.q, hitObj.r, hitObj.h].centerPos; //If the target has a goal if (levelController[hitObj.q, hitObj.r, hitObj.h].hasGoal) { //Update the goal levelController.numOfGoals -= 1; levelController[hitObj.q, hitObj.r, hitObj.h].goal.GetComponent <Goal>().Accomplished(); } //Reduce number of player action points remaining actionPoints -= i + 1; //Clear the UI controller uiController.ClearCells(); uiController.setVisibility(false); return(true); } } } } } //VR Specific movement } else { if (vrMoveComplete) { vrMoveComplete = false; return(true); } } //Movement not finished return(false); }
/// <summary> /// A basic implementation of A* /// </summary> /// <param name="startCoords">start hex coordinate array</param> /// <param name="endCoords">end hex coordinate array</param> /// <returns>A list of hex coordinates that form a path. Null if no path possible</returns> public List <int[]> PathBetween(int[] startCoords, int[] endCoords) { //Get references to the start and end path objects PathCell cStart = pathGrid[startCoords[0], startCoords[1], startCoords[2]]; PathCell cEnd = pathGrid[endCoords[0], endCoords[1], endCoords[2]]; //If the start is the end, there is no path if (cStart == null || cEnd == null) { return(null); } //Initialize the open and closed sets. Sets instead of lists because they need to be unique. HashSet <PathCell> closed = new HashSet <PathCell>(); HashSet <PathCell> open = new HashSet <PathCell>(); //Initialize the start node's values cStart.g = DistBetween(cStart, cEnd); open.Add(cStart); //While items exist in the open set while (open.Count > 0) { //Get the lowest g-valued cell; PathCell cCell = null; foreach (PathCell cell in open) { if (cCell == null) { cCell = cell; continue; } if (cCell.g > cell.g) { cCell = cell; } } //If the current cell is the goal, return the found path if (cCell.Equals(cEnd)) { return(ReconstructPath(cCell, cStart)); } //Remove cCell from open and add it to closed open.Remove(cCell); closed.Add(cCell); //Loop through the valid neighbors of cCell foreach (PathCell nCell in ValidNeighbors(cCell)) { //If the neighbor node is already in the closed set, don't evaluate if (closed.Contains(nCell)) { continue; } //If the neighbor isn't in the open set if (!open.Contains(nCell)) { //Initialize it's g-value and parent nCell.g = cCell.g + DistBetween(cCell, nCell); nCell.parent = cCell; //Add it to the open set open.Add(nCell); //Neighbor is already in the open set } else { //If moving from the cCell would be quicker than the current saved path if (nCell.g > cCell.g + DistBetween(cCell, nCell)) { //Override previous shortest-path data to the nCell nCell.g = cCell.g + DistBetween(cCell, nCell); nCell.parent = cCell; } } } } //No path found, return null return(null); }