-
-
Save markdekuijer/ad0d4afe8a93e81700b7aaa8b0643ca0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.IO; | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using System; | |
using System.Linq; | |
public class HexUnit : MonoBehaviour | |
{ | |
const float travelSpeed = 4f; | |
const float rotationSpeed = 180f; | |
List<HexCell> pathToTravel; | |
public bool hasMovedThisTurn; | |
public bool hasAttackThisTurn; | |
public bool hasTurned; | |
public bool isEnemy; | |
[SerializeField] private GameObject enemyIndicator; | |
public HexUnitAnimator animHandler; | |
private List<SkinnedMeshRenderer> skinnedRenderers = new List<SkinnedMeshRenderer>(); | |
private List<MeshRenderer> renderers = new List<MeshRenderer>(); | |
public bool IsTraveling | |
{ | |
get | |
{ | |
return isTraveling; | |
} | |
} | |
bool isTraveling; | |
HexCell location, currentTravelLocation; | |
public HexCell Location | |
{ | |
get | |
{ | |
return location; | |
} | |
set | |
{ | |
if (location) | |
{ | |
if (!isEnemy) | |
{ | |
Grid.DecreaseVisibility(location, unitType.VisionRange); | |
} | |
location.Unit = null; | |
} | |
location = value; | |
value.Unit = this; | |
if(!isEnemy) | |
Grid.IncreaseVisibility(value, unitType.VisionRange); | |
transform.localPosition = value.Position; | |
} | |
} | |
float orientation; | |
public float Orientation | |
{ | |
get | |
{ | |
return orientation; | |
} | |
set | |
{ | |
orientation = value; | |
transform.localRotation = Quaternion.Euler(0, value, 0); | |
} | |
} | |
public HexGrid Grid { get; set; } | |
public UnitType unitType; | |
public int typeID; | |
int health; | |
public int Health | |
{ | |
get | |
{ | |
return health; | |
} | |
private set | |
{ | |
if (health != value) | |
health = value; | |
} | |
} | |
public void ValidatePosition() | |
{ | |
transform.localPosition = location.Position; | |
} | |
public bool IsValidDestination(HexCell cell) | |
{ | |
return cell.IsExplored && !cell.IsUnderWater && !cell.Unit; | |
} | |
private void OnEnable() | |
{ | |
if (location) | |
{ | |
transform.localPosition = location.Position; | |
if (currentTravelLocation) | |
{ | |
if (!isEnemy) | |
{ | |
Grid.IncreaseVisibility(location, unitType.VisionRange); | |
Grid.DecreaseVisibility(currentTravelLocation, unitType.VisionRange); | |
} | |
currentTravelLocation = null; | |
} | |
} | |
} | |
//Set id and get associated unit data | |
//also set some base values | |
public void Initialize(int id, HexCell spawnCell, bool isEnemy) | |
{ | |
this.isEnemy = isEnemy; | |
typeID = id; | |
health = unitType.Health; | |
skinnedRenderers = GetComponentsInChildren<SkinnedMeshRenderer>().ToList(); | |
renderers = GetComponentsInChildren<MeshRenderer>().ToList(); | |
if (isEnemy) | |
if(enemyIndicator != null) | |
enemyIndicator.SetActive(true); | |
if (spawnCell.IsExplored || spawnCell.IsVisible) | |
{ | |
if (isEnemy) | |
DisplayRenderers(true); | |
} | |
else | |
{ | |
DisplayRenderers(false); | |
} | |
} | |
//This function will be called in combination with the fog of war | |
//Definitly write a shader for this later on instead of changing the color | |
public void DisplayRenderers(bool show) | |
{ | |
for (int i = 0; i < skinnedRenderers.Count; i++) | |
{ | |
skinnedRenderers[i].material.color = show ? new Color(1, 1, 1, 1) : new Color(0, 0, 0, 0); | |
} | |
for (int i = 0; i < renderers.Count; i++) | |
{ | |
renderers[i].material.color = show ? new Color(1, 1, 1, 1) : new Color(0, 0, 0, 0); | |
} | |
if(enemyIndicator != null) | |
enemyIndicator.SetActive(show); | |
} | |
public int GetMoveCost(HexCell fromCell, HexCell toCell, HexDirection direciton) | |
{ | |
HexEdgeType edgeType = fromCell.GetEdgeType(direciton); | |
if(edgeType == HexEdgeType.Cliff) | |
{ | |
return -1; | |
} | |
int moveCost; | |
if (fromCell.HasRoadThroughEdge(direciton)) | |
{ | |
moveCost = 1; | |
} | |
else if (fromCell.Walled != toCell.Walled) | |
{ | |
return -1; | |
} | |
else | |
{ | |
moveCost = edgeType == HexEdgeType.Flat ? 5 : 10; | |
moveCost += toCell.UrbanLevel + toCell.PlantLevel + toCell.FarmLevel; | |
} | |
return moveCost; | |
} | |
//Function called by enemys to get the closest enemy and attack that | |
//While also avoiding getting to close if the enemy has a range greater then 1 | |
public void CalculateNextMove(HexGrid grid, List<HexUnit> unitsToCheck) | |
{ | |
List<HexUnit> allUnits = new List<HexUnit>(unitsToCheck); | |
if (allUnits.Count == 0) | |
{ | |
print("No Units"); | |
hasTurned = true; | |
return; | |
} | |
HexUnit target = TurnbasedManager.Instance.GetClosestAlly(location.coordinates, allUnits); | |
bool canWalkThisPath = grid.Search(location, target.location, this, true); | |
if (canWalkThisPath) | |
{ | |
List<HexCell> path = grid.GetPathWithoutExistCheck(unitType.speed, target.location, location); | |
int reduceSteps = unitType.attackRange - 1; | |
if(path.Count > 1) | |
{ | |
if (path[path.Count - 1].Unit) | |
{ | |
path.RemoveAt(path.Count - 1); | |
if (reduceSteps > 0) | |
{ | |
if(path[path.Count - 1].coordinates.DistanceTo(target.location.coordinates) != 1) | |
{ | |
for (int i = 0; i < reduceSteps; i++) | |
{ | |
path.RemoveAt(path.Count - 1); | |
} | |
} | |
} | |
} | |
if(path.Count > 1) | |
{ | |
if(path[path.Count - 1].coordinates.DistanceTo(target.location.coordinates) == 1) | |
{ | |
for (int i = 0; i < reduceSteps; i++) | |
{ | |
path.RemoveAt(path.Count - 1); | |
} | |
} | |
} | |
Travel(path, null, target.location, false); | |
} | |
} | |
else | |
{ | |
if (!target) | |
{ | |
Debug.LogError("fcked up no target existing"); | |
} | |
allUnits.Remove(target); | |
CalculateNextMove(grid, allUnits); | |
} | |
} | |
//Travel gets the path and makes the units walk over it. | |
//after this a seperate function for AI or Player units will get called | |
//It has small differences on how the fog of war and other things get called | |
public void Travel(List<HexCell> path, HexGameUI gameUI, HexCell c, bool isPlayer) | |
{ | |
HexCell origin = location; | |
if(path.Count != 0) | |
{ | |
location.Unit = null; | |
location = path[path.Count - 1]; | |
} | |
location.Unit = this; | |
pathToTravel = path; | |
StopAllCoroutines(); | |
if (isPlayer) | |
StartCoroutine(TravelPathPlayer(gameUI, c)); | |
else | |
StartCoroutine(TravelPathEnemy(c, origin)); | |
} | |
IEnumerator TravelPathPlayer(HexGameUI gameUI, HexCell attackCell) | |
{ | |
isTraveling = true; | |
Vector3 a, b, c = pathToTravel[0].Position; | |
yield return LookAt(pathToTravel[1].Position); | |
animHandler.SetWalking(isTraveling); | |
Grid.DecreaseVisibility(currentTravelLocation ? currentTravelLocation : pathToTravel[0], unitType.VisionRange); | |
float t = Time.deltaTime * travelSpeed; | |
for (int i = 1; i < pathToTravel.Count; i++) | |
{ | |
currentTravelLocation = pathToTravel[i]; | |
a = c; | |
b = pathToTravel[i - 1].Position; | |
c = (b + currentTravelLocation.Position) * 0.5f; | |
Grid.IncreaseVisibility(pathToTravel[i], unitType.VisionRange); | |
for (; t < 1; t += Time.deltaTime * travelSpeed) | |
{ | |
transform.localPosition = Bezier.GetPoint(a, b, c, t); | |
Vector3 d = Bezier.GetDerivative(a, b, c, t); | |
d.y = 0f; | |
transform.localRotation = Quaternion.LookRotation(d); | |
yield return null; | |
} | |
Grid.DecreaseVisibility(pathToTravel[i], unitType.VisionRange); | |
t -= 1f; | |
} | |
currentTravelLocation = null; | |
a = c; | |
b = location.Position; | |
c = b; | |
Grid.IncreaseVisibility(location, unitType.VisionRange); | |
for (; t < 1; t += Time.deltaTime * travelSpeed) | |
{ | |
transform.localPosition = Bezier.GetPoint(a, b, c, t); | |
Vector3 d = Bezier.GetDerivative(a, b, c, t); | |
d.y = 0f; | |
transform.localRotation = Quaternion.LookRotation(d); yield return null; | |
} | |
transform.localPosition = location.Position; | |
orientation = transform.localRotation.eulerAngles.y; | |
ListPool<HexCell>.Add(pathToTravel); | |
pathToTravel = null; | |
isTraveling = false; | |
hasMovedThisTurn = true; | |
animHandler.SetWalking(isTraveling); | |
if(gameUI) | |
gameUI.AttackAfterCheck(attackCell); | |
} | |
IEnumerator TravelPathEnemy(HexCell attackCell, HexCell originalCell) | |
{ | |
if (originalCell.coordinates.DistanceTo(attackCell.coordinates) <= unitType.attackRange) | |
{ | |
InitAttack(attackCell, null); | |
yield break; | |
} | |
isTraveling = true; | |
Vector3 a, b, c = pathToTravel[0].Position; | |
yield return LookAt(pathToTravel[1].Position); | |
animHandler.SetWalking(isTraveling); | |
float t = Time.deltaTime * travelSpeed; | |
for (int i = 1; i < pathToTravel.Count; i++) | |
{ | |
currentTravelLocation = pathToTravel[i]; | |
a = c; | |
b = pathToTravel[i - 1].Position; | |
c = (b + currentTravelLocation.Position) * 0.5f; | |
for (; t < 1; t += Time.deltaTime * travelSpeed) | |
{ | |
transform.localPosition = Bezier.GetPoint(a, b, c, t); | |
Vector3 d = Bezier.GetDerivative(a, b, c, t); | |
d.y = 0f; | |
transform.localRotation = Quaternion.LookRotation(d); | |
yield return null; | |
} | |
t -= 1f; | |
if (currentTravelLocation.IsExplored && currentTravelLocation.IsVisible) | |
DisplayRenderers(true); | |
} | |
currentTravelLocation = null; | |
a = c; | |
b = location.Position; | |
c = b; | |
for (; t < 1; t += Time.deltaTime * travelSpeed) | |
{ | |
transform.localPosition = Bezier.GetPoint(a, b, c, t); | |
Vector3 d = Bezier.GetDerivative(a, b, c, t); | |
d.y = 0f; | |
transform.localRotation = Quaternion.LookRotation(d); yield return null; | |
} | |
transform.localPosition = location.Position; | |
orientation = transform.localRotation.eulerAngles.y; | |
ListPool<HexCell>.Add(pathToTravel); | |
pathToTravel = null; | |
isTraveling = false; | |
hasMovedThisTurn = true; | |
animHandler.SetWalking(isTraveling); | |
yield return null; | |
if(location.coordinates.DistanceTo(attackCell.coordinates) <= unitType.attackRange) | |
InitAttack(attackCell, null); | |
else | |
hasTurned = true; | |
} | |
#region attack | |
//start a coroutine for the units attack | |
//in the start of the coroutine it will rotate towards the unit that its attacking | |
//after that it will set certain variables required by the system and deal damage | |
public void InitAttack(HexCell cell, HexGameUI gameUI) | |
{ | |
if(location.IsExplored) | |
StartCoroutine(Attack(cell, gameUI)); | |
} | |
IEnumerator Attack(HexCell attackedCell, HexGameUI gameUI) | |
{ | |
yield return LookAt(attackedCell.Position); | |
animHandler.InitAttack(); | |
hasMovedThisTurn = true; | |
hasAttackThisTurn = true; | |
if(gameUI) | |
gameUI.CloseSelect(); | |
DoDamage(attackedCell.Unit); | |
yield return new WaitForSeconds(2f); | |
hasTurned = true; | |
} | |
IEnumerator LookAt(Vector3 point) | |
{ | |
point.y = transform.localPosition.y; | |
Quaternion fromRotation = transform.localRotation; | |
Quaternion toRotation = Quaternion.LookRotation(point - transform.localPosition); | |
float angle = Quaternion.Angle(fromRotation, toRotation); | |
if(angle > 0f) | |
{ | |
float speed = rotationSpeed / angle; | |
for (float t = Time.deltaTime * speed; t < 1f; t += Time.deltaTime * speed) | |
{ | |
transform.localRotation = Quaternion.Slerp(fromRotation, toRotation, t); | |
yield return null; | |
} | |
} | |
transform.LookAt(point); | |
orientation = transform.localRotation.eulerAngles.y; | |
} | |
#endregion | |
#region dmg | |
public void DoDamage(HexUnit otherUnit) | |
{ | |
if (otherUnit == null) | |
return; | |
otherUnit.TakeDamage(unitType.damage); | |
} | |
public void TakeDamage(int damage) | |
{ | |
health -= damage; | |
if(health <= 0) | |
{ | |
Die(); | |
} | |
} | |
public void Die() | |
{ | |
if(unitType.objectName == "castle") | |
{ | |
string gameoverString; | |
if (!isEnemy) | |
gameoverString = "You Lost!"; | |
else | |
gameoverString = "You Won!"; | |
HexGameUI.instance.InitGameOver(gameoverString); | |
return; | |
} | |
if (location) | |
{ | |
if (!isEnemy) | |
{ | |
Grid.DecreaseVisibility(location, unitType.VisionRange); | |
} | |
} | |
location.Unit = null; | |
animHandler.Die(); | |
if (isEnemy) | |
TurnbasedManager.Instance.enemyUnits.Remove(this); | |
else | |
TurnbasedManager.Instance.allyUnits.Remove(this); | |
//Grid.RemoveUnit(this); | |
} | |
#endregion | |
#region savedata | |
//saving and loading data gets down in bits and bytes | |
//this same format gets used everywhere in the game | |
//The reason for doing this is because you can save mid-game and continue playing without any problem later on | |
public void Save(BinaryWriter writer) | |
{ | |
location.coordinates.Save(writer); | |
writer.Write(orientation); | |
writer.Write(isEnemy); | |
writer.Write(typeID); | |
} | |
public static void Load(BinaryReader reader, HexGrid grid) | |
{ | |
HexCoordinates coordinates = HexCoordinates.Load(reader); | |
float orientation = reader.ReadSingle(); | |
bool isEnemy = reader.ReadBoolean(); | |
int typeID = reader.ReadInt32(); | |
HexUnit u = Instantiate(HexGameUI.instance.unitTypes.unitTypeIDs[typeID].GetComponent<HexUnit>()); | |
u.Initialize(typeID, grid.GetCell(coordinates), isEnemy); | |
grid.AddUnit(u, grid.GetCell(coordinates), orientation); | |
} | |
#endregion | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment