diff --git a/ClickableTileScript.cs b/ClickableTileScript.cs new file mode 100644 index 0000000..5a43e1f --- /dev/null +++ b/ClickableTileScript.cs @@ -0,0 +1,27 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class ClickableTileScript : MonoBehaviour +{ + //The x and y co-ordinate of the tile + public int tileX; + public int tileY; + //The unit on the tile + public GameObject unitOnTile; + public tileMapScript map; + + + /* + * This was used in Quill18Create'sTutorial, I no longer use this portion + private void OnMouseDown() + { + + Debug.Log("tile has been clicked"); + if (map.selectedUnit != null) + { + map.generatePathTo(tileX, tileY); + } + + }*/ +} diff --git a/Node.cs b/Node.cs new file mode 100644 index 0000000..36d77e1 --- /dev/null +++ b/Node.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class Node { + + public List neighbours; + public int x; + public int y; + //Edges + public Node() + { + neighbours = new List(); + } + + public float DistanceTo(Node n) + { + return Vector2.Distance(new Vector2(x, y), new Vector2(n.x, n.y)); + } + + + +} diff --git a/Tile.cs b/Tile.cs new file mode 100644 index 0000000..340fb6e --- /dev/null +++ b/Tile.cs @@ -0,0 +1,33 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +[System.Serializable] +public class Tile +{ + + public string name; + public GameObject tileVisualPrefab; + public GameObject unitOnTile; + public float movementCost = 1; + public bool isWalkable=true; + + /* + private int x; + private int y; + + + + + public Tile( int xLocation, int yLocation) + { + x = xLocation; + y = yLocation; + } + + public void setCoords(int xLocation, int yLocation) + { + x = xLocation; + y = yLocation; + } + */ +} diff --git a/UnitScript.cs b/UnitScript.cs new file mode 100644 index 0000000..dbd8002 --- /dev/null +++ b/UnitScript.cs @@ -0,0 +1,355 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using TMPro; +using UnityEngine.UI; + +public class UnitScript : MonoBehaviour +{ + public int teamNum; + public int x; + public int y; + + //This is a low tier idea, don't use it + public bool coroutineRunning; + + //Meta defining play here + public Queue movementQueue; + public Queue combatQueue; + //This global variable is used to increase the units movementSpeed when travelling on the board + public float visualMovementSpeed = .15f; + + //Animator + public Animator animator; + + + public GameObject tileBeingOccupied; + + public GameObject damagedParticle; + //UnitStats + public string unitName; + public int moveSpeed = 2; + public int attackRange = 1; + public int attackDamage = 1; + public int maxHealthPoints = 5; + public int currentHealthPoints; + public Sprite unitSprite; + + [Header("UI Elements")] + //Unity UI References + public Canvas healthBarCanvas; + public TMP_Text hitPointsText; + public Image healthBar; + + public Canvas damagePopupCanvas; + public TMP_Text damagePopupText; + public Image damageBackdrop; + + + //This may change in the future if 2d sprites are used instead + //public Material unitMaterial; + //public Material unitWaitMaterial; + + public tileMapScript map; + + //Location for positional update + public Transform startPoint; + public Transform endPoint; + public float moveSpeedTime = 1f; + + //3D Model or 2D Sprite variables to check which version to use + //Make sure only one of them are enabled in the inspector + //public GameObject holder3D; + public GameObject holder2D; + // Total distance between the markers. + private float journeyLength; + + //Boolean to startTravelling + public bool unitInMovement; + + + //Enum for unit states + public enum movementStates + { + Unselected, + Selected, + Moved, + Wait + } + public movementStates unitMoveState; + + //Pathfinding + + public List path = null; + + //Path for moving unit's transform + public List pathForMovement = null; + public bool completedMovement = false; + + private void Awake() + { + + animator = holder2D.GetComponent(); + movementQueue = new Queue(); + combatQueue = new Queue(); + + + x = (int)transform.position.x; + y = (int)transform.position.z; + unitMoveState = movementStates.Unselected; + currentHealthPoints = maxHealthPoints; + hitPointsText.SetText(currentHealthPoints.ToString()); + + + } + + public void LateUpdate() + { + healthBarCanvas.transform.forward = Camera.main.transform.forward; + //damagePopupCanvas.transform.forward = Camera.main.transform.forward; + holder2D.transform.forward = Camera.main.transform.forward; + } + + public void MoveNextTile() + { + if (path.Count == 0) + { + return; + } + else + { + StartCoroutine(moveOverSeconds(transform.gameObject, path[path.Count - 1])); + } + + } + + + public void moveAgain() + { + + path = null; + setMovementState(0); + completedMovement = false; + gameObject.GetComponentInChildren().color = Color.white; + setIdleAnimation(); + //gameObject.GetComponentInChildren().material = unitMaterial; + } + public movementStates getMovementStateEnum(int i) + { + if (i == 0) + { + return movementStates.Unselected; + } + else if (i == 1) + { + return movementStates.Selected; + } + else if (i == 2) + { + return movementStates.Moved; + } + else if (i == 3) + { + return movementStates.Wait; + } + return movementStates.Unselected; + + } + public void setMovementState(int i) + { + if (i == 0) + { + unitMoveState = movementStates.Unselected; + } + else if (i == 1) + { + unitMoveState = movementStates.Selected; + } + else if (i == 2) + { + unitMoveState = movementStates.Moved; + } + else if (i == 3) + { + unitMoveState = movementStates.Wait; + } + + + } + public void updateHealthUI() + { + healthBar.fillAmount = (float)currentHealthPoints / maxHealthPoints; + hitPointsText.SetText(currentHealthPoints.ToString()); + } + public void dealDamage(int x) + { + currentHealthPoints = currentHealthPoints - x; + updateHealthUI(); + } + public void wait() + { + + gameObject.GetComponentInChildren().color = Color.gray; + //gameObject.GetComponentInChildren().material = unitWaitMaterial; + } + public void changeHealthBarColour(int i) + { + if (i == 0) + { + healthBar.color = Color.blue; + } + else if (i == 1) + { + + healthBar.color = Color.red; + } + } + public void unitDie() + { + if (holder2D.activeSelf) + { + StartCoroutine(fadeOut()); + StartCoroutine(checkIfRoutinesRunning()); + + } + + //Destroy(gameObject,2f); + /* + Renderer rend = GetComponentInChildren(); + Color c = rend.material.color; + c.a = 0f; + rend.material.color = c; + StartCoroutine(fadeOut(rend));*/ + + } + public IEnumerator checkIfRoutinesRunning() + { + while (combatQueue.Count>0) + { + + yield return new WaitForEndOfFrame(); + } + + Destroy(gameObject); + + } + public IEnumerator fadeOut() + { + + combatQueue.Enqueue(1); + //setDieAnimation(); + //yield return new WaitForSeconds(animator.GetCurrentAnimatorStateInfo(0).length); + Renderer rend = GetComponentInChildren(); + + for (float f = 1f; f >= .05; f -= 0.01f) + { + Color c = rend.material.color; + c.a = f; + rend.material.color = c; + yield return new WaitForEndOfFrame(); + } + combatQueue.Dequeue(); + + + } + public IEnumerator moveOverSeconds(GameObject objectToMove,Node endNode) + { + movementQueue.Enqueue(1); + + //remove first thing on path because, its the tile we are standing on + + path.RemoveAt(0); + while (path.Count != 0) + { + + Vector3 endPos = map.tileCoordToWorldCoord(path[0].x, path[0].y); + objectToMove.transform.position = Vector3.Lerp(transform.position, endPos, visualMovementSpeed); + if ((transform.position - endPos).sqrMagnitude < 0.001) + { + + path.RemoveAt(0); + + } + yield return new WaitForEndOfFrame(); + } + visualMovementSpeed = 0.15f; + transform.position = map.tileCoordToWorldCoord(endNode.x, endNode.y); + + x = endNode.x; + y = endNode.y; + tileBeingOccupied.GetComponent().unitOnTile = null; + tileBeingOccupied = map.tilesOnMap[x, y]; + movementQueue.Dequeue(); + + } + + + + public IEnumerator displayDamageEnum(int damageTaken) + { + + combatQueue.Enqueue(1); + + damagePopupText.SetText(damageTaken.ToString()); + damagePopupCanvas.enabled = true; + for (float f = 1f; f >=-0.01f; f -= 0.01f) + { + + Color backDrop = damageBackdrop.GetComponent().color; + Color damageValue = damagePopupText.color; + + backDrop.a = f; + damageValue.a = f; + damageBackdrop.GetComponent().color = backDrop; + damagePopupText.color = damageValue; + yield return new WaitForEndOfFrame(); + } + + //damagePopup.enabled = false; + combatQueue.Dequeue(); + + } + public void resetPath() + { + path = null; + completedMovement = false; + } + public void displayDamage(int damageTaken) + { + damagePopupCanvas.enabled = true; + damagePopupText.SetText(damageTaken.ToString()); + } + public void disableDisplayDamage() + { + damagePopupCanvas.enabled = false; + } + + public void setSelectedAnimation() + { + + animator.SetTrigger("toSelected"); + } + public void setIdleAnimation() + { + animator.SetTrigger("toIdle"); + } + public void setWalkingAnimation() + { + animator.SetTrigger("toWalking"); + } + + public void setAttackAnimation() + { + animator.SetTrigger("toAttacking"); + } + public void setWaitIdleAnimation() + { + + animator.SetTrigger("toIdleWait"); + } + + public void setDieAnimation() + { + animator.SetTrigger("dieTrigger"); + } +} diff --git a/battleManagerScript.cs b/battleManagerScript.cs new file mode 100644 index 0000000..f29d765 --- /dev/null +++ b/battleManagerScript.cs @@ -0,0 +1,189 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class battleManagerScript : MonoBehaviour +{ + //This script is for the battle system that this game uses + //The following variables are public for easy setting in the inspector + //They can be set to private if you can pull them into the inspector + public camShakeScript CSS; + public gameManagerScript GMS; + //This is used to check if the battle has been finished + private bool battleStatus; + + //In: two 'unit' game Objects the initiator is the unit that initiated the attack and the recipient is the receiver + //Out: void - units take damage or are destroyed if the hp threshold is <= + //Desc: This is usually called by another script which has access to the two units and then just sets the units as parameters for the function + + public void battle(GameObject initiator, GameObject recipient) + { + battleStatus = true; + var initiatorUnit = initiator.GetComponent(); + var recipientUnit = recipient.GetComponent(); + int initiatorAtt = initiatorUnit.attackDamage; + int recipientAtt = recipientUnit.attackDamage; + //If the two units have the same attackRange then they can trade + if (initiatorUnit.attackRange == recipientUnit.attackRange) + { + GameObject tempParticle = Instantiate( recipientUnit.GetComponent().damagedParticle,recipient.transform.position, recipient.transform.rotation); + Destroy(tempParticle, 2f); + recipientUnit.dealDamage(initiatorAtt); + if (checkIfDead(recipient)) + { + //Set to null then remove, if the gameObject is destroyed before its removed it will not check properly + //This leads to the game not actually ending because the check to see if any units remains happens before the object + //is removed from the parent, so we need to parent to null before we destroy the gameObject. + recipient.transform.parent = null; + recipientUnit.unitDie(); + battleStatus = false; + GMS.checkIfUnitsRemain(initiator, recipient); + return; + } + + + initiatorUnit.dealDamage(recipientAtt); + if (checkIfDead(initiator)) + { + initiator.transform.parent = null; + initiatorUnit.unitDie(); + battleStatus = false; + GMS.checkIfUnitsRemain(initiator, recipient); + return; + + } + } + //if the units don't have the same attack range, like a swordsman vs an archer; the recipient cannot strike back + else + { + GameObject tempParticle = Instantiate(recipientUnit.GetComponent().damagedParticle, recipient.transform.position, recipient.transform.rotation); + Destroy(tempParticle, 2f); + + recipientUnit.dealDamage(initiatorAtt); + if (checkIfDead(recipient)) + { + recipient.transform.parent = null; + recipientUnit.unitDie(); + battleStatus = false; + GMS.checkIfUnitsRemain(initiator, recipient); + + return; + } + } + + battleStatus = false; + + } + + //In: gameObject to check + //Out: boolean - true if unit is dead, false otherwise + //Desc: the health of the gameObject is checked (must be 'unit') or it'll break + public bool checkIfDead(GameObject unitToCheck) + { + if (unitToCheck.GetComponent().currentHealthPoints <= 0) + { + return true; + } + return false; + } + + //In: gameObject to destroy + //Out: void + //Desc: the gameObject in the parameter is destroyed + public void destroyObject(GameObject unitToDestroy) + { + Destroy(unitToDestroy); + } + + //In: two unit gameObjects the attacker and the receiver + //Out: this plays the animations for the battle + //Desc: this function calls all the functions for the battle + public IEnumerator attack(GameObject unit, GameObject enemy) + { + battleStatus = true; + float elapsedTime = 0; + Vector3 startingPos = unit.transform.position; + Vector3 endingPos = enemy.transform.position; + unit.GetComponent().setWalkingAnimation(); + while (elapsedTime < .25f) + { + + unit.transform.position = Vector3.Lerp(startingPos, startingPos+((((endingPos - startingPos) / (endingPos - startingPos).magnitude)).normalized*.5f), (elapsedTime / .25f)); + elapsedTime += Time.deltaTime; + + yield return new WaitForEndOfFrame(); + } + + + + while (battleStatus) + { + + StartCoroutine(CSS.camShake(.2f,unit.GetComponent().attackDamage,getDirection(unit,enemy))); + if(unit.GetComponent().attackRange == enemy.GetComponent().attackRange && enemy.GetComponent().currentHealthPoints - unit.GetComponent().attackDamage > 0) + { + StartCoroutine(unit.GetComponent().displayDamageEnum(enemy.GetComponent().attackDamage)); + StartCoroutine(enemy.GetComponent().displayDamageEnum(unit.GetComponent().attackDamage)); + } + + else + { + StartCoroutine(enemy.GetComponent().displayDamageEnum(unit.GetComponent().attackDamage)); + } + + //unit.GetComponent().displayDamage(enemy.GetComponent().attackDamage); + //enemy.GetComponent().displayDamage(unit.GetComponent().attackDamage); + + battle(unit, enemy); + + yield return new WaitForEndOfFrame(); + } + + if (unit != null) + { + StartCoroutine(returnAfterAttack(unit, startingPos)); + + } + + + + + //unit.GetComponent().wait(); + + } + + //In: unit that is returning to its position, the endPoint vector to return to + //Out: The unit returns back to its location + //Desc: the gameObject in the parameter is returned to the endPoint + public IEnumerator returnAfterAttack(GameObject unit, Vector3 endPoint) { + float elapsedTime = 0; + + + while (elapsedTime < .30f) + { + unit.transform.position = Vector3.Lerp(unit.transform.position, endPoint, (elapsedTime / .25f)); + elapsedTime += Time.deltaTime; + yield return new WaitForEndOfFrame(); + } + + unit.GetComponent().setWaitIdleAnimation(); + unit.GetComponent().wait(); + + + } + + //In: two 'unit' gameObjects + //Out: vector3 the direction that the unit needs to moveTowards + //Desc: the vector3 which the unit needs to moveTowards is returned by this function + public Vector3 getDirection(GameObject unit, GameObject enemy) + { + Vector3 startingPos = unit.transform.position; + Vector3 endingPos = enemy.transform.position; + return (((endingPos - startingPos) / (endingPos - startingPos).magnitude)).normalized; + } + + + + + +} diff --git a/camShakeScript.cs b/camShakeScript.cs new file mode 100644 index 0000000..3c91543 --- /dev/null +++ b/camShakeScript.cs @@ -0,0 +1,36 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class camShakeScript : MonoBehaviour +{ + + public IEnumerator camShake(float duration,float camShakeStrength,Vector3 direction) + { + float updatedShakeStrength = camShakeStrength; + if (camShakeStrength > 10) + { + camShakeStrength = 10; + } + Vector3 originalPos = transform.position; + Vector3 endPoint = new Vector3(direction.x, 0, direction.z)*(camShakeStrength/2); + + float timePassed = 0f; + while (timePassed < duration) + { + + float xPos = Random.Range(-.1f, .1f)*camShakeStrength; + float zPos = Random.Range(-.1f, .1f)*camShakeStrength; + Vector3 newPos = new Vector3(transform.position.x + xPos, transform.position.y, transform.position.z + zPos); + //Vector3 newPos = endPoint + originalPos; + transform.position = Vector3.Lerp(transform.position,newPos,0.15f); + timePassed += Time.deltaTime; + yield return new WaitForEndOfFrame(); + + } + + + + + } +} diff --git a/gameManagerScript.cs b/gameManagerScript.cs new file mode 100644 index 0000000..63fa585 --- /dev/null +++ b/gameManagerScript.cs @@ -0,0 +1,794 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using TMPro; + +public class gameManagerScript : MonoBehaviour +{ + + //A lot of the UI does not need to be public, they just are currently if you need to make quick changes in the inspector + //Changing them to private will not break anything, but you will need to re-enable them to show in the inspector + [Header("UI GameObjects")] + public TMP_Text currentTeamUI; + public Canvas displayWinnerUI; + + public TMP_Text UIunitCurrentHealth; + public TMP_Text UIunitAttackDamage; + public TMP_Text UIunitAttackRange; + public TMP_Text UIunitMoveSpeed; + public TMP_Text UIunitName; + public UnityEngine.UI.Image UIunitSprite; + + public Canvas UIunitCanvas; + public GameObject playerPhaseBlock; + private Animator playerPhaseAnim; + private TMP_Text playerPhaseText; + + //Raycast for the update for unitHover info + private Ray ray; + private RaycastHit hit; + + /// The number of teams is hard coded as 2, if there are changes in the future a few of the + /// functions in this class need to be altered as well to update this change. + + public int numberOfTeams = 2; + public int currentTeam; + public GameObject unitsOnBoard; + + public GameObject team1; + public GameObject team2; + + public GameObject unitBeingDisplayed; + public GameObject tileBeingDisplayed; + public bool displayingUnitInfo; + + public tileMapScript TMS; + + //Cursor Info for tileMapScript + public int cursorX; + public int cursorY; + //currentTileBeingMousedOver + public int selectedXTile; + public int selectedYTile; + + //Variables for unitPotentialMovementRoute + List currentPathForUnitRoute; + List unitPathToCursor; + + public bool unitPathExists; + + public Material UIunitRoute; + public Material UIunitRouteCurve; + public Material UIunitRouteArrow; + public Material UICursor; + + public int routeToX; + public int routeToY; + + //This game object is to record the location of the 2 count path when it is reset to 0 this is used to remember what tile to disable + public GameObject quadThatIsOneAwayFromUnit; + + + public void Start() + { + currentTeam = 0; + setCurrentTeamUI(); + teamHealthbarColorUpdate(); + displayingUnitInfo = false; + playerPhaseAnim = playerPhaseBlock.GetComponent(); + playerPhaseText = playerPhaseBlock.GetComponentInChildren(); + unitPathToCursor = new List(); + unitPathExists = false; + + TMS = GetComponent(); + + + } + //2019/10/17 there is a small blink between disable and re-enable for path, its a bit jarring, try to fix it later + public void Update() + { + //Always trying to see where the mouse is pointing + ray = Camera.main.ScreenPointToRay(Input.mousePosition); + if (Physics.Raycast(ray, out hit)) + { + //Update cursorLocation and unit appearing in the topLeft + cursorUIUpdate(); + unitUIUpdate(); + //If the unit is selected we want to highlight the current path with the UI + if (TMS.selectedUnit != null && TMS.selectedUnit.GetComponent().getMovementStateEnum(1) == TMS.selectedUnit.GetComponent().unitMoveState) + { + //Check to see if the cursor is in range, we cant show movement outside of range so there is no point if its outside + if (TMS.selectedUnitMoveRange.Contains(TMS.graph[cursorX, cursorY])) + { + //Generate new path to cursor try to limit this to once per new cursor location or else its too many calculations + + + + if (cursorX != TMS.selectedUnit.GetComponent().x || cursorY != TMS.selectedUnit.GetComponent().y) + { + if (!unitPathExists&&TMS.selectedUnit.GetComponent().movementQueue.Count==0) + { + + unitPathToCursor = generateCursorRouteTo(cursorX, cursorY); + + routeToX = cursorX; + routeToY = cursorY; + + if (unitPathToCursor.Count != 0) + { + + for(int i = 0; i < unitPathToCursor.Count; i++) + { + int nodeX = unitPathToCursor[i].x; + int nodeY = unitPathToCursor[i].y; + + if (i == 0) + { + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().material = UICursor; + } + else if (i!=0 && (i+1)!=unitPathToCursor.Count) + { + //This is used to set the indicator for tiles excluding the first/last tile + setCorrectRouteWithInputAndOutput(nodeX, nodeY,i); + } + else if (i == unitPathToCursor.Count-1) + { + //This is used to set the indicator for the final tile; + setCorrectRouteFinalTile(nodeX, nodeY, i); + } + + TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY].GetComponent().enabled = true; + + } + + } + unitPathExists = true; + + } + + else if (routeToX != cursorX || routeToY != cursorY) + { + + if (unitPathToCursor.Count != 0) + { + for (int i = 0; i < unitPathToCursor.Count; i++) + { + int nodeX = unitPathToCursor[i].x; + int nodeY = unitPathToCursor[i].y; + + TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY].GetComponent().enabled = false; + } + } + + unitPathExists = false; + } + } + else if(cursorX == TMS.selectedUnit.GetComponent().x && cursorY == TMS.selectedUnit.GetComponent().y) + { + + TMS.disableUnitUIRoute(); + unitPathExists = false; + } + + } + } + + } + + } + //In: + //Out: void + //Desc: sets the current player Text in the UI + public void setCurrentTeamUI() + { + currentTeamUI.SetText("Current Player is : Player " + (currentTeam+1).ToString()); + } + + //In: + //Out: void + //Desc: increments the current team + public void switchCurrentPlayer() + { + resetUnitsMovements(returnTeam(currentTeam)); + currentTeam++; + if (currentTeam == numberOfTeams) + { + currentTeam = 0; + } + + } + + //In: int i, the index for each team + //Out: gameObject team + //Desc: return the gameObject of the requested team + public GameObject returnTeam(int i) + { + GameObject teamToReturn = null; + if (i == 0) + { + teamToReturn = team1; + } + else if (i == 1) + { + teamToReturn = team2; + } + return teamToReturn; + } + + //In: gameObject team - used to reset (re-enable) all the unit movements + //Out: void + //Desc: re-enables movement for all units on the team + public void resetUnitsMovements(GameObject teamToReset) + { + foreach (Transform unit in teamToReset.transform) + { + unit.GetComponent().moveAgain(); + } + } + + //In: + //Out: void + //Desc: ends the turn and plays the animation + public void endTurn() + { + + if (TMS.selectedUnit == null) + { + switchCurrentPlayer(); + if (currentTeam == 1) + { + playerPhaseAnim.SetTrigger("slideLeftTrigger"); + playerPhaseText.SetText("Player 2 Phase"); + } + else if (currentTeam == 0) + { + playerPhaseAnim.SetTrigger("slideRightTrigger"); + playerPhaseText.SetText("Player 1 Phase"); + } + teamHealthbarColorUpdate(); + setCurrentTeamUI(); + } + } + + //In: attacking unit and receiving unit + //Out: void + //Desc: checks to see if units remain on a team + public void checkIfUnitsRemain(GameObject unit, GameObject enemy) + { + // Debug.Log(team1.transform.childCount); + // Debug.Log(team2.transform.childCount); + StartCoroutine(checkIfUnitsRemainCoroutine(unit,enemy)); + } + + + //In: + //Out: void + //Desc: updates the cursor for the UI + public void cursorUIUpdate() + { + //If we are mousing over a tile, highlight it + if (hit.transform.CompareTag("Tile")) + { + if (tileBeingDisplayed == null) + { + selectedXTile = hit.transform.gameObject.GetComponent().tileX; + selectedYTile = hit.transform.gameObject.GetComponent().tileY; + cursorX = selectedXTile; + cursorY = selectedYTile; + TMS.quadOnMapCursor[selectedXTile, selectedYTile].GetComponent().enabled = true; + tileBeingDisplayed = hit.transform.gameObject; + + } + else if (tileBeingDisplayed != hit.transform.gameObject) + { + selectedXTile = tileBeingDisplayed.GetComponent().tileX; + selectedYTile = tileBeingDisplayed.GetComponent().tileY; + TMS.quadOnMapCursor[selectedXTile, selectedYTile].GetComponent().enabled = false; + + selectedXTile = hit.transform.gameObject.GetComponent().tileX; + selectedYTile = hit.transform.gameObject.GetComponent().tileY; + cursorX = selectedXTile; + cursorY = selectedYTile; + TMS.quadOnMapCursor[selectedXTile, selectedYTile].GetComponent().enabled = true; + tileBeingDisplayed = hit.transform.gameObject; + + } + + } + //If we are mousing over a unit, highlight the tile that the unit is occupying + else if (hit.transform.CompareTag("Unit")) + { + if (tileBeingDisplayed == null) + { + selectedXTile = hit.transform.parent.gameObject.GetComponent().x; + selectedYTile = hit.transform.parent.gameObject.GetComponent().y; + cursorX = selectedXTile; + cursorY = selectedYTile; + TMS.quadOnMapCursor[selectedXTile, selectedYTile].GetComponent().enabled = true; + tileBeingDisplayed = hit.transform.parent.gameObject.GetComponent().tileBeingOccupied; + + } + else if (tileBeingDisplayed != hit.transform.gameObject) + { + if (hit.transform.parent.gameObject.GetComponent().movementQueue.Count == 0) + { + selectedXTile = tileBeingDisplayed.GetComponent().tileX; + selectedYTile = tileBeingDisplayed.GetComponent().tileY; + TMS.quadOnMapCursor[selectedXTile, selectedYTile].GetComponent().enabled = false; + + selectedXTile = hit.transform.parent.gameObject.GetComponent().x; + selectedYTile = hit.transform.parent.gameObject.GetComponent().y; + cursorX = selectedXTile; + cursorY = selectedYTile; + TMS.quadOnMapCursor[selectedXTile, selectedYTile].GetComponent().enabled = true; + tileBeingDisplayed = hit.transform.parent.GetComponent().tileBeingOccupied; + + } + + } + } + //We aren't pointing at anything no cursor. + else + { + TMS.quadOnMapCursor[selectedXTile, selectedYTile].GetComponent().enabled = false; + } + } + + + //In: + //Out: void + //Desc: the unit that is being highlighted will have its stats in the UI + public void unitUIUpdate() + { + if (!displayingUnitInfo) + { + if (hit.transform.CompareTag("Unit")) + { + UIunitCanvas.enabled = true; + displayingUnitInfo = true; + unitBeingDisplayed = hit.transform.parent.gameObject; + var highlightedUnitScript = hit.transform.parent.gameObject.GetComponent(); + + UIunitCurrentHealth.SetText(highlightedUnitScript.currentHealthPoints.ToString()); + UIunitAttackDamage.SetText(highlightedUnitScript.attackDamage.ToString()); + UIunitAttackRange.SetText(highlightedUnitScript.attackRange.ToString()); + UIunitMoveSpeed.SetText(highlightedUnitScript.moveSpeed.ToString()); + UIunitName.SetText(highlightedUnitScript.unitName); + UIunitSprite.sprite = highlightedUnitScript.unitSprite; + + } + else if (hit.transform.CompareTag("Tile")) + { + if (hit.transform.GetComponent().unitOnTile != null) + { + unitBeingDisplayed = hit.transform.GetComponent().unitOnTile; + + UIunitCanvas.enabled = true; + displayingUnitInfo = true; + var highlightedUnitScript = unitBeingDisplayed.GetComponent(); + + UIunitCurrentHealth.SetText(highlightedUnitScript.currentHealthPoints.ToString()); + UIunitAttackDamage.SetText(highlightedUnitScript.attackDamage.ToString()); + UIunitAttackRange.SetText(highlightedUnitScript.attackRange.ToString()); + UIunitMoveSpeed.SetText(highlightedUnitScript.moveSpeed.ToString()); + UIunitName.SetText(highlightedUnitScript.unitName); + UIunitSprite.sprite = highlightedUnitScript.unitSprite; + + } + } + } + else if (hit.transform.gameObject.CompareTag("Tile")) + { + if (hit.transform.GetComponent().unitOnTile == null) + { + UIunitCanvas.enabled = false; + displayingUnitInfo = false; + } + else if (hit.transform.GetComponent().unitOnTile != unitBeingDisplayed) + { + UIunitCanvas.enabled = false; + displayingUnitInfo = false; + } + } + else if (hit.transform.gameObject.CompareTag("Unit")) + { + if (hit.transform.parent.gameObject != unitBeingDisplayed) + { + UIunitCanvas.enabled = false; + displayingUnitInfo = false; + } + } + } + + //In: + //Out: void + //Desc: When the current team is active, the healthbars are blue, and the other team is red + public void teamHealthbarColorUpdate() + { + for(int i = 0; i < numberOfTeams; i++) + { + GameObject team = returnTeam(i); + if(team == returnTeam(currentTeam)) + { + foreach (Transform unit in team.transform) + { + unit.GetComponent().changeHealthBarColour(0); + } + } + else + { + foreach (Transform unit in team.transform) + { + unit.GetComponent().changeHealthBarColour(1); + } + } + } + + + } + //In: x and y location to go to + //Out: list of nodes to traverse + //Desc: generate the cursor route to a position x , y + public List generateCursorRouteTo(int x, int y) + { + + if (TMS.selectedUnit.GetComponent().x == x && TMS.selectedUnit.GetComponent().y == y) + { + Debug.Log("clicked the same tile that the unit is standing on"); + currentPathForUnitRoute = new List(); + + + return currentPathForUnitRoute; + } + if (TMS.unitCanEnterTile(x, y) == false) + { + //cant move into something so we can probably just return + //cant set this endpoint as our goal + + return null; + } + + //TMS.selectedUnit.GetComponent().path = null; + currentPathForUnitRoute = null; + //from wiki dijkstra's + Dictionary dist = new Dictionary(); + Dictionary prev = new Dictionary(); + Node source = TMS.graph[TMS.selectedUnit.GetComponent().x, TMS.selectedUnit.GetComponent().y]; + Node target = TMS.graph[x, y]; + dist[source] = 0; + prev[source] = null; + //Unchecked nodes + List unvisited = new List(); + + //Initialize + foreach (Node n in TMS.graph) + { + + //Initialize to infite distance as we don't know the answer + //Also some places are infinity + if (n != source) + { + dist[n] = Mathf.Infinity; + prev[n] = null; + } + unvisited.Add(n); + } + //if there is a node in the unvisited list lets check it + while (unvisited.Count > 0) + { + //u will be the unvisited node with the shortest distance + Node u = null; + foreach (Node possibleU in unvisited) + { + if (u == null || dist[possibleU] < dist[u]) + { + u = possibleU; + } + } + + + if (u == target) + { + break; + } + + unvisited.Remove(u); + + foreach (Node n in u.neighbours) + { + + //float alt = dist[u] + u.DistanceTo(n); + float alt = dist[u] + TMS.costToEnterTile(n.x, n.y); + if (alt < dist[n]) + { + dist[n] = alt; + prev[n] = u; + } + } + } + //if were here we found shortest path, or no path exists + if (prev[target] == null) + { + //No route; + return null; + } + currentPathForUnitRoute = new List(); + Node curr = target; + //Step through the current path and add it to the chain + while (curr != null) + { + currentPathForUnitRoute.Add(curr); + curr = prev[curr]; + } + //Now currPath is from target to our source, we need to reverse it from source to target. + currentPathForUnitRoute.Reverse(); + + return currentPathForUnitRoute; + + + + + } + + //In: gameObject quad + //Out: void + //Desc: reset its rotation + public void resetQuad(GameObject quadToReset) + { + quadToReset.GetComponent().material = UICursor; + quadToReset.transform.eulerAngles = new Vector3(90, 0, 0); + + } + + //In: Vector2 cursorPos the location we change, Vector3 the rotation that we will rotate the quad + //Out: void + //Desc: the quad is rotated approriately + public void UIunitRouteArrowDisplay(Vector2 cursorPos,Vector3 arrowRotationVector) + { + GameObject quadToManipulate = TMS.quadOnMapForUnitMovementDisplay[(int)cursorPos.x, (int)cursorPos.y]; + quadToManipulate.transform.eulerAngles = arrowRotationVector; + quadToManipulate.GetComponent().material = UIunitRouteArrow; + quadToManipulate.GetComponent().enabled = true; + } + + //In: two gameObjects current vector and the next one in the list + //Out: vector which is the direction between the two inputs + //Desc: the direction from current to the next vector is returned + public Vector2 directionBetween(Vector2 currentVector, Vector2 nextVector) + { + + + Vector2 vectorDirection = (nextVector - currentVector).normalized; + + if (vectorDirection == Vector2.right) + { + return Vector2.right; + } + else if (vectorDirection == Vector2.left) + { + return Vector2.left; + } + else if (vectorDirection == Vector2.up) + { + return Vector2.up; + } + else if (vectorDirection == Vector2.down) + { + return Vector2.down; + } + else + { + Vector2 vectorToReturn = new Vector2(); + return vectorToReturn; + } + } + + //In: two nodes that are being checked and int i is the position in the path ie i=0 is the first thing in the list + //Out: void + //Desc: orients the quads to display proper information + public void setCorrectRouteWithInputAndOutput(int nodeX,int nodeY,int i) + { + Vector2 previousTile = new Vector2(unitPathToCursor[i - 1].x + 1, unitPathToCursor[i - 1].y + 1); + Vector2 currentTile = new Vector2(unitPathToCursor[i].x + 1, unitPathToCursor[i].y + 1); + Vector2 nextTile = new Vector2(unitPathToCursor[i + 1].x + 1, unitPathToCursor[i + 1].y + 1); + + Vector2 backToCurrentVector = directionBetween(previousTile, currentTile); + Vector2 currentToFrontVector = directionBetween(currentTile, nextTile); + + + //Right (UP/DOWN/RIGHT) + if (backToCurrentVector == Vector2.right && currentToFrontVector == Vector2.right) + { + //Debug.Log("[IN[R]]->[Out[R]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 270); + quadToUpdate.GetComponent().material = UIunitRoute; + quadToUpdate.GetComponent().enabled = true; + } + else if (backToCurrentVector == Vector2.right && currentToFrontVector == Vector2.up) + { + //Debug.Log("[IN[R]]->[Out[UP]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 180); + quadToUpdate.GetComponent().material = UIunitRouteCurve; + quadToUpdate.GetComponent().enabled = true; + + } + else if (backToCurrentVector == Vector2.right && currentToFrontVector == Vector2.down) + { + //Debug.Log("[IN[R]]->[Out[DOWN]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 270); + quadToUpdate.GetComponent().material = UIunitRouteCurve; + quadToUpdate.GetComponent().enabled = true; + } + //Left (UP/DOWN/LEFT) + else if (backToCurrentVector == Vector2.left && currentToFrontVector == Vector2.left) + { + //Debug.Log("[IN[L]]->[Out[L]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 90); + quadToUpdate.GetComponent().material = UIunitRoute; + quadToUpdate.GetComponent().enabled = true; + } + else if (backToCurrentVector == Vector2.left && currentToFrontVector == Vector2.up) + { + //Debug.Log("[IN[L]]->[Out[UP]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 90); + quadToUpdate.GetComponent().material = UIunitRouteCurve; + quadToUpdate.GetComponent().enabled = true; + } + else if (backToCurrentVector == Vector2.left && currentToFrontVector == Vector2.down) + { + //Debug.Log("[IN[L]]->[Out[DOWN]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 0); + quadToUpdate.GetComponent().material = UIunitRouteCurve; + quadToUpdate.GetComponent().enabled = true; + } + //UP (UP/RIGHT/LEFT) + else if (backToCurrentVector == Vector2.up && currentToFrontVector == Vector2.up) + { + //Debug.Log("[IN[UP]]->[Out[UP]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 0); + quadToUpdate.GetComponent().material = UIunitRoute; + quadToUpdate.GetComponent().enabled = true; + } + else if (backToCurrentVector == Vector2.up && currentToFrontVector == Vector2.right) + { + //Debug.Log("[IN[UP]]->[Out[R]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 0); + quadToUpdate.GetComponent().material = UIunitRouteCurve; + quadToUpdate.GetComponent().enabled = true; + } + else if (backToCurrentVector == Vector2.up && currentToFrontVector == Vector2.left) + { + //Debug.Log("[IN[UP]]->[Out[L]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 270); + quadToUpdate.GetComponent().material = UIunitRouteCurve; + quadToUpdate.GetComponent().enabled = true; + } + //DOWN (DOWN/RIGHT/LEFT) + else if (backToCurrentVector == Vector2.down && currentToFrontVector == Vector2.down) + { + //Debug.Log("[IN[DOWN]]->[Out[DOWN]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 0); + quadToUpdate.GetComponent().material = UIunitRoute; + quadToUpdate.GetComponent().enabled = true; + } + else if (backToCurrentVector == Vector2.down && currentToFrontVector == Vector2.right) + { + //Debug.Log("[IN[DOWN]]->[Out[R]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 90); + quadToUpdate.GetComponent().material = UIunitRouteCurve; + quadToUpdate.GetComponent().enabled = true; + + } + else if (backToCurrentVector == Vector2.down && currentToFrontVector == Vector2.left) + { + //Debug.Log("[IN[DOWN]]->[Out[L]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 180); + quadToUpdate.GetComponent().material = UIunitRouteCurve; + quadToUpdate.GetComponent().enabled = true; + } + } + + //In: two nodes that are being checked and int i is the position in the path ie i=0 is the first thing in the list + //Out: void + //Desc: orients the quad for the final node in list to display proper information + public void setCorrectRouteFinalTile(int nodeX,int nodeY,int i) + { + Vector2 previousTile = new Vector2(unitPathToCursor[i - 1].x + 1, unitPathToCursor[i - 1].y + 1); + Vector2 currentTile = new Vector2(unitPathToCursor[i].x + 1, unitPathToCursor[i].y + 1); + Vector2 backToCurrentVector = directionBetween(previousTile, currentTile); + + if (backToCurrentVector == Vector2.right) + { + //Debug.Log("[IN[R]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 270); + quadToUpdate.GetComponent().material = UIunitRouteArrow; + quadToUpdate.GetComponent().enabled = true; + } + else if (backToCurrentVector == Vector2.left) + { + //Debug.Log("[IN[L]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 90); + quadToUpdate.GetComponent().material = UIunitRouteArrow; + quadToUpdate.GetComponent().enabled = true; + + } + else if (backToCurrentVector == Vector2.up) + { + //Debug.Log("[IN[U]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 0); + quadToUpdate.GetComponent().material = UIunitRouteArrow; + quadToUpdate.GetComponent().enabled = true; + } + else if (backToCurrentVector == Vector2.down) + { + //Debug.Log("[IN[D]]"); + GameObject quadToUpdate = TMS.quadOnMapForUnitMovementDisplay[nodeX, nodeY]; + quadToUpdate.GetComponent().rotation = Quaternion.Euler(90, 0, 180); + quadToUpdate.GetComponent().material = UIunitRouteArrow; + quadToUpdate.GetComponent().enabled = true; + } + } + + //In: two units that last fought + //Out: void + //Desc: waits until all the animations and stuff are finished before calling the game + public IEnumerator checkIfUnitsRemainCoroutine(GameObject unit, GameObject enemy) + { + while (unit.GetComponent().combatQueue.Count != 0) + { + yield return new WaitForEndOfFrame(); + } + + while (enemy.GetComponent().combatQueue.Count != 0) + { + yield return new WaitForEndOfFrame(); + } + if (team1.transform.childCount == 0) + { + displayWinnerUI.enabled = true; + displayWinnerUI.GetComponentInChildren().SetText("Player 2 has won!"); + + + } + else if (team2.transform.childCount == 0) + { + displayWinnerUI.enabled = true; + displayWinnerUI.GetComponentInChildren().SetText("Player 1 has won!"); + + + } + + + } + + + //In: + //Out: void + //Desc: set the player winning + + public void win() + { + displayWinnerUI.enabled = true; + displayWinnerUI.GetComponentInChildren().SetText("Winner!"); + + } + + + +} diff --git a/gameSceneManager.cs b/gameSceneManager.cs new file mode 100644 index 0000000..d79d0a5 --- /dev/null +++ b/gameSceneManager.cs @@ -0,0 +1,48 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +public class gameSceneManager : MonoBehaviour +{ + //This was just used to load menu stuff properly and change scenes + + public Canvas mainCanvas; + public Canvas helpCanvas; + public Canvas helpCanvas2; + // Start is called before the first frame update + public void loadMainMenu() + { + SceneManager.LoadScene(0); + } + + public void loadLevelOne() + { + SceneManager.LoadScene(1); + } + + public void loadHelpCanvas() + { + mainCanvas.enabled = false; + helpCanvas.enabled = true; + } + + public void loadHelpCanvasBack() + { + helpCanvas2.enabled = false; + helpCanvas.enabled = true; + } + + public void loadHelpCanvas2() + { + helpCanvas.enabled = false; + helpCanvas2.enabled = true; + } + + public void loadMainCanvas() + { + mainCanvas.enabled = true; + helpCanvas.enabled = false; + helpCanvas2.enabled = false; + } +} diff --git a/tileMapScript.cs b/tileMapScript.cs new file mode 100644 index 0000000..c7c757e --- /dev/null +++ b/tileMapScript.cs @@ -0,0 +1,1125 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class tileMapScript : MonoBehaviour +{ + //Reference holders for the other two scripts that are currently running + //alongside this script + [Header("Manager Scripts")] + public battleManagerScript BMS; + public gameManagerScript GMS; + + //List of tiles that are used to generate the map + //Try chaging tilesTypes to enum later + [Header("Tiles")] + public Tile[] tileTypes; + public int[,] tiles; + + //This is used when the game starts and there are pre-existing units + //It uses this variable to check if there are any units and then maps them to the proper tiles + [Header("Units on the board")] + public GameObject unitsOnBoard; + + //This 2d array is the list of tile gameObjects on the board + public GameObject[,] tilesOnMap; + + //This 2d array is the list of quadUI gameObjects on the board + public GameObject[,] quadOnMap; + public GameObject[,] quadOnMapForUnitMovementDisplay; + public GameObject[,] quadOnMapCursor; + + //public is only to set them in the inspector, if you change these to private then you will + //need to re-enable them in the inspector + //Game object that is used to overlay onto the tiles to show possible movement + public GameObject mapUI; + //Game object that is used to highlight the mouse location + public GameObject mapCursorUI; + //Game object that is used to highlight the path the unit is taking + public GameObject mapUnitMovementUI; + + //Nodes along the path of shortest path from the pathfinding + public List currentPath = null; + + //Node graph for pathfinding purposes + public Node[,] graph; + + //containers (parent gameObjects) for the UI tiles + [Header("Containers")] + public GameObject tileContainer; + public GameObject UIQuadPotentialMovesContainer; + public GameObject UIQuadCursorContainer; + public GameObject UIUnitMovementPathContainer; + + + //Set in the inspector, might change this otherwise. + //This is the map size (please put positive numbers it probably wont work well with negative numbers) + [Header("Board Size")] + public int mapSizeX; + public int mapSizeY; + + //In the update() function mouse down raycast sets this unit + [Header("Selected Unit Info")] + public GameObject selectedUnit; + //These two are set in the highlightUnitRange() function + //They are used for other things as well, mainly to check for movement, or finalize function + public HashSet selectedUnitTotalRange; + public HashSet selectedUnitMoveRange; + + public bool unitSelected = false; + + public int unitSelectedPreviousX; + public int unitSelectedPreviousY; + + public GameObject previousOccupiedTile; + + + //public AudioSource selectedSound; + //public AudioSource unselectedSound; + //public area to set the material for the quad material for UI purposes + [Header("Materials")] + public Material greenUIMat; + public Material redUIMat; + public Material blueUIMat; + private void Start() + { + //Get the battlemanager running + //BMS = GetComponent(); + //GMS = GetComponent(); + //Generate the map info that will be used + generateMapInfo(); + //Generate pathfinding graph + generatePathFindingGraph(); + //With the generated info this function will read the info and produce the map + generateMapVisuals(); + //Check if there are any pre-existing units on the board + setIfTileIsOccupied(); + + + } + + private void Update() + { + + //If input is left mouse down then select the unit + if (Input.GetMouseButtonDown(0)) + { + if (selectedUnit == null) + { + //mouseClickToSelectUnit(); + mouseClickToSelectUnitV2(); + + } + //After a unit has been selected then if we get a mouse click, we need to check if the unit has entered the selection state (1) 'Selected' + //Move the unit + else if (selectedUnit.GetComponent().unitMoveState == selectedUnit.GetComponent().getMovementStateEnum(1) && selectedUnit.GetComponent().movementQueue.Count == 0) + { + + + if ( selectTileToMoveTo()) + { + //selectedSound.Play(); + Debug.Log("movement path has been located"); + unitSelectedPreviousX = selectedUnit.GetComponent().x; + unitSelectedPreviousY = selectedUnit.GetComponent().y; + previousOccupiedTile = selectedUnit.GetComponent().tileBeingOccupied; + selectedUnit.GetComponent().setWalkingAnimation(); + moveUnit(); + + StartCoroutine(moveUnitAndFinalize()); + //The moveUnit function calls a function on the unitScriptm when the movement is completed the finalization is called from that script. + + + } + + } + //Finalize the movement + else if(selectedUnit.GetComponent().unitMoveState == selectedUnit.GetComponent().getMovementStateEnum(2)) + { + finalizeOption(); + } + + } + //Unselect unit with the right click + if (Input.GetMouseButtonDown(1)) + { + if (selectedUnit != null) + { + if (selectedUnit.GetComponent().movementQueue.Count == 0 && selectedUnit.GetComponent().combatQueue.Count==0) + { + if (selectedUnit.GetComponent().unitMoveState != selectedUnit.GetComponent().getMovementStateEnum(3)) + { + //unselectedSound.Play(); + selectedUnit.GetComponent().setIdleAnimation(); + deselectUnit(); + } + } + else if (selectedUnit.GetComponent().movementQueue.Count == 1) + { + selectedUnit.GetComponent().visualMovementSpeed = 0.5f; + } + } + } + + + } + + //This is from quill18Create's tutorial + //You can find it by searching for grid based movement on youtube, he goes into explaining how everything works + //The map layouts a bit different + //all this does is set the tiles[x,y] to the corresponding tile + public void generateMapInfo() + { + tiles = new int[mapSizeX, mapSizeY]; + for (int x = 0; x < mapSizeX; x++) + { + for (int y = 0; y < mapSizeY; y++) + { + tiles[x, y] = 0; + } + } + tiles[2, 7] = 2; + tiles[3, 7] = 2; + + tiles[6, 7] = 2; + tiles[7, 7] = 2; + + tiles[2, 2] = 2; + tiles[3, 2] = 2; + + tiles[6, 2] = 2; + tiles[7, 2] = 2; + + tiles[0, 3] = 3; + tiles[1, 3] = 3; + tiles[0, 2] = 3; + tiles[1, 2] = 3; + + tiles[0, 6] = 3; + tiles[1, 6] = 3; + tiles[2, 6] = 3; + tiles[0, 7] = 3; + tiles[1, 7] = 3; + + tiles[2, 3] = 3; + tiles[0, 4] = 1; + tiles[0, 5] = 1; + tiles[1, 4] = 1; + tiles[1, 5] = 1; + tiles[2, 4] = 3; + tiles[2, 5] = 3; + + tiles[4, 4] = 1; + tiles[5, 4] = 1; + tiles[4, 5] = 1; + tiles[5, 5] = 1; + + tiles[7, 3] = 3; + tiles[8, 3] = 3; + tiles[9, 3] = 3; + tiles[8, 2] = 3; + tiles[9, 2] = 3; + tiles[7, 4] = 3; + tiles[7, 5] = 3; + tiles[7, 6] = 3; + tiles[8, 6] = 3; + tiles[9, 6] = 3; + tiles[8, 7] = 3; + tiles[9, 7] = 3; + tiles[8, 4] = 1; + tiles[8, 5] = 1; + tiles[9, 4] = 1; + tiles[9, 5] = 1; + + + } + //Creates the graph for the pathfinding, it sets up the neighbours + //This is also from Quill18Create's tutorial + public void generatePathFindingGraph() + { + graph = new Node[mapSizeX, mapSizeY]; + + //initialize graph + for (int x = 0; x < mapSizeX; x++) + { + for (int y = 0; y < mapSizeY; y++) + { + graph[x, y] = new Node(); + graph[x, y].x = x; + graph[x, y].y = y; + } + } + //calculate neighbours + for (int x = 0; x < mapSizeX; x++) + { + for (int y = 0; y < mapSizeY; y++) + { + //X is not 0, then we can add left (x - 1) + if (x > 0) + { + graph[x, y].neighbours.Add(graph[x - 1, y]); + } + //X is not mapSizeX - 1, then we can add right (x + 1) + if (x < mapSizeX-1) + { + graph[x, y].neighbours.Add(graph[x + 1, y]); + } + //Y is not 0, then we can add downwards (y - 1 ) + if (y > 0) + { + graph[x, y].neighbours.Add(graph[x, y - 1]); + } + //Y is not mapSizeY -1, then we can add upwards (y + 1) + if (y < mapSizeY - 1) + { + graph[x, y].neighbours.Add(graph[x, y + 1]); + } + + + } + } + } + + + //In: + //Out: void + //Desc: This instantiates all the information for the map, the UI Quads and the map tiles + public void generateMapVisuals() + { + //generate list of actual tileGameObjects + tilesOnMap = new GameObject[mapSizeX, mapSizeY]; + quadOnMap = new GameObject[mapSizeX, mapSizeY]; + quadOnMapForUnitMovementDisplay = new GameObject[mapSizeX, mapSizeY]; + quadOnMapCursor = new GameObject[mapSizeX, mapSizeY]; + int index; + for (int x = 0; x < mapSizeX; x++) + { + for (int y = 0; y < mapSizeY; y++) + { + index = tiles[x, y]; + GameObject newTile = Instantiate(tileTypes[index].tileVisualPrefab, new Vector3(x, 0, y), Quaternion.identity); + newTile.GetComponent().tileX = x; + newTile.GetComponent().tileY = y; + newTile.GetComponent().map = this; + newTile.transform.SetParent(tileContainer.transform); + tilesOnMap[x, y] = newTile; + + + GameObject gridUI = Instantiate(mapUI, new Vector3(x, 0.501f, y),Quaternion.Euler(90f,0,0)); + gridUI.transform.SetParent(UIQuadPotentialMovesContainer.transform); + quadOnMap[x, y] = gridUI; + + GameObject gridUIForPathfindingDisplay = Instantiate(mapUnitMovementUI, new Vector3(x, 0.502f, y), Quaternion.Euler(90f, 0, 0)); + gridUIForPathfindingDisplay.transform.SetParent(UIUnitMovementPathContainer.transform); + quadOnMapForUnitMovementDisplay[x, y] = gridUIForPathfindingDisplay; + + GameObject gridUICursor = Instantiate(mapCursorUI, new Vector3(x, 0.503f, y), Quaternion.Euler(90f, 0, 0)); + gridUICursor.transform.SetParent(UIQuadCursorContainer.transform); + quadOnMapCursor[x, y] = gridUICursor; + + } + } + } + + //Moves the unit + public void moveUnit() + { + if (selectedUnit != null) + { + selectedUnit.GetComponent().MoveNextTile(); + } + } + + //In: the x and y of a tile + //Out: vector 3 of the tile in world space, theyre .75f off of zero + //Desc: returns a vector 3 of the tile in world space, theyre .75f off of zero + public Vector3 tileCoordToWorldCoord(int x, int y) + { + return new Vector3(x, 0.75f, y); + } + + + + //In: + //Out: void + //Desc: sets the tile as occupied, if a unit is on the tile + public void setIfTileIsOccupied() + { + foreach (Transform team in unitsOnBoard.transform) + { + //Debug.Log("Set if Tile is Occupied is Called"); + foreach (Transform unitOnTeam in team) { + int unitX = unitOnTeam.GetComponent().x; + int unitY = unitOnTeam.GetComponent().y; + unitOnTeam.GetComponent().tileBeingOccupied = tilesOnMap[unitX, unitY]; + tilesOnMap[unitX, unitY].GetComponent().unitOnTile = unitOnTeam.gameObject; + } + + } + } + //In: x and y position of the tile to move to + //Out: void + //Desc: generates the path for the selected unit + //Think this one is also partially from Quill18Create's tutorial + public void generatePathTo(int x, int y) + { + + if (selectedUnit.GetComponent().x == x && selectedUnit.GetComponent().y == y){ + Debug.Log("clicked the same tile that the unit is standing on"); + currentPath = new List(); + selectedUnit.GetComponent().path = currentPath; + + return; + } + if (unitCanEnterTile(x, y) == false) + { + //cant move into something so we can probably just return + //cant set this endpoint as our goal + + return; + } + + selectedUnit.GetComponent().path = null; + currentPath = null; + //from wiki dijkstra's + Dictionary dist = new Dictionary(); + Dictionary prev = new Dictionary(); + Node source = graph[selectedUnit.GetComponent().x, selectedUnit.GetComponent().y]; + Node target = graph[x, y]; + dist[source] = 0; + prev[source] = null; + //Unchecked nodes + List unvisited = new List(); + + //Initialize + foreach (Node n in graph) + { + + //Initialize to infite distance as we don't know the answer + //Also some places are infinity + if (n != source) + { + dist[n] = Mathf.Infinity; + prev[n] = null; + } + unvisited.Add(n); + } + //if there is a node in the unvisited list lets check it + while (unvisited.Count > 0) + { + //u will be the unvisited node with the shortest distance + Node u = null; + foreach (Node possibleU in unvisited) + { + if (u == null || dist[possibleU] < dist[u]) + { + u = possibleU; + } + } + + + if (u == target) + { + break; + } + + unvisited.Remove(u); + + foreach (Node n in u.neighbours) + { + + //float alt = dist[u] + u.DistanceTo(n); + float alt = dist[u] + costToEnterTile(n.x, n.y); + if (alt < dist[n]) + { + dist[n] = alt; + prev[n] = u; + } + } + } + //if were here we found shortest path, or no path exists + if (prev[target] == null) + { + //No route; + return; + } + currentPath = new List(); + Node curr = target; + //Step through the current path and add it to the chain + while (curr != null) + { + currentPath.Add(curr); + curr = prev[curr]; + } + //Now currPath is from target to our source, we need to reverse it from source to target. + currentPath.Reverse(); + + selectedUnit.GetComponent().path = currentPath; + + + + + } + + //In: tile's x and y position + //Out: cost that is requiredd to enter the tile + //Desc: checks the cost of the tile for a unit to enter + public float costToEnterTile(int x, int y) + { + + if (unitCanEnterTile(x, y) == false) + { + return Mathf.Infinity; + + } + + //Gotta do the math here + Tile t = tileTypes[tiles[x, y]]; + float dist = t.movementCost; + + return dist; + } + + //change this when we add movement types + //In: tile's x and y position + //Out: true or false if the unit can enter the tile that was entered + //Desc: if the tile is not occupied by another team's unit, then you can walk through and if the tile is walkable + public bool unitCanEnterTile(int x, int y) + { + if (tilesOnMap[x, y].GetComponent().unitOnTile != null) + { + if (tilesOnMap[x, y].GetComponent().unitOnTile.GetComponent().teamNum != selectedUnit.GetComponent().teamNum) + { + return false; + } + } + return tileTypes[tiles[x, y]].isWalkable; + } + + + //In: + //Out: void + //Desc: uses a raycast to see where the mouse is pointing, this is used to select units + public void mouseClickToSelectUnit() + { + GameObject tempSelectedUnit; + + RaycastHit hit; + Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); + + + + if (Physics.Raycast(ray, out hit)) + { + + + //Debug.Log(hit.transform.tag); + if (unitSelected == false) + { + + if (hit.transform.gameObject.CompareTag("Tile")) + { + if (hit.transform.GetComponent().unitOnTile != null) + { + + + tempSelectedUnit = hit.transform.GetComponent().unitOnTile; + if (tempSelectedUnit.GetComponent().unitMoveState == tempSelectedUnit.GetComponent().getMovementStateEnum(0) + && tempSelectedUnit.GetComponent().teamNum == GMS.currentTeam + ) + { + disableHighlightUnitRange(); + selectedUnit = tempSelectedUnit; + selectedUnit.GetComponent().map = this; + selectedUnit.GetComponent().setMovementState(1); + unitSelected = true; + + highlightUnitRange(); + } + } + } + + else if (hit.transform.parent != null && hit.transform.parent.gameObject.CompareTag("Unit")) + { + + tempSelectedUnit = hit.transform.parent.gameObject; + if (tempSelectedUnit.GetComponent().unitMoveState == tempSelectedUnit.GetComponent().getMovementStateEnum(0) + && tempSelectedUnit.GetComponent().teamNum == GMS.currentTeam + ) + { + + disableHighlightUnitRange(); + selectedUnit = tempSelectedUnit; + selectedUnit.GetComponent().setMovementState(1); + //These were here before I don't think they do anything the unit location is set beforehand + //selectedUnit.GetComponent().x = (int)selectedUnit.transform.position.x; + // selectedUnit.GetComponent().y = (int)selectedUnit.transform.position.z; + selectedUnit.GetComponent().map = this; + unitSelected = true; + + highlightUnitRange(); + } + } + } + + } + } + + + + //In: + //Out: void + //Desc: finalizes the movement, sets the tile the unit moved to as occupied, etc + public void finalizeMovementPosition() + { + tilesOnMap[selectedUnit.GetComponent().x, selectedUnit.GetComponent().y].GetComponent().unitOnTile = selectedUnit; + //After a unit has been moved we will set the unitMoveState to (2) the 'Moved' state + + + selectedUnit.GetComponent().setMovementState(2); + + highlightUnitAttackOptionsFromPosition(); + highlightTileUnitIsOccupying(); + } + + + + //In: + //Out: void + //Desc: selects a unit based on the cursor from the other script + public void mouseClickToSelectUnitV2() + { + + if (unitSelected == false && GMS.tileBeingDisplayed!=null) + { + + if (GMS.tileBeingDisplayed.GetComponent().unitOnTile != null) + { + GameObject tempSelectedUnit = GMS.tileBeingDisplayed.GetComponent().unitOnTile; + if (tempSelectedUnit.GetComponent().unitMoveState == tempSelectedUnit.GetComponent().getMovementStateEnum(0) + && tempSelectedUnit.GetComponent().teamNum == GMS.currentTeam + ) + { + disableHighlightUnitRange(); + //selectedSound.Play(); + selectedUnit = tempSelectedUnit; + selectedUnit.GetComponent().map = this; + selectedUnit.GetComponent().setMovementState(1); + selectedUnit.GetComponent().setSelectedAnimation(); + unitSelected = true; + highlightUnitRange(); + + } + } + } + +} + //In: + //Out: void + //Desc: finalizes the player's option, wait or attack + public void finalizeOption() + { + + RaycastHit hit; + Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); + HashSet attackableTiles = getUnitAttackOptionsFromPosition(); + + if (Physics.Raycast(ray, out hit)) + { + + //This portion is to ensure that the tile has been clicked + //If the tile has been clicked then we need to check if there is a unit on it + if (hit.transform.gameObject.CompareTag("Tile")) + { + if (hit.transform.GetComponent().unitOnTile != null) + { + GameObject unitOnTile = hit.transform.GetComponent().unitOnTile; + int unitX = unitOnTile.GetComponent().x; + int unitY = unitOnTile.GetComponent().y; + + if (unitOnTile == selectedUnit) + { + disableHighlightUnitRange(); + Debug.Log("ITS THE SAME UNIT JUST WAIT"); + selectedUnit.GetComponent().wait(); + selectedUnit.GetComponent().setWaitIdleAnimation(); + selectedUnit.GetComponent().setMovementState(3); + deselectUnit(); + + + } + else if (unitOnTile.GetComponent().teamNum != selectedUnit.GetComponent().teamNum && attackableTiles.Contains(graph[unitX,unitY])) + { + if (unitOnTile.GetComponent().currentHealthPoints > 0) + { + Debug.Log("We clicked an enemy that should be attacked"); + Debug.Log(selectedUnit.GetComponent().currentHealthPoints); + StartCoroutine(BMS.attack(selectedUnit, unitOnTile)); + + + StartCoroutine(deselectAfterMovements(selectedUnit, unitOnTile)); + } + } + } + } + else if (hit.transform.parent != null && hit.transform.parent.gameObject.CompareTag("Unit")) + { + GameObject unitClicked = hit.transform.parent.gameObject; + int unitX = unitClicked.GetComponent().x; + int unitY = unitClicked.GetComponent().y; + + if (unitClicked == selectedUnit) + { + disableHighlightUnitRange(); + Debug.Log("ITS THE SAME UNIT JUST WAIT"); + selectedUnit.GetComponent().wait(); + selectedUnit.GetComponent().setWaitIdleAnimation(); + selectedUnit.GetComponent().setMovementState(3); + deselectUnit(); + + } + else if (unitClicked.GetComponent().teamNum != selectedUnit.GetComponent().teamNum && attackableTiles.Contains(graph[unitX, unitY])) + { + if (unitClicked.GetComponent().currentHealthPoints > 0) + { + + Debug.Log("We clicked an enemy that should be attacked"); + Debug.Log("Add Code to Attack enemy"); + //selectedUnit.GetComponent().setAttackAnimation(); + StartCoroutine(BMS.attack(selectedUnit, unitClicked)); + + // selectedUnit.GetComponent().wait(); + //Check if soemone has won + //GMS.checkIfUnitsRemain(); + StartCoroutine(deselectAfterMovements(selectedUnit, unitClicked)); + } + } + + } + } + +} + + //In: + //Out: void + //Desc: de-selects the unit + public void deselectUnit() + { + + if (selectedUnit != null) + { + if (selectedUnit.GetComponent().unitMoveState == selectedUnit.GetComponent().getMovementStateEnum(1)) + { + disableHighlightUnitRange(); + disableUnitUIRoute(); + selectedUnit.GetComponent().setMovementState(0); + + + selectedUnit = null; + unitSelected = false; + } + else if (selectedUnit.GetComponent().unitMoveState == selectedUnit.GetComponent().getMovementStateEnum(3) ) + { + disableHighlightUnitRange(); + disableUnitUIRoute(); + unitSelected = false; + selectedUnit = null; + } + else + { + disableHighlightUnitRange(); + disableUnitUIRoute(); + tilesOnMap[selectedUnit.GetComponent().x, selectedUnit.GetComponent().y].GetComponent().unitOnTile = null; + tilesOnMap[unitSelectedPreviousX, unitSelectedPreviousY].GetComponent().unitOnTile = selectedUnit; + + selectedUnit.GetComponent().x = unitSelectedPreviousX; + selectedUnit.GetComponent().y = unitSelectedPreviousY; + selectedUnit.GetComponent().tileBeingOccupied = previousOccupiedTile; + selectedUnit.transform.position = tileCoordToWorldCoord(unitSelectedPreviousX, unitSelectedPreviousY); + selectedUnit.GetComponent().setMovementState(0); + selectedUnit = null; + unitSelected = false; + } + } + } + + + //In: + //Out: void + //Desc: highlights the units range options (this is the portion shown in the video) + public void highlightUnitRange() + { + + + HashSet finalMovementHighlight = new HashSet(); + HashSet totalAttackableTiles = new HashSet(); + HashSet finalEnemyUnitsInMovementRange = new HashSet(); + + int attRange = selectedUnit.GetComponent().attackRange; + int moveSpeed = selectedUnit.GetComponent().moveSpeed; + + + Node unitInitialNode = graph[selectedUnit.GetComponent().x, selectedUnit.GetComponent().y]; + finalMovementHighlight = getUnitMovementOptions(); + totalAttackableTiles = getUnitTotalAttackableTiles(finalMovementHighlight, attRange, unitInitialNode); + //Debug.Log("There are this many available tiles for the unit: "+finalMovementHighlight.Count); + + foreach (Node n in totalAttackableTiles) + { + + if (tilesOnMap[n.x, n.y].GetComponent().unitOnTile != null) + { + GameObject unitOnCurrentlySelectedTile = tilesOnMap[n.x, n.y].GetComponent().unitOnTile; + if (unitOnCurrentlySelectedTile.GetComponent().teamNum != selectedUnit.GetComponent().teamNum) + { + finalEnemyUnitsInMovementRange.Add(n); + } + } + } + + + highlightEnemiesInRange(totalAttackableTiles); + //highlightEnemiesInRange(finalEnemyUnitsInMovementRange); + highlightMovementRange(finalMovementHighlight); + //Debug.Log(finalMovementHighlight.Count); + selectedUnitMoveRange = finalMovementHighlight; + + //This final bit sets the selected Units tiles, which can be accessible in other functions + //Probably bad practice, but I'll need to get things to work for now (2019-09-30) + selectedUnitTotalRange = getUnitTotalRange(finalMovementHighlight, totalAttackableTiles); + //Debug.Log(unionTiles.Count); + + //Debug.Log("exiting the while loop"); + //This will for each loop will highlight the movement range of the units + + + } + + + //In: + //Out: void + //Desc: disables the quads that are being used to highlight position + public void disableUnitUIRoute() + { + foreach(GameObject quad in quadOnMapForUnitMovementDisplay) + { + if (quad.GetComponent().enabled == true) + { + + quad.GetComponent().enabled = false; + } + } + } + + //In: + //Out: HashSet of the tiles that can be reached by unit + //Desc: returns the hashSet of nodes that the unit can reach from its position + public HashSet getUnitMovementOptions() + { + float[,] cost = new float[mapSizeX, mapSizeY]; + HashSet UIHighlight = new HashSet(); + HashSet tempUIHighlight = new HashSet(); + HashSet finalMovementHighlight = new HashSet(); + int moveSpeed = selectedUnit.GetComponent().moveSpeed; + Node unitInitialNode = graph[selectedUnit.GetComponent().x, selectedUnit.GetComponent().y]; + + ///Set-up the initial costs for the neighbouring nodes + finalMovementHighlight.Add(unitInitialNode); + foreach (Node n in unitInitialNode.neighbours) + { + cost[n.x, n.y] = costToEnterTile(n.x, n.y); + //Debug.Log(cost[n.x, n.y]); + if (moveSpeed - cost[n.x, n.y] >= 0) + { + UIHighlight.Add(n); + } + } + + finalMovementHighlight.UnionWith(UIHighlight); + + while (UIHighlight.Count != 0) + { + foreach (Node n in UIHighlight) + { + foreach (Node neighbour in n.neighbours) + { + if (!finalMovementHighlight.Contains(neighbour)) + { + cost[neighbour.x, neighbour.y] = costToEnterTile(neighbour.x, neighbour.y) + cost[n.x, n.y]; + //Debug.Log(cost[neighbour.x, neighbour.y]); + if (moveSpeed - cost[neighbour.x, neighbour.y] >= 0) + { + //Debug.Log(cost[neighbour.x, neighbour.y]); + tempUIHighlight.Add(neighbour); + } + } + } + + } + + UIHighlight = tempUIHighlight; + finalMovementHighlight.UnionWith(UIHighlight); + tempUIHighlight = new HashSet(); + + } + Debug.Log("The total amount of movable spaces for this unit is: " + finalMovementHighlight.Count); + Debug.Log("We have used the function to calculate it this time"); + return finalMovementHighlight; + } + + //In: finalMovement highlight and totalAttackabletiles + //Out: a hashSet of nodes that are the combination of the two inputs + //Desc: returns the unioned hashSet + public HashSet getUnitTotalRange(HashSet finalMovementHighlight, HashSet totalAttackableTiles) + { + HashSet unionTiles = new HashSet(); + unionTiles.UnionWith(finalMovementHighlight); + //unionTiles.UnionWith(finalEnemyUnitsInMovementRange); + unionTiles.UnionWith(totalAttackableTiles); + return unionTiles; + } + //In: finalMovement highlight, the attack range of the unit, and the initial node that the unit was standing on + //Out: hashSet Node of the total attackable tiles for the unit + //Desc: returns a set of nodes that represent the unit's total attackable tiles + public HashSet getUnitTotalAttackableTiles(HashSet finalMovementHighlight, int attRange, Node unitInitialNode) + { + HashSet tempNeighbourHash = new HashSet(); + HashSet neighbourHash = new HashSet(); + HashSet seenNodes = new HashSet(); + HashSet totalAttackableTiles = new HashSet(); + foreach (Node n in finalMovementHighlight) + { + neighbourHash = new HashSet(); + neighbourHash.Add(n); + for (int i = 0; i < attRange; i++) + { + foreach (Node t in neighbourHash) + { + foreach (Node tn in t.neighbours) + { + tempNeighbourHash.Add(tn); + } + } + + neighbourHash = tempNeighbourHash; + tempNeighbourHash = new HashSet(); + if (i < attRange - 1) + { + seenNodes.UnionWith(neighbourHash); + } + + } + neighbourHash.ExceptWith(seenNodes); + seenNodes = new HashSet(); + totalAttackableTiles.UnionWith(neighbourHash); + } + totalAttackableTiles.Remove(unitInitialNode); + + //Debug.Log("The unit node has this many attack options" + totalAttackableTiles.Count); + return (totalAttackableTiles); + } + + + //In: + //Out: hashSet of nodes get all the attackable tiles from the current position + //Desc: returns a set of nodes that are all the attackable tiles from the units current position + public HashSet getUnitAttackOptionsFromPosition() + { + HashSet tempNeighbourHash = new HashSet(); + HashSet neighbourHash = new HashSet(); + HashSet seenNodes = new HashSet(); + Node initialNode = graph[selectedUnit.GetComponent().x, selectedUnit.GetComponent().y]; + int attRange = selectedUnit.GetComponent().attackRange; + + + neighbourHash = new HashSet(); + neighbourHash.Add(initialNode); + for (int i = 0; i < attRange; i++) + { + foreach (Node t in neighbourHash) + { + foreach (Node tn in t.neighbours) + { + tempNeighbourHash.Add(tn); + } + } + neighbourHash = tempNeighbourHash; + tempNeighbourHash = new HashSet(); + if (i < attRange - 1) + { + seenNodes.UnionWith(neighbourHash); + } + } + neighbourHash.ExceptWith(seenNodes); + neighbourHash.Remove(initialNode); + return neighbourHash; + } + + //In: + //Out: hashSet node that the unit is currently occupying + //Desc: returns a set of nodes of the tile that the unit is occupying + public HashSet getTileUnitIsOccupying() + { + + int x = selectedUnit.GetComponent().x; + int y = selectedUnit.GetComponent().y; + HashSet singleTile = new HashSet(); + singleTile.Add(graph[x, y]); + return singleTile; + + } + + //In: + //Out: void + //Desc: highlights the selected unit's options + public void highlightTileUnitIsOccupying() + { + if (selectedUnit != null) + { + highlightMovementRange(getTileUnitIsOccupying()); + } + } + + //In: + //Out: void + //Desc: highlights the selected unit's attackOptions from its position + public void highlightUnitAttackOptionsFromPosition() + { + if (selectedUnit != null) + { + highlightEnemiesInRange(getUnitAttackOptionsFromPosition()); + } + } + + //In: Hash set of the available nodes that the unit can range + //Out: void - it changes the quadUI property in the gameworld to visualize the selected unit's movement + //Desc: This function highlights the selected unit's movement range + public void highlightMovementRange(HashSet movementToHighlight) + { + foreach (Node n in movementToHighlight) + { + quadOnMap[n.x, n.y].GetComponent().material = blueUIMat; + quadOnMap[n.x, n.y].GetComponent().enabled = true; + } + } + + + + //In: Hash set of the enemies in range of the selected Unit + //Out: void - it changes the quadUI property in the gameworld to visualize an enemy + //Desc: This function highlights the enemies in range once they have been added to a hashSet + public void highlightEnemiesInRange(HashSet enemiesToHighlight) + { + foreach (Node n in enemiesToHighlight) + { + quadOnMap[n.x, n.y].GetComponent().material = redUIMat; + quadOnMap[n.x, n.y].GetComponent().enabled = true; + } + } + + + //In: + //Out: void + //Desc: disables the highlight + public void disableHighlightUnitRange() + { + foreach(GameObject quad in quadOnMap) + { + if(quad.GetComponent().enabled == true) + { + quad.GetComponent().enabled = false; + } + } + } + + //In: + //Out: void + //Desc: moves the unit then finalizes the movement + public IEnumerator moveUnitAndFinalize() + { + disableHighlightUnitRange(); + disableUnitUIRoute(); + while (selectedUnit.GetComponent().movementQueue.Count != 0) + { + yield return new WaitForEndOfFrame(); + } + finalizeMovementPosition(); + selectedUnit.GetComponent().setSelectedAnimation(); + } + + + //In: both units engaged in a battle + //Out: + //Desc: deselects the selected unit after the action has been taken + public IEnumerator deselectAfterMovements(GameObject unit, GameObject enemy) + { + //selectedSound.Play(); + selectedUnit.GetComponent().setMovementState(3); + disableHighlightUnitRange(); + disableUnitUIRoute(); + //If i dont have this wait for seconds the while loops get passed as the coroutine has not started from the other script + //Adding a delay here to ensure that it all works smoothly. (probably not the best idea) + yield return new WaitForSeconds(.25f); + while (unit.GetComponent().combatQueue.Count > 0) + { + yield return new WaitForEndOfFrame(); + } + while (enemy.GetComponent().combatQueue.Count > 0) + { + yield return new WaitForEndOfFrame(); + + } + Debug.Log("All animations done playing"); + + deselectUnit(); + + + } + + //In: + //Out: true if there is a tile that was clicked that the unit can move to, false otherwise + //Desc: checks if the tile that was clicked is move-able for the selected unit + public bool selectTileToMoveTo() + { + RaycastHit hit; + Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); + if (Physics.Raycast(ray, out hit)) + { + + if (hit.transform.gameObject.CompareTag("Tile")){ + + int clickedTileX = hit.transform.GetComponent().tileX; + int clickedTileY = hit.transform.GetComponent().tileY; + Node nodeToCheck = graph[clickedTileX, clickedTileY]; + //var unitScript = selectedUnit.GetComponent(); + + if (selectedUnitMoveRange.Contains(nodeToCheck)) { + if ((hit.transform.gameObject.GetComponent().unitOnTile == null || hit.transform.gameObject.GetComponent().unitOnTile == selectedUnit) && (selectedUnitMoveRange.Contains(nodeToCheck))) + { + Debug.Log("We have finally selected the tile to move to"); + generatePathTo(clickedTileX, clickedTileY); + return true; + } + } + } + else if (hit.transform.gameObject.CompareTag("Unit")) + { + + if (hit.transform.parent.GetComponent().teamNum != selectedUnit.GetComponent().teamNum) + { + Debug.Log("Clicked an Enemy"); + } + else if(hit.transform.parent.gameObject == selectedUnit) + { + + generatePathTo(selectedUnit.GetComponent().x, selectedUnit.GetComponent().y); + return true; + } + } + + } + return false; + } + + +}