/// <summary> /// Unity's Update() function called once per step /// </summary> void Update() { //Get player position. Different in VR if (vrActive) { int[] hexCoords = HexConst.CoordToHexIndex(new Vector3(transform.parent.position.x, transform.parent.position.y, transform.parent.position.z)); q = hexCoords[0]; r = hexCoords[1]; h = hexCoords[2]; } else { int[] hexCoords = HexConst.CoordToHexIndex(new Vector3(transform.position.x, transform.position.y, transform.position.z)); q = hexCoords[0]; r = hexCoords[1]; h = hexCoords[2]; } //If player presses "m" to start acting, isn't yet acting, and has enough action points to do so if (Input.GetKeyUp("m")) { StartMove(); } if (Input.GetKeyUp(KeyCode.Alpha1) && actionPoints > 0 && this.hasFireball) { StartFireball(); } //Cancel abilities if (Input.GetKeyUp(KeyCode.Escape)) { CancelAction(); } }
/// <summary> /// Get coordinates in a radius around center. This is a private split out function for radial selections /// </summary> /// <param name="q">column</param> /// <param name="r">row</param> /// <param name="radius">radius</param> /// <param name="includeOrigin">include the origin coordinates?</param> /// <returns></returns> private List <int[]> GetAxialCoordsInRadius(int q, int r, int radius, bool includeOrigin) { //Convert the given axial coordinate to cube coordinates int[] cCoords = HexConst.AxialToCube(q, r, 0); //Store found axial coordinates in a list List <int[]> aCoords = new List <int[]>(); //Loop from -radius to +radius on the x-axis for (int dx = -1 * radius; dx <= radius; dx++) { //Loop from -radius (constrained by the x radius) to +radius (also constrained by the x radius) on the y axis for (int dy = Math.Max(-radius, -dx - radius); dy <= Math.Min(radius, -dx + radius); dy++) { //Grab the final z coordinate int dz = -dx - dy; //include the origin cell in the return? if (includeOrigin == false && dx == 0 && dy == 0 && dz == 0) { continue; } //Convert the location back to axial coordinates and add it to the list aCoords.Add(new int[] { cCoords[0] + dx, cCoords[2] + dz }); } } return(aCoords); }
/// <summary> /// Constructor /// </summary> /// <param name="q">column</param> /// <param name="r">row</param> /// <param name="h">height</param> public HexCell(int q, int r, int h) { this.q = q; this.r = r; this.h = h; this.centerPos = HexConst.HexToWorldCoord(q, r, h); }
/// <summary> /// Step towards the player along a path /// Assumes pathToPlayer is not null /// </summary> /// <returns>Returns true when move action has finished</returns> public bool MoveToPlayer() { //If the monster is already adjacent to the player if (curPInd == pathToPlayer.Count - 2) { //don't move more return(true); } //Get the move destination by converting it's hex coordinates to a world position Vector3 movementDest = HexConst.HexToWorldCoord(pathToPlayer[movementSpeed][0], pathToPlayer[movementSpeed][1], pathToPlayer[movementSpeed][2]) + new Vector3(0, 0.8f, 0); //If this monster has reached the target destination if ((transform.position - movementDest).magnitude < 0.2f) { //Set the transform position to equal the destination transform.position = movementDest; //Return true since movement has ended return(true); } //Get the 'next waypoint' to move towards. This is simply the next cell in the path's world coordinates Vector3 nextWaypoint = HexConst.HexToWorldCoord(pathToPlayer[curPInd + 1][0], pathToPlayer[curPInd + 1][1], pathToPlayer[curPInd + 1][2]) + new Vector3(0, 0.8f, 0); //Step towards the waypoint transform.position = Vector3.MoveTowards(transform.position, nextWaypoint, realtimeSpeed * Time.deltaTime); //If next waypoint has been reached, move on to the next one if ((transform.position - nextWaypoint).magnitude < 0.2f) { curPInd++; } //If logic has made it this far, movement is not over. return(false); }
/// <summary> /// Get the distance between 2 cells (in hex cells) /// Basically, how many cells are needed to traverse from p1 to p2 /// NOTE: Does not account for height differences /// </summary> /// <param name="cell1">Start cell</param> /// <param name="cell2">End cell</param> /// <returns>Integer cell distance</returns> public int DistBetween(PathCell cell1, PathCell cell2) { //Convert the axial coordinates to cube coordinates for both cells int[] ac = HexConst.AxialToCube(cell1.q, cell1.r, cell1.h); int[] bc = HexConst.AxialToCube(cell2.q, cell2.r, cell2.h); //Calculate the cell distance return(((int)Mathf.Abs(ac[0] - bc[0]) + (int)Mathf.Abs(ac[1] - bc[1]) + (int)Mathf.Abs(ac[2] - bc[2])) / 2); }
public void vrMove(Vector3 targetPosition) { int[] figurePositionHex = HexConst.CoordToHexIndex(targetPosition); transform.position = levelController[figurePositionHex[0], figurePositionHex[1], figurePositionHex[2]].centerPos; actionPoints -= 1; uiController.ClearCells(); uiController.setVisibility(false); vrMoveComplete = true; }
/// <summary> /// End of turn code for housekeeping /// </summary> /// <returns>Always returns true. Allows you to replace "return true" with "return EndTurn()"</returns> public bool EndTurn() { //Reset path to player pathToPlayer = null; //Update the AI controller to show an enemy is standing on the tile curCell = HexConst.CoordToHexIndex(transform.position - new Vector3(0, 0.8f, 0)); aiController[curCell[0], curCell[1], curCell[2]].hasEnemy = true; return(true); }
/// <summary> /// Unity start method /// </summary> void Start() { //Grab required references player = GameObject.FindGameObjectWithTag("Player"); aiController = GameObject.Find("AIController").GetComponent <AIController>() as AIController; levelController = GameObject.Find("LevelController").GetComponent <LevelController>() as LevelController; curCell = HexConst.CoordToHexIndex(transform.position - new Vector3(0, 0.8f, 0)); //Add self to the list of monsters aiController.monsters.Add(this); }
/// <summary> /// Unity's start function /// </summary> void Start() { //get the goal's model height so we can properly determine the cell it is on float modelHeight = gameObject.GetComponent <Renderer>().bounds.size.y; //Get the hex index for this hex cell. Pass in the transform. int[] thisHexIndex = HexConst.CoordToHexIndex(transform.position + new Vector3(0, -0.5f * modelHeight, 0)); q = thisHexIndex[0]; r = thisHexIndex[1]; h = thisHexIndex[2]; }
/// <summary> /// Create player figure if there isnt already one /// </summary> void spawnPlayerFigure() { if (!playerFigure) { playerFigure = (GameObject)Instantiate(playerFigurePrefab, transform.position, transform.rotation); playerFigure.transform.SetParent(gameObject.transform); //Subtract the player position figurePositionHex = HexConst.CoordToHexIndex(new Vector3(playerFigure.transform.position.x - transform.parent.position.x, playerFigure.transform.position.y - transform.parent.position.y, playerFigure.transform.position.z - transform.parent.position.z)); } else { playerFigure.transform.position = this.transform.position; } }
/// <summary> /// Create player figure if there isnt already one /// </summary> void spawnPlayerFigure() { if (!playerFigure) { playerFigure = (GameObject)Instantiate(playerFigurePrefab, transform.position, transform.rotation); playerFigure.transform.SetParent(gameObject.transform); //Subtract the player position figurePositionHex = HexConst.CoordToHexIndex(new Vector3(playerFigure.transform.position.x - transform.parent.position.x, playerFigure.transform.position.y - transform.parent.position.y, playerFigure.transform.position.z - transform.parent.position.z)); } else { playerFigure.transform.position = HexConst.HexToWorldCoord(player.q, player.r, player.h) + uiControllerCenterPos; } }
/// <summary> /// Unity draw gizmos function. This is just a debug to draw pathfinding data in the world /// </summary> void OnDrawGizmos() { //If the path exists if (pathToPlayer != null) { Gizmos.color = Color.cyan; //Loop through the path and draw a line between all cells to form a path. for (int i = 1; i < pathToPlayer.Count; i++) { Vector3 curCoords = HexConst.HexToWorldCoord(pathToPlayer[i][0], pathToPlayer[i][1], pathToPlayer[i][2]) + new Vector3(0, 1, 0); Vector3 prevCoords = HexConst.HexToWorldCoord(pathToPlayer[i - 1][0], pathToPlayer[i - 1][1], pathToPlayer[i - 1][2]) + new Vector3(0, 1, 0); Gizmos.DrawLine(curCoords, prevCoords); } } }
private static void MenuSnapToGrid() { //Loop through all gameobjects (this could be really clunky) //TODO: Find a better way of getting hex cells foreach (Transform transform in Selection.GetTransforms(SelectionMode.TopLevel | SelectionMode.OnlyUserModifiable)) { //If the object's transform is named "HexCell", it is a snap-able hex cell if (transform.name.Contains("HexCell")) { float modelHeight = transform.gameObject.GetComponent <Renderer>().bounds.size.y; //Get the hex coordinates the object is overlapping with int[] hexCoords = HexConst.CoordToHexIndex(transform.position + new Vector3(0, modelHeight / 2, 0)); //Move this object to the specific grid-aligned coordinates. transform.position = HexConst.HexToWorldCoord(hexCoords[0], hexCoords[1], hexCoords[2]); transform.position = transform.position - new Vector3(0, modelHeight / 2, 0); } } }
/// <summary> /// Unity start method /// </summary> void Start() { //Get the model height & scale from the renderer modelHeight = gameObject.GetComponent <Renderer>().bounds.size.y; modelScale = gameObject.transform.localScale.y; //Get a reference to the level controller LevelController levelController = GameObject.Find("LevelController").GetComponent("LevelController") as LevelController; //Get the hex index for this hex cell. Pass in the transform. //Use the model height to allow for y-scaling. This lets the engine handle hex cell models with variable heights int[] thisHexIndex = HexConst.CoordToHexIndex(transform.position + new Vector3(0, 0.5f * modelHeight, 0)); q = thisHexIndex[0]; r = thisHexIndex[1]; h = thisHexIndex[2]; //Tell the level controller to initialize this hex cell levelController.AddCell(q, r, h, gameObject); }
/// <summary> /// Unity start method /// </summary> void Start() { //Grab required references player = GameObject.FindGameObjectWithTag("Player"); aiController = GameObject.Find("AIController").GetComponent <AIController>() as AIController; levelController = GameObject.Find("LevelController").GetComponent <LevelController>() as LevelController; //Set full bounds of prefab foreach (Renderer renderer in gameObject.GetComponentsInChildren <Renderer>()) { if (renderer != gameObject.GetComponentInChildren <Renderer>()) { gameObject.GetComponentInChildren <Renderer>().bounds.Encapsulate(renderer.bounds); } } modelHeight = gameObject.GetComponentInChildren <Renderer> ().bounds.size.y; curCell = HexConst.CoordToHexIndex(transform.position - new Vector3(0, originVertOffset, 0)); //Add self to the list of monsters aiController.monsters.Add(this); }
/// <summary> /// Scales the controller position to world UI coordinates ans snaps to a grid /// </summary> /// <param></param> /// <returns></returns> void convertControllerPosition() { Vector3 scaledControllerPosition = new Vector3(controller.transform.parent.transform.localPosition.x, controller.transform.parent.transform.localPosition.y - 1, controller.transform.parent.transform.localPosition.z); scaledControllerPosition = scaledControllerPosition * 50; int[] figurePositionHex = HexConst.CoordToHexIndex(scaledControllerPosition); Vector3 newPosition = HexConst.HexToWorldCoord(figurePositionHex [0], figurePositionHex [1], figurePositionHex [2]); if (levelController.levelGrid.GetHex(figurePositionHex [0], figurePositionHex [1], figurePositionHex [2]) != null) { drawLine(newPosition * 0.02f, Color.green); createDestinationObject(newPosition); } else { //Destroy (instantiatedHolographicFigure); drawLine(newPosition * 0.02f, Color.red); } }
/// <summary> /// Unity's Update() function called once per step /// </summary> void Update() { //Get player position. Different in VR if (vrActive) { int[] hexCoords = HexConst.CoordToHexIndex(new Vector3(transform.position.x, uiController.transform.position.y, transform.position.z)); q = hexCoords[0]; r = hexCoords[1]; h = hexCoords[2]; } else { int[] hexCoords = HexConst.CoordToHexIndex(new Vector3(transform.position.x, transform.position.y, transform.position.z)); q = hexCoords[0]; r = hexCoords[1]; h = hexCoords[2]; } //If player presses "m" to start acting, isn't yet acting, and has enough action points to do so if (Input.GetKeyUp("m") && actionPoints > 0) { //Start action this.playerActing = true; this.currentAction = AbilityEnum.MOVE_PLAYER; uiController.setVisibility(true); } if (Input.GetKeyUp(KeyCode.Alpha1) && actionPoints > 0) { this.playerActing = true; this.currentAction = AbilityEnum.FIREBALL; uiController.setVisibility(true); } //Cancel abilities if (Input.GetKeyUp(KeyCode.Escape)) { this.playerActing = false; this.currentAction = AbilityEnum.NOT_USING_ABILITIES; uiController.setVisibility(false); } }
/// <summary> /// Enable/Disable the renderer this will eventually become on/off for the minimap /// </summary> public void setVisibility(bool visible) { //Show UI if (visible) { //Get cells in a radius UICell[] toDisplay = uiGrid.TopDownRadius(player.q, player.r, player.h, 8, true); //Display them all foreach (UICell c in toDisplay) { c.Display(true); } //Center the minimap Vector3 translationVec = HexConst.HexToWorldCoord(player.q, player.r, player.h) + uiControllerCenterPos - uiGrid[player.q, player.r, player.h].gameObject.transform.position; gameObject.transform.position += translationVec; //Show player figure spawnPlayerFigure(); foreach (MeshRenderer r in playerFigure.GetComponentsInChildren <MeshRenderer>()) { r.enabled = true; } //Hide UI } else { //Hide all UICells foreach (UICell c in uiGrid) { c.Display(false); } //Hide player figure foreach (MeshRenderer r in playerFigure.GetComponentsInChildren <MeshRenderer>()) { r.enabled = false; } } }
/// <summary> /// Called by a canvas button when minimap is open, Moves the player to the hex corresponding to the player figure /// </summary> public void doMove() { //Subtract the player position Vector3 scaledFigurePosition = new Vector3(playerFigure.transform.position.x - transform.parent.position.x, playerFigure.transform.position.y - transform.parent.position.y, playerFigure.transform.position.z - transform.parent.position.z); //Scale up the position from the miniature to full scale and reset the y axis scaledFigurePosition = scaledFigurePosition * 50; scaledFigurePosition.y = scaledFigurePosition.y - 50; //Convert the position into hex coordinates and move the player int[] figurePositionHex = HexConst.CoordToHexIndex(scaledFigurePosition); if (levelController.levelGrid.GetHex(figurePositionHex[0], figurePositionHex[1], figurePositionHex[2]) != null) { print("There is a Hex Here"); Vector3 newPosition = HexConst.HexToWorldCoord(figurePositionHex[0], figurePositionHex[1], figurePositionHex[2]); GameObject.FindGameObjectWithTag("Player").transform.position = newPosition; ClearCells(); } else { Debug.LogError("OH NO!! THERE IS NO HEX WHERE THE PLAYER FIGURE IS!!" + "q: " + figurePositionHex[0] + "r: " + figurePositionHex[1] + "h: " + figurePositionHex[2]); } }
/// <summary> /// Called every step on this monsters turn /// Logically flows through different stages of the monster and updates it in the world, returning true once this monster's turn is over /// </summary> /// <returns>turn is over?</returns> public bool TakeTurn() { //Monster has action points left? if (this.actionPoints > 0) { //If there is not a current path to the player if (pathToPlayer == null) { //Get player positino Vector3 playerPos = player.GetComponent <Transform>().position; //Get the current cell and the player's cell curCell = HexConst.CoordToHexIndex(transform.position - new Vector3(0, 0.8f, 0)); playerCell = HexConst.CoordToHexIndex(playerPos); //Update the AI controller. This monster will be moving off it's current cell aiController[curCell[0], curCell[1], curCell[2]].hasEnemy = false; //Try to path from this cell to the player's cell pathToPlayer = aiController.PathBetween(playerCell, curCell); //If there is no valid path, end turn if (pathToPlayer == null) { return(EndTurn()); } //Start the path index at 0 curPInd = 0; //There is a path //If the player is within <aggroRadius> hexes } else if (pathToPlayer.Count - 1 <= aggroRadius && pathToPlayer.Count > 2) { //Stall the logic by repeatedly calling MoveToPlayer() until it returns true if (this.MoveToPlayer()) { pathToPlayer = null; actionPoints -= 1; } //Player is within Melee range } else if (pathToPlayer.Count == 2) { //TODO: Attack player. For now, if a monster detects it can attack the player, the player loses //End the game in a failure state levelController.EndGame(false); //Turn a different color so the player knows what attacked them gameObject.GetComponent <Renderer>().material = attackMaterial; //Reset everything pathToPlayer = null; actionPoints -= 1; } else { //Player not close enough to do anything, end turn return(EndTurn()); } //Turn is over, end it } else { return(EndTurn()); } //If the logic made it this far, the turn is not over return(false); }