/// <summary> /// Get manhatten distance from start tile to end tile /// </summary> /// <param name="a_nodeA"></param> /// <param name="a_nodeB"></param> /// <returns></returns> public int GetManhattenDistance(GridTileInfo a_nodeA, GridTileInfo a_nodeB) { int ix = Mathf.Abs(a_nodeA.xCoord - a_nodeB.xCoord); //x1 - x2 int iy = Mathf.Abs(a_nodeA.zCoord - a_nodeB.zCoord); //z1 - z2 return(ix + iy); //Return the sum }
// Update is called once per frame void Update() { ControlTurnTips(); // Update different UI tips about game phase // Player input currentMouseOverTile = null; // Clear the last hovered tile // If the player cursor is not on UI element if (!EventSystem.current.IsPointerOverGameObject()) { // If the player cursor is on a tile RaycastHit hit; if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, Mathf.Infinity)) { // Debug.Log(hit.collider.tag); if (hit.collider.tag == "Tile") { currentMouseOverTile = hit.collider.GetComponent <GridTileInfo>(); } } // If the player cursor is on a tile if (currentMouseOverTile != null) { PlayerHoverTile(currentMouseOverTile); // If the player clicked LMB on hovering tile if (Input.GetMouseButtonDown(0)) { PlayerSelectedTile(currentMouseOverTile); } } } }
/// <summary> /// When player finish current turn /// </summary> public void PlayerFinishTurn() { // Player cannot finish turn when an unit is still in animation if (inPlayerUnitAnimation) { return; } playerTurn = false; currentSelectedUnitTile = null; // Clear map marks bool[] clearFlags = { true, true }; ClearMapMarks(clearFlags); // If there is no more enemy left in this level if (EnemyManager.thisLevelEnemies.Count == 0) { GameManager.sGameManager.LevelFinished(); // Finish current level and enters evolve phase } else { // Zoom out camera if (!GameManager.cameraZoomedOut) { GameManager.sGameManager.ZoomCamera(); } enemyTurnTip.SetActive(true); // Show enemy turn UI tip StartCoroutine(EnemyManager.sEnemyManager.ActEnemies()); // Start enemy turn } }
public static void CreateMap() { MapManager instance = (MapManager)FindObjectOfType(typeof(MapManager)); instance.currentMap = new GridTileInfo[instance.mapSizeX, instance.mapSizeZ]; GameObject newMapObject = Instantiate(new GameObject(), Vector3.zero, Quaternion.identity); newMapObject.name = "Grid"; for (int i = 0; i < instance.mapSizeX; i++) { GameObject newColumnObject = Instantiate(new GameObject(), newMapObject.transform); newColumnObject.name = "Column_" + i.ToString(); for (int j = 0; j < instance.mapSizeZ; j++) { GameObject newTile = Instantiate(instance.tilePrefab, Vector3.right * i + Vector3.forward * j, instance.tilePrefab.transform.rotation); newTile.transform.parent = newColumnObject.transform; GridTileInfo newTileInfo = newTile.GetComponent <GridTileInfo>(); newTileInfo.xCoord = i; newTileInfo.zCoord = j; instance.currentMap[i, j] = newTileInfo; } } }
public override void OnInspectorGUI() { GUIStyle style = new GUIStyle(); bool showClose = true; base.OnInspectorGUI(); //test = false; ScriptableObjectGridStructure origin = (ScriptableObjectGridStructure)target; BattleTileInfo bti; GridTileInfo gti = null; if (origin.GridInfo.Count > 0) { EditorGUILayout.Space(); for (int x = 0; x < 6; x++) { EditorGUILayout.BeginHorizontal(); for (int y = 0; y < 12; y++) { //Debug.Log(x + " " + y); bti = origin.GridInfo.Where(r => r.Pos == new Vector2Int(x, y)).First(); bti.name = x + "," + y; if (firstOpen) { gti = new GridTileInfo(new Vector2Int(x, y), bti); TilesInfo.Add(gti, bti.BattleTileState == BattleTileStateType.Empty ? true : false); } else { gti = TilesInfo.Where(r => r.Key.Pos == new Vector2Int(x, y)).First().Key; } showClose = EditorGUILayout.ToggleLeft(x + "," + y, TilesInfo.Where(r => r.Key.Pos == new Vector2Int(x, y)).First().Value, GUILayout.Width(40)); if (showClose != TilesInfo[gti]) { if (showClose) { differentGti = gti; } else { differentGti = null; } } TilesInfo[gti] = showClose; bti.BattleTileState = showClose ? BattleTileStateType.Empty : BattleTileStateType.Blocked; //Debug.Log(showClose); } EditorGUILayout.EndHorizontal(); } if (differentGti != null) { ShowTileObject(ref differentGti.Tile); } firstOpen = false; } EditorUtility.SetDirty(origin); }
public ScenarioData(int xTiles, int zTiles) { gridWidth = xTiles; gridHeight = zTiles; tileArray = new GridTileInfo[xTiles, zTiles]; for (int i = 0; i < xTiles; i++) { for (int j = 0; j < zTiles; j++) { tileArray [i, j] = new GridTileInfo(); } } }
/// <summary> /// Return a list of GridTileInfo that represents the shortest path from start tile to end tile /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <returns></returns> public List <GridTileInfo> FindPath(GridTileInfo start, GridTileInfo end) { List <GridTileInfo> OpenList = new List <GridTileInfo>(); //List of nodes for the open list HashSet <GridTileInfo> ClosedList = new HashSet <GridTileInfo>(); //Hashset of nodes for the closed list OpenList.Add(start); //Add the starting node to the open list to begin the program while (OpenList.Count > 0) //Whilst there is something in the open list { GridTileInfo CurrentNode = OpenList[0]; //Create a node and set it to the first item in the open list for (int i = 1; i < OpenList.Count; i++) //Loop through the open list starting from the second object { if (OpenList[i].ihCost + OpenList[i].igCost < CurrentNode.ihCost + CurrentNode.igCost || OpenList[i].ihCost + OpenList[i].igCost == CurrentNode.ihCost + CurrentNode.igCost && OpenList[i].ihCost < CurrentNode.ihCost) //If the f cost of that object is less than or equal to the f cost of the current node { CurrentNode = OpenList[i]; //Set the current node to that object } } OpenList.Remove(CurrentNode); //Remove that from the open list ClosedList.Add(CurrentNode); //And add it to the closed list if (CurrentNode == end) //If the current node is the same as the target node { return(GetFinalPath(start, end)); //Calculate the final path } foreach (GridTileInfo NeighborNode in GetNeighboringNodes(CurrentNode)) //Loop through each neighbor of the current node { if (NeighborNode.isObstacle || (NeighborNode.containingObject != null && NeighborNode != end) || ClosedList.Contains(NeighborNode)) //If the neighbor is a wall or (not empty and not the end node) or has already been checked { continue; //Skip it } int MoveCost = CurrentNode.igCost + GetManhattenDistance(CurrentNode, NeighborNode); //Get the F cost of that neighbor if (MoveCost < NeighborNode.igCost || !OpenList.Contains(NeighborNode)) //If the f cost is greater than the g cost or it is not in the open list { NeighborNode.igCost = MoveCost; //Set the g cost to the f cost NeighborNode.ihCost = GetManhattenDistance(NeighborNode, end); //Set the h cost NeighborNode.parentTile = CurrentNode; //Set the parent of the node for retracing steps if (!OpenList.Contains(NeighborNode)) //If the neighbor is not in the openlist { OpenList.Add(NeighborNode); //Add it to the list } } } } // Return null if cannot find path return(null); }
/// <summary> /// Return a list of neighbor tiles of a tile /// </summary> /// <param name="checkedTile"></param> /// <returns></returns> public static List <GridTileInfo> GetNeighboringNodes(GridTileInfo checkedTile) { List <GridTileInfo> NeighborList = new List <GridTileInfo>(); //Make a new list of all available neighbors. int icheckX; //Variable to check if the XPosition is within range of the node array to avoid out of range errors. int icheckZ; //Variable to check if the ZPosition is within range of the node array to avoid out of range errors. //Check the right side of the current node. icheckX = checkedTile.xCoord + 1; icheckZ = checkedTile.zCoord; if (icheckX >= 0 && icheckX < sMapManager.mapSizeX) //If the XPosition is in range of the array { if (icheckZ >= 0 && icheckZ < sMapManager.mapSizeZ) //If the YPosition is in range of the array { NeighborList.Add(sMapManager.currentMap[icheckX, icheckZ]); //Add the grid to the available neighbors list } } //Check the Left side of the current node. icheckX = checkedTile.xCoord - 1; icheckZ = checkedTile.zCoord; if (icheckX >= 0 && icheckX < sMapManager.mapSizeX) //If the XPosition is in range of the array { if (icheckZ >= 0 && icheckZ < sMapManager.mapSizeZ) //If the YPosition is in range of the array { NeighborList.Add(sMapManager.currentMap[icheckX, icheckZ]); //Add the grid to the available neighbors list } } //Check the Top side of the current node. icheckX = checkedTile.xCoord; icheckZ = checkedTile.zCoord + 1; if (icheckX >= 0 && icheckX < sMapManager.mapSizeX) //If the XPosition is in range of the array { if (icheckZ >= 0 && icheckZ < sMapManager.mapSizeZ) //If the YPosition is in range of the array { NeighborList.Add(sMapManager.currentMap[icheckX, icheckZ]); //Add the grid to the available neighbors list } } //Check the Bottom side of the current node. icheckX = checkedTile.xCoord; icheckZ = checkedTile.zCoord - 1; if (icheckX >= 0 && icheckX < sMapManager.mapSizeX) //If the XPosition is in range of the array { if (icheckZ >= 0 && icheckZ < sMapManager.mapSizeZ) //If the YPosition is in range of the array { NeighborList.Add(sMapManager.currentMap[icheckX, icheckZ]); //Add the grid to the available neighbors list } } return(NeighborList);//Return the neighbors list. }
/// <summary> /// Update the player units that are reproducing /// </summary> public IEnumerator UpdateReproducingPlayerUnits() { reproductionPhaseTip.SetActive(true); // Show reproduction phase UI tip foreach (PlayerUnit p in GameManager.playerUnits) { // Wait if there is a player unit currently ready to reproduce while (playerUnitReproducing) { yield return(null); } yield return(new WaitForSeconds(p.moveAnimationInterval)); // Focus cam on reproducing unit p.turnsLeftForReproduce--; // If the clone is ready to reproduce if (p.turnsLeftForReproduce == 0) { // If there is empty neighbor to place new clone if (ShowRange(p.GetComponent <MapObjectInfo>().currentOccupyingTile, 1, true) > 0) { currentSelectedUnitTile = p.GetComponent <MapObjectInfo>().currentOccupyingTile; playerUnitReproducing = true; } } } reproductionPhaseTip.SetActive(false); // Hide reproduction phase UI tip // Copy new clones to player unit list in GameManager foreach (PlayerUnit p in newCloneReproduced) { GameManager.playerUnits.Add(p); } // Clear new clone list newCloneReproduced.Clear(); // Make existing player units be able to move in the next turn foreach (PlayerUnit p in GameManager.playerUnits) { p.hasMoved = false; } playerTurn = true; // Let player play the turn }
public List <GridTileInfo> GetFinalPath(GridTileInfo start, GridTileInfo end) { List <GridTileInfo> finalPath = new List <GridTileInfo>(); //List to hold the path sequentially GridTileInfo currentTile = end; //Node to store the current node being checked while (currentTile != start) //While loop to work through each node going through the parents to the beginning of the path { finalPath.Add(currentTile); //Add that node to the final path currentTile = currentTile.parentTile; //Move onto its parent node } finalPath.Reverse(); //Reverse the path to get the correct order return(finalPath); //Return the final path }
/// <summary> /// Find a route /// </summary> /// <returns></returns> public List <GridTileInfo> FindRoute() { int shortestRoute = MapManager.sMapManager.mapSizeX * MapManager.sMapManager.mapSizeZ; GridTileInfo occupyingTile = GetComponent <MapObjectInfo>().currentOccupyingTile; List <GridTileInfo> finalRoute = null; // Test all player units foreach (PlayerUnit p in GameManager.playerUnits) { // Try to get a route to p List <GridTileInfo> route = MapManager.sMapManager.FindPath(occupyingTile, p.GetComponent <MapObjectInfo>().currentOccupyingTile); // If there is a route and the route is currently the shortest if (route != null && route.Count < shortestRoute) { shortestRoute = route.Count; finalRoute = route; } } return(finalRoute); // If there is no player unit that is reachable by this enemy if (finalRoute == null) { PlayerUnit closestPlayerUnit = null; // Test all player manhatten distance foreach (PlayerUnit p in GameManager.playerUnits) { // Get manhatten distance int distance = MapManager.sMapManager.GetManhattenDistance(occupyingTile, p.GetComponent <MapObjectInfo>().currentOccupyingTile); // If this player has the closest manhatten distance if (distance < shortestRoute) { shortestRoute = distance; closestPlayerUnit = p; } } } else { return(finalRoute); } }
public List <IntPoint2D> GetAdjacentRoadTiles(IntPoint2D startTile) { List <IntPoint2D> tileList = new List <IntPoint2D> (); GridTileInfo tileInfo = tileArray [startTile.xCoord, startTile.yCoord]; if (tileInfo.IsRoad()) { tileList.Add(startTile); } else { IntPoint2D topLeft = startTile; int sideLen = 1; if (!tileInfo.IsClear()) { topLeft = tileInfo.GetTopLeftOfBuilding(); sideLen = tileInfo.GetSides(); } // now we need to check each adjacent tile for (int step = 0; step < sideLen; step++) { IntPoint2D tileLoc = new IntPoint2D(topLeft.xCoord + step, topLeft.yCoord - 1); if (IsRoadTile(tileLoc)) { tileList.Add(tileLoc); } tileLoc = new IntPoint2D(topLeft.xCoord + step, topLeft.yCoord + sideLen); if (IsRoadTile(tileLoc)) { tileList.Add(tileLoc); } tileLoc = new IntPoint2D(topLeft.xCoord - 1, topLeft.yCoord + step); if (IsRoadTile(tileLoc)) { tileList.Add(tileLoc); } tileLoc = new IntPoint2D(topLeft.xCoord + sideLen, topLeft.yCoord + step); if (IsRoadTile(tileLoc)) { tileList.Add(tileLoc); } } } return(tileList); }
/// <summary> /// When player selected a unit /// </summary> /// <param name="selectedUnit"></param> //public void PlayerSelectUnit(PlayerUnit selectedUnit) //{ //} /// <summary> /// When player ended a unit's act /// </summary> public void UnitFinishAct() { // Mark the selected unit as moved currentSelectedUnitTile.containingObject.GetComponent <PlayerUnit>().hasMoved = true; currentSelectedUnitTile = null; // Clear previous map marks bool[] clearFlags = { true, true }; ClearMapMarks(clearFlags); // Mark the player finished an unit's act, and can select other unit playerUnitAct = false; // Check if finish turn if (!GameManager.playerUnits.Exists(u => (!u.hasMoved || !u.isReproducing))) { PlayerFinishTurn(); } }
/// <summary> /// Show the path from the selected player clone tile to the player selected destination tile /// </summary> /// <param name="selectedTile"></param> /// <param name="destinationTile"></param> public void ShowPath(GridTileInfo selectedTile, GridTileInfo destinationTile) { // Clear previous map marks bool[] clearFlags = { false, true }; ClearMapMarks(clearFlags); // Show route List <GridTileInfo> route = MapManager.sMapManager.FindPath(selectedTile, destinationTile); if (route == null || route.Count > currentSelectedUnitTile.containingObject.GetComponent <PlayerUnit>().moveRange) { // No valid route } else { foreach (GridTileInfo tile in MapManager.sMapManager.FindPath(selectedTile, destinationTile)) { tile.marks[1].SetActive(true); } } }
/// <summary> /// Show a range for the current action of the current selected player unit /// Can show move range, attack range, etc. /// </summary> /// <param name="selectedTile"></param> /// <param name="range"></param> /// <param name="isEmpty"></param> /// <returns></returns> public int ShowRange(GridTileInfo selectedTile, int range, bool isEmpty) { // Clear previous map marks bool[] clearFlags = { true, true }; ClearMapMarks(clearFlags); int availableTileCount = 0; // Show range foreach (GridTileInfo tile in MapManager.sMapManager.currentMap) { // If tile is not obstacle and empty (if showed tile has to be empty) if (!tile.isObstacle && (tile.containingObject == null || !isEmpty) && MapManager.sMapManager.GetManhattenDistance(selectedTile, tile) <= range) { tile.marks[0].SetActive(true); // Count available tile availableTileCount++; } } return(availableTileCount); }
public IEnumerator UnitReproduce(GridTileInfo targetTile) { yield return(new WaitForSeconds(moveAnimationInterval)); GameObject newClone = Instantiate(gameObject); PlayerUnit newCloneUnit = newClone.GetComponent <PlayerUnit>(); newCloneUnit.GetComponent <MapObjectInfo>().currentOccupyingTile = null; // Reset new clone's MapObjectInfo's occupying tile info, because it has not been placed on the map yet // Place new clone on target tile MapManager.PlaceObject(newClone.transform, targetTile.xCoord, targetTile.zCoord); newCloneUnit.InitiateClone(); // Add new clone to new clone list TurnManager.newCloneReproduced.Add(newCloneUnit); // Clear selected tile in TurnManager; TurnManager.currentSelectedUnitTile = null; yield return(new WaitForSeconds(moveAnimationInterval)); // If new clone meet the win requirement if (GameManager.sGameManager.CheckWinCondition(newCloneUnit)) { //GameManager.playerUnits.Add(newCloneUnit); GameManager.sGameManager.PlayerWin(); } // Finish reproduction TurnManager.playerUnitReproducing = false; isReproducing = false; // Finish animation TurnManager.inPlayerUnitAnimation = false; }
/// <summary> /// When player clicked on a tile /// </summary> /// <param name="selectedTile"></param> public void PlayerSelectedTile(GridTileInfo selectedTile) { // Player cannot select tile during an unit animation if (inPlayerUnitAnimation) { return; } // If it's currently in evolve phase if (GameManager.inEvolvePhase) { // If player selected a clone unit if (selectedTile.containingObject != null) { // Open evolve shop for the selected unit GameManager.sGameManager.StartEvolve(selectedTile.containingObject.GetComponent <PlayerUnit>()); } return; } // If one of the player's unit is ready to reproduce if (playerUnitReproducing) { // If the player selected a valid tile if (selectedTile.marks[0].activeInHierarchy) { inPlayerUnitAnimation = true; // Start animation StartCoroutine(currentSelectedUnitTile.containingObject.GetComponent <PlayerUnit>().UnitReproduce(selectedTile)); } // Stop player from doing other things before finish the reproduction phase return; } // Player cannot select tile when it's not player's turn if (!playerTurn) { return; } // If there is no unit that has moved but did not finish act yet if (!playerUnitAct) { // If the player selected a tile with a player unit if (selectedTile.containingObject != null && selectedTile.containingObject.GetComponent <PlayerUnit>()) { PlayerUnit selectedUnit = selectedTile.containingObject.GetComponent <PlayerUnit>(); // If the unit has not moved in this turn yet and is not reproducing if (!selectedUnit.hasMoved && !selectedUnit.isReproducing) { currentSelectedUnitTile = selectedTile; // Show move range of just selected unit ShowRange(selectedTile, selectedUnit.moveRange, true); } } // If the player selected a tile with no object and there is already a selected unit and the selected tile is within move range if (currentSelectedUnitTile != null && selectedTile.containingObject == null && selectedTile.marks[1].activeInHierarchy) { // Clear previous map marks bool[] clearFlags = { true, true }; ClearMapMarks(clearFlags); // If their is a valid path to the selected tile List <GridTileInfo> path = MapManager.sMapManager.FindPath(currentSelectedUnitTile, selectedTile); if (path != null) { inPlayerUnitAnimation = true; // Start animation // Start move player unit StartCoroutine(currentSelectedUnitTile.containingObject.GetComponent <PlayerUnit>().UnitMove(path)); } } } else { // If the player selected an enemy that's within range if (selectedTile.marks[0].activeInHierarchy && selectedTile.containingObject != null && selectedTile.containingObject.GetComponent <EnemyUnit>()) { inPlayerUnitAnimation = true; // Start animation StartCoroutine(currentSelectedUnitTile.containingObject.GetComponent <PlayerUnit>().UnitAttack(selectedTile.containingObject.GetComponent <EnemyUnit>())); // Unit attack selected enemy } } }
/// <summary> /// If the player hover the mouse above a tile /// </summary> /// <param name="hoverTile"></param> public void PlayerHoverTile(GridTileInfo hoverTile) { // Player cannot select tile when it's not player's turn if (!playerTurn) { // If there is a player unit ready to reproduce if (playerUnitReproducing) { // Clear previous map marks bool[] clearFlags = { false, true }; ClearMapMarks(clearFlags); // If the hovered tile is valid for place new clone if (hoverTile.marks[0].activeInHierarchy) { hoverTile.marks[1].SetActive(true); // Highlight hovering tile } } return; } // If player did not select a unit if (currentSelectedUnitTile == null) { // Clear previous map marks bool[] clearFlags = { true, true }; ClearMapMarks(clearFlags); // If the tile has a player unit if (hoverTile.containingObject != null && hoverTile.containingObject.GetComponent <PlayerUnit>()) { //// If the player unit can move //if () hoverTile.marks[0].SetActive(true); // Highlight tile } } // If player selected a unit, and the unit has not moved yet if (currentSelectedUnitTile != null && !playerUnitAct) { // Clear previous map marks bool[] clearFlags = { false, true }; ClearMapMarks(clearFlags); // If the tile is within the unit's move range if (hoverTile.marks[0].activeInHierarchy) { ShowPath(currentSelectedUnitTile, hoverTile); } } // If a player unit just moved and is in act phase if (playerUnitAct) { // Clear previous map marks bool[] clearFlags = { false, true }; ClearMapMarks(clearFlags); // If the player selected an enemy within range if (hoverTile.marks[0].activeInHierarchy && hoverTile.containingObject != null && hoverTile.containingObject.GetComponent <EnemyUnit>()) { // Mark selected enemy hoverTile.marks[1].SetActive(true); } } }