public void OnLeftClick(IMouseTargetable target, Vector3 exactClickPosition) { if (target is IDamageable) { var targetObject = target as IDamageable; if (attack.CanAttack(targetObject)) { Networking.instance.SendCommandToStartAttack(this, targetObject); statistics.numberOfAttacks--; } } if (target is Unit) { var targetUnit = target as Unit; if (targetUnit == this) { targetUnit.GetMyOwner().DeselectUnit(); } else if (targetUnit.GetMyOwner().team == owner.team) { targetUnit.GetMyOwner().SelectUnit(targetUnit); } } else if (target is Tile) { MultiTile destination = (target as Tile).PositionRelatedToMouse(currentPosition.size, exactClickPosition); if (CanMoveTo(destination)) { Networking.instance.SendCommandToMove(this, destination); } } }
public override IEnumerator MoveTo(MultiTile destination) { PlayMovementAnimation(); //this is what can be called retarded movement, but i cannot into realistic movement as much as Poland cannot into space ;<\ // it flies up, then forwards, then down, in straight lines. I know it is bad! //turns in one frame currently TurnTowards(destination.center); //while not up enough, rise while (myUnit.transform.position.y < flyHeight) { FlyUp(); yield return(null); } //once we have broke out of the first loop, we will not get back to it (we use yield return, not yield break) //while not above the target, fly towards it while (!IsAbove(destination.center)) { FlyForward(); yield return(null); } while (myUnit.transform.position.y > 0) { Land(); yield return(null); } StopMovementAnimation(); //HERE we need to pathfind, actually, to get distance etc. to know how many points we lost - I THINK. Or maybe fliers cannot move more that once per turn xD? myUnit.statistics.movementPoints = 0; myUnit.OnMove(myUnit.currentPosition, destination); destination.SetMyObjectTo(myUnit); PlayerInput.instance.isInputBlocked = false; }
void SpawnObstacle() { Tile targetTile = target as Tile; Obstacle obstacle = Instantiate(obstaclePrefab, targetTile.transform.position, obstaclePrefab.transform.rotation).GetComponent <Obstacle>(); obstacle.OnSpawn(MultiTile.Create(targetTile, obstacle.currentPosition.size)); }
public override IEnumerator MoveTo(MultiTile newPosition) { finalPosition = newPosition; Queue <MultiTile> path = Pathfinder.instance.GetPathFromTo(myUnit, newPosition); if (myUnit.IsExittingCombat(newPosition)) { myUnit.ExitCombat(); int health = myUnit.statistics.healthPoints; foreach (Tile neighbour in myUnit.currentPosition.closeNeighbours) { if (myUnit.IsAlive() && neighbour.GetMyObject <Unit>() != null && myUnit.IsEnemyOf(neighbour.GetMyObject <Unit>())) { int damage = DamageCalculator.CalculateDamage(neighbour.GetMyObject <Unit>(), myUnit, 1.5f); neighbour.GetMyObject <Unit>().Backstab(myUnit, damage); health -= damage; } } if (health > 0) { //THe attacks will not kill us, cause calculated :P } else { //rip, abort. yield break; } } BattlescapeGraphics.ColouringTool.UncolourAllTiles(); PlayMovementAnimation(); int tileCount = path.Count; for (int i = 0; i < tileCount; ++i) { MultiTile temporaryGoal = path.Dequeue(); myUnit.OnMove(myUnit.currentPosition, temporaryGoal); myUnit.TryToSetMyPositionTo(temporaryGoal); //I am aware, that for now we are still just turning into a direction in one frame. If we ever want it any other way, it needs a bit of work to set it otherwise so im not doing it now :D. //if we want to slowly turn, we need to ask if we already turned, and if not we turn and if yes we move here. TurnTowards(temporaryGoal.center); while (Vector3.Distance(myUnit.transform.position, temporaryGoal.center) > 0.0001f) { myUnit.transform.position = Vector3.MoveTowards(myUnit.transform.position, temporaryGoal.center, visualSpeed * Time.deltaTime); yield return(null); } temporaryGoal.SetMyObjectTo(myUnit); } StopMovementAnimation(); PlayerInput.instance.isInputBlocked = false; if (newPosition.IsProtectedByEnemyOf(myUnit)) { myUnit.statistics.movementPoints = 0; } else { myUnit.statistics.movementPoints -= tileCount - 1; } BattlescapeGraphics.ColouringTool.ColourLegalTilesFor(myUnit); }
// this class is supposed to make an army "randomly" position itself in the begining of a fight. I want it also to be an option for PLAYER's army - so that a "casual" player, who does not want to // have to think about it - can also click it and not think about positioning army before the battle. public void RepositionUnits() { foreach (Unit unit in GameRound.instance.currentPlayer.playerUnits) { MultiTile newPosition = ChooseThePosition(unit.currentPosition.size); DropZone.instance.SendCommandToSetUnitPosition(unit, newPosition); } }
bool HasExtraSpace(MultiTile position) { foreach (Tile neighbour in position.closeNeighbours) { if (neighbour.IsEmpty() == false) { return(false); } } return(true); }
public bool CanMoveTo(MultiTile destination) { return (destination != null && myUnit.GetMyOwner().IsCurrentLocalPlayer() && myUnit.GetMyOwner() == GameRound.instance.currentPlayer && GameRound.instance.currentPhase == TurnPhases.Movement && myUnit.CanStillMove() && Pathfinder.instance.IsLegalTileForUnit(destination, myUnit) && PlayerInput.instance.isInputBlocked == false); }
void SetDistancesToMinus(MultiTile start) { distances = new int[Global.instance.currentMap.mapWidth - start.size.width + 1, Global.instance.currentMap.mapHeight - start.size.height + 1]; for (int i = 0; i < Global.instance.currentMap.mapWidth - start.size.width + 1; i++) { for (int j = 0; j < Global.instance.currentMap.mapHeight - start.size.height + 1; j++) { distances[i, j] = -1; } } }
public static void SetNewPosition(int index, int endPosX, int endPosZ) { Vector3 newPos = Global.instance.currentMap.board[endPosX, endPosZ].transform.position; Unit unit = UnitFactory.GetUnitByIndex(index); Tile tile = Global.instance.currentMap.board[endPosX, endPosZ]; unit.TryToSetMyPositionAndMoveTo(MultiTile.Create(tile, unit.currentPosition.size)); unit.FaceMiddleOfMap(); }
//Played BEFORE the first step in the whole movement. Check for ExitCombat here cause it only makes sense here. //Returns true if movement is exiting combat public bool IsExittingCombat(MultiTile newPosition) { if (newPosition.IsProtectedByEnemyOf(this)) { return(false); } if (currentPosition.IsProtectedByEnemyOf(this)) { return(true); } return(false); }
void PlaceObject(GameObject objectToPlace, MultiTile position) { if (position == null) { GameObject.Destroy(objectToPlace); return; } objectToPlace.GetComponent <IVisuals>().OnSpawn(position); Vector3 oldScale = objectToPlace.transform.localScale; objectToPlace.transform.SetParent(position.bottomLeftCorner.transform); objectToPlace.transform.localScale = oldScale; }
public bool IsLegalTileForUnit(MultiTile position, Unit unit) { BFS(unit); int legalDistance = 0; if (unit.IsInCombat() && unit.statistics.movementPoints > 0) { legalDistance = 1; } else if (unit.IsInCombat() == false) { legalDistance = unit.statistics.movementPoints; } return(distances[position.bottomLeftCorner.position.x, position.bottomLeftCorner.position.z] <= legalDistance && distances[position.bottomLeftCorner.position.x, position.bottomLeftCorner.position.z] > 0); }
public void OnTileToMoveHovered(Unit unitToMove, MultiTile targetTile) { if (targetTile.IsProtectedByEnemyOf(unitToMove)) { SetCursorTo(enterCombatCursor, clickingEnterCombatCursor); } else if (unitToMove.IsInCombat()) { SetCursorTo(combatExitingMovementCursor, clickingCombatExitingMovementCursor); } else { SetCursorTo(walkingCursor, clickingWalkingCursor); } }
public void OnTileHovered(Tile hoveredTile, Vector3 exactMousePosition) { MultiTile hoveredMultitile = hoveredTile.PositionRelatedToMouse(currentPosition.size, exactMousePosition); if (CanMoveTo(hoveredMultitile)) { foreach (Unit otherUnit in Global.instance.GetAllUnits()) { if (IsEnemyOf(otherUnit) && CouldAttackEnemyFromTile(otherUnit, hoveredMultitile)) { BattlescapeGraphics.ColouringTool.ColourObject(otherUnit, Color.red); } } } }
void RPCDoMovement(int startX, int startZ, int endX, int endZ) { Tile bottomLeftCorner = Global.instance.currentMap.board[startX, startZ]; Unit unit = bottomLeftCorner.GetMyObject <Unit>(); if (unit == null) { Debug.LogError("NoUnit!"); LogConsole.instance.SpawnLog("NO UNIT TO MOVE!"); return; } MultiTile destination = MultiTile.Create(Global.instance.currentMap.board[endX, endZ], unit.currentPosition.size); unit.Move(destination); }
MultiTile CalibrateToFitInBoard(MultiTile position) { int posX = position.bottomLeftCorner.position.x; int posZ = position.bottomLeftCorner.position.z; if (posX + position.size.width > Global.instance.currentMap.mapWidth) { posX = Global.instance.currentMap.mapWidth - position.size.width; } if (posZ + position.size.height > Global.instance.currentMap.mapHeight) { posZ = Global.instance.currentMap.mapHeight - position.size.height; } return(MultiTile.Create(Global.instance.currentMap.board[posX, posZ], position.size)); }
public MultiTile PositionRelatedToMouse(Size size, Vector3 exactClickPosition) { // this variable is equal to 1 if width or height are even, otherwise 0 int widthEven = size.width % 2; int heightEven = size.height % 2; // check which part of tile player clicked int xGt = Convert.ToInt32(exactClickPosition.x > this.transform.position.x); int zGt = Convert.ToInt32(exactClickPosition.z > this.transform.position.z); // find new bottom left corner of Multitile int widthOffset = (size.width - widthEven) / 2 - xGt * Convert.ToInt32(widthEven == 0); int heightOffset = (size.height - heightEven) / 2 - zGt * Convert.ToInt32(heightEven == 0); return(MultiTile.Create(ToTile(this.Offset(-widthOffset, -heightOffset).CalibrateTo(size.width, size.height)), size)); }
public void OnMove(MultiTile oldPosition, MultiTile newPosition) { //played on EVERY change of tile. Two tiles are used here to avoid confusion in using currentPosition - this will work no matter if we use it slightly before or after movement. if (oldPosition.IsProtectedByEnemyOf(this) == false && newPosition.IsProtectedByEnemyOf(this)) { //Unit just came from SAFETY to COMBAT, so inform it and all of the enemies around about it. OnCombatEnter(); foreach (Tile neighbour in newPosition.closeNeighbours) { if (neighbour.GetMyObject <Unit>() != null && IsEnemyOf(neighbour.GetMyObject <Unit>())) { neighbour.GetMyObject <Unit>().OnCombatEnter(); } } } }
public int DistanceTo(MultiTile other) { int currentDistance = Int32.MaxValue; foreach (Tile tile in this) { foreach (Tile otherTile in other) { int newDistance = tile.position.DistanceTo(otherTile.position); if (newDistance < currentDistance) { currentDistance = newDistance; } } } return(currentDistance); }
public void OnCursorOver(IMouseTargetable target, Vector3 exactMousePosition) { if (target is Unit) { var targetUnit = target as Unit; if (targetUnit.CanBeSelected()) { Cursor.instance.OnSelectableHovered(); return; } } if (target is IDamageable) { var targetDamagableObject = target as IDamageable; if (attack.CanAttack(targetDamagableObject)) { Cursor.instance.OnEnemyHovered(this, targetDamagableObject); return; } else { Cursor.instance.ShowInfoCursor(); } } if (target is Tile) { var targetTile = target as Tile; MultiTile position = targetTile.PositionRelatedToMouse(currentPosition.size, exactMousePosition); if (CanMoveTo(position)) { BattlescapeGraphics.ColouringTool.ColourLegalTilesFor(this); BattlescapeGraphics.ColouringTool.OnPositionHovered(position); Cursor.instance.OnTileToMoveHovered(this, position); } else { Cursor.instance.OnInvalidTargetHovered(); } } else { Cursor.instance.OnInvalidTargetHovered(); } }
//This function gives the list of possible tiles a Unit could get to. public List <MultiTile> GetAllLegalPositionsFor(Unit unitToMove) { List <MultiTile> returnList = new List <MultiTile>(); BFS(unitToMove); for (int i = 0; i < Global.instance.currentMap.mapWidth - unitToMove.currentPosition.size.width + 1; i++) { for (int j = 0; j < Global.instance.currentMap.mapHeight - unitToMove.currentPosition.size.height + 1; j++) { MultiTile newPosition = MultiTile.Create(Global.instance.currentMap.board[i, j], unitToMove.currentPosition.size); if (unitToMove.CanMoveTo(newPosition)) { returnList.Add(newPosition); } } } return(returnList); }
//This function populates Distances and Parents arrays with data, using BFS algorithm. //Currently it just calculates for whole board (not until reaching destination). void BFS(Unit unitToMove) { //THIS first part is just for optimization if (HaveToBFSFor(unitToMove) == false) { return; } else { lastTile = unitToMove.currentPosition.bottomLeftCorner; lastUnit = unitToMove; } MultiTile start = unitToMove.currentPosition; parents = new MultiTile[Global.instance.currentMap.mapWidth - start.size.width + 1, Global.instance.currentMap.mapHeight - start.size.height + 1]; SetDistancesToMinus(start); SetProtectedByEnemy(unitToMove); Queue <MultiTile> queue = new Queue <MultiTile>(); distances[start.bottomLeftCorner.position.x, start.bottomLeftCorner.position.z] = 0; queue.Enqueue(start); while (queue.Count > 0) { MultiTile current = queue.Peek(); queue.Dequeue(); foreach (MultiTile neighbour in current.neighbours) { if (distances[neighbour.bottomLeftCorner.position.x, neighbour.bottomLeftCorner.position.z] == -1 && neighbour.IsFreeFor(unitToMove) && IsQuittingCombatIntoCombat(unitToMove, neighbour) == false) { distances[neighbour.bottomLeftCorner.position.x, neighbour.bottomLeftCorner.position.z] = distances[current.bottomLeftCorner.position.x, current.bottomLeftCorner.position.z] + 1; parents[neighbour.bottomLeftCorner.position.x, neighbour.bottomLeftCorner.position.z] = current; foreach (Tile tile in neighbour) { if (!enemyProtection[tile.position.x, tile.position.z]) { queue.Enqueue(neighbour); } } } } } }
public Queue <MultiTile> GetPathFromTo(Unit unitToMove, MultiTile destination) { BFS(unitToMove); Stack <MultiTile> tileStack = new Stack <MultiTile>(); tileStack.Push(destination); while (!tileStack.Contains(unitToMove.currentPosition)) { MultiTile positionOnTheStack = tileStack.Peek(); tileStack.Push(parents[positionOnTheStack.bottomLeftCorner.position.x, positionOnTheStack.bottomLeftCorner.position.z]); } Queue <MultiTile> path = new Queue <MultiTile>(); while (tileStack.Count > 0) { path.Enqueue(tileStack.Pop()); } return(path); }
MultiTile GetRandomMultiTile(Size size, MapVisualsSpecification spec) { int terminator = 0; Tile tile = Global.instance.currentMap.board[Random.Range(spec.minDistanceToShortSide, Global.instance.currentMap.mapWidth - spec.minDistanceToShortSide), Random.Range(spec.minDistanceToLongSide, Global.instance.currentMap.mapHeight - spec.minDistanceToLongSide)]; MultiTile position = MultiTile.Create(tile, size); while (IsMultiTileLegal(position, spec) == false) { terminator++; tile = Global.instance.currentMap.board[Random.Range(spec.minDistanceToShortSide, Global.instance.currentMap.mapWidth - spec.minDistanceToShortSide), Random.Range(spec.minDistanceToLongSide, Global.instance.currentMap.mapHeight - spec.minDistanceToLongSide)]; position = MultiTile.Create(tile, size); if (terminator == 100) { return(null); } } return(position); }
void OnMouseDrag() { if (GameRound.instance.gameRoundCount > 0) { return; } Ray cameraRay = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hitInfo; int tileMask = 1 << 9; if (Physics.Raycast(cameraRay, out hitInfo, Mathf.Infinity, tileMask)) { Tile tile = hitInfo.transform.gameObject.GetComponent <Tile>(); MultiTile position = tile.PositionRelatedToMouse(myUnit.currentPosition.size, hitInfo.point); if (position != null && (position.IsDropzoneOfTeam(GameRound.instance.currentPlayer.team.index)) && position.IsFreeFor(myUnit)) { DropZone.instance.SendCommandToSetUnitPosition(myUnit, position); } } }
MultiTile ChooseThePosition(Size size) { List <MultiTile> possibleTiles = new List <MultiTile>(); foreach (Tile tile in Global.instance.currentMap.board) { MultiTile position = MultiTile.Create(tile, size); if (position != null && position.IsWalkable() && (position.IsDropzoneOfTeam(GameRound.instance.currentPlayer.team.index))) { possibleTiles.Add(position); } } MultiTile chosenTile = Tools.GetRandomElementFromList <MultiTile>(possibleTiles); if (chosenTile == null) { Debug.LogError("Too many units, couldn't put them on battlefield"); return(null); } return(chosenTile); }
/// <summary> /// Used to either perform movement in offline modes or send an RPC in online mode. /// </summary> /// <param name="unit"> Unit to be moved to the last tile in Path made by PathCreator</param> public void SendCommandToMove(Unit unit, MultiTile destination) { PlayerInput.instance.isInputBlocked = true; //this makes sense only on the 'active' PC' that's why I put it here ;) if (Global.instance.matchType == MatchTypes.Online) { int startX = unit.currentPosition.bottomLeftCorner.position.x; int startZ = unit.currentPosition.bottomLeftCorner.position.z; int endX = destination.bottomLeftCorner.position.x; int endZ = destination.bottomLeftCorner.position.z; photonView.RPC( "RPCDoMovement", RpcTarget.All, startX, startZ, endX, endZ); } else { unit.Move(destination); } }
public abstract IEnumerator MoveTo(MultiTile destination);
bool IsMultiTileLegal(MultiTile position, MapVisualsSpecification spec) { return(position.IsEmpty() && (spec.needsExtraSpace == false || HasExtraSpace(position))); }
public void OnSpawn(MultiTile spawningTile) { TryToSetMyPositionAndMoveTo(spawningTile); }