public readonly UnitType unitTypeBuild; // Nullable #endregion Fields #region Constructors public Order(OrderType orderType, Position targetPosition=null, Unit targetUnit=null, UnitType unitTypeBuild=null) { this.orderType = orderType; this.targetPosition = targetPosition; this.targetUnit = targetUnit; this.unitTypeBuild = unitTypeBuild; }
public static Position FindNextStep( Engine engine, Unit unit, Tile start, Tile end ) { List<Position> temp = FindPath(engine, unit, start, end); if (temp != null && temp.Count > 1) return temp[1]; else return null; }
public Unit NearestUnitTo(Unit startUnit, int maxDistance, Position startPosition=null) { if (startPosition == null) { startPosition = startUnit.position; } if (!Inside(startPosition)) { var nearestPosition = new Position(Math.Max(0, Math.Min(startPosition.x, width - 1)), Math.Max(0, Math.Min(startPosition.y, height - 1))); maxDistance -= nearestPosition.Distance(startPosition); startPosition = nearestPosition; } Chunk chunk = GetChunk(startPosition); // Breadth first search HashSet<Chunk> haveBeenInFrontier = new HashSet<Chunk> {chunk}; LinkedList<Chunk> frontier = new LinkedList<Chunk>(haveBeenInFrontier); while (frontier.Count > 0) { var top = frontier.First(); frontier.RemoveFirst(); // Try to find nearest in this chunk Unit closestUnit = null; int nearestDistance = Int32.MaxValue; foreach (var unit in top.units) { int distance = startPosition.Distance(unit.position); if (distance <= nearestDistance && unit != startUnit) { nearestDistance = distance; closestUnit = unit; } } if (closestUnit != null && nearestDistance <= maxDistance) { return closestUnit; } // if a unit has not been found yet, try the neighbors foreach (var neighbor in top.neighbors) { if (!haveBeenInFrontier.Contains(neighbor) && neighbor.GetDistanceFrom(startPosition) <= maxDistance) { frontier.AddLast(neighbor); haveBeenInFrontier.Add(neighbor); } } } return null; // Didn't find a unit within maxDistance }
public void OrderProduce(Unit factory, UnitType unitType, Position targetPosition = null) { factory.orders.Add(Order.CreateProduceOrder(unitType, targetPosition)); ScheduleUpdate(1, factory); }
public void OrderGather(Unit gatherer, Position target) { gatherer.orders.Add(Order.CreateGatherOrder(target)); ScheduleUpdate(1, gatherer); }
public void OrderMove(Unit unit, Position targetPosition) { unit.orders.Add(Order.CreateMoveOrder(targetPosition)); ScheduleUpdate(1, unit); }
// Kinda private methods public void MoveUnit(Unit unit, Position targetPosition) { Debug.Assert(targetPosition.Distance(unit.position) == 1); Debug.Assert(unitGrid[targetPosition.x, targetPosition.y] == null); CacheRemoveUnitAt(unit.position); unit.previousPosition = unit.position; unit.position = targetPosition; unit.animationStartTick = currentTick; CacheSetUnitAt(unit); }
public void OrderAttack(Unit attacker, Unit target) { attacker.orders.Add(Order.CreateAttackOrder(target)); ScheduleUpdate(1, attacker); }
public static Order CreateAttackOrder(Unit target) { Debug.Assert(target != null); return new Order(OrderType.Attack, targetUnit: target, targetPosition: target.position); }
public Unit FindNearestEnemy(Unit unit, int maxDistance) { Unit nearestEnemy = null; int nearestDistance = int.MaxValue; foreach (var player in players) { if (player.team != unit.owner.team) { Unit nearUnit = unitQuadtrees[player].NearestUnitTo(unit, maxDistance); if (nearUnit != null) { int distance = nearUnit.position.Distance(unit.position); if (nearestEnemy == null || distance < nearestDistance) { nearestEnemy = nearUnit; nearestDistance = distance; } } } } return nearestEnemy; }
public void SwapUnits(Unit a, Unit b) { Debug.Assert(a.position.Distance(b.position) == 1); var targetPosition = b.position; // Remove a CacheRemoveUnitAt(a.position); // Tell b to move into a's spot Debug.Assert(b.orders.Count == 0, "Swap: b still had orders left."); b.orders.Add(Order.CreateMoveOrder(a.position)); b.Update(); // This will force the unit to wait the appropriate amount of time before moving back // Debug.Assert(b.position.Equals(a.position), "Swap: b did not move back to original position."); // Add a to b's old position a.previousPosition = a.position; a.position = targetPosition; a.animationStartTick = currentTick; CacheSetUnitAt(a); // Give an order to b to go back to his original position OrderMove(b, targetPosition); }
public Unit AddUnit(UnitType unitType, Position position, Player owner) { if (!map.Inside(position)) return null; var newUnit = new Unit(GetNextId(), this, unitType, position, owner); units.Add(newUnit); unitQuadtrees[owner].AddUnit(newUnit); CacheSetUnitAt(newUnit); return newUnit; }
public void AddUnit(Unit unit) { var chunk = GetChunk(unit.position); if (chunk != null) chunk.AddUnit(unit); previousUnitPositions[unit] = new Position(unit.position); }
public void RemoveUpdate(Unit unit) { if (!futureUpdates.ContainsKey(unit.nextMove)) { return; } if( futureUpdates[unit.nextMove].Contains(unit)) { if (unit.nextMove != currentTick) // Don't remove from the current update list because WE ARE ITERATING OVER IT { futureUpdates[unit.nextMove].Remove(unit); } } }
public void RemoveUnit(Unit unit) { units.Remove(unit); }
public bool Contains(Unit unit) { return units.Contains(unit); }
public void AddUnit(Unit unit) { Debug.Assert(Inside(unit.position)); units.Add(unit); }
public void UpdateUnit(Unit unit) { // It is an error to call this when unit was never added to the quadtree Debug.Assert(previousUnitPositions.ContainsKey(unit)); Position previousPosition = previousUnitPositions[unit]; var previousChunk = GetChunk(previousPosition); var newChunk = GetChunk(unit.position); if (previousChunk != newChunk) { if (previousChunk != null) previousChunk.RemoveUnit(unit); if (newChunk != null) newChunk.AddUnit(unit); } previousUnitPositions[unit] = unit.position; }
public void RemoveUnit(Unit unit) { // It is an error to call this when unit was never added to the quadtree Debug.Assert(previousUnitPositions.ContainsKey(unit)); GetChunk(previousUnitPositions[unit]).RemoveUnit(unit); previousUnitPositions.Remove(unit); }
public void ScheduleUpdate(int ticksFromNow, Unit unit) { if (unit.nextMove < currentTick + (inTick ? 1 : 0)) { if (!futureUpdates.ContainsKey(currentTick + ticksFromNow)) { futureUpdates[currentTick + ticksFromNow] = new List<Unit>(); } futureUpdates[currentTick + ticksFromNow].Add(unit); unit.nextMove = currentTick + ticksFromNow; } }
public static Position FindNextStep( Engine engine, Unit unit, Position start, Position end) { return FindNextStep(engine, unit, engine.map.GetTileAt(start), engine.map.GetTileAt(end)); }
private void CacheSetUnitAt(Unit unit) { Debug.Assert(unit != null); if (map.Inside(unit.position)) { unitGrid[unit.position.x, unit.position.y] = unit; unitQuadtrees[unit.owner].UpdateUnit(unit); } }
public static List<Position> FindPath( Engine engine, Unit unit, Tile start, Tile end ) { List<Position> path = null; if (!unit.CanMove(end.position)) { foreach (Position pos in BreadthFirst(engine, end.position, -1, 500)) { if (unit.CanMove(pos)) { end = engine.map.tiles[pos.x, pos.y]; break; } } } if (!unit.CanMove(end.position)) { return null; } bool success = false; start.pathParent = null; start.pathDistance = 0; start.pathHeuristic = start.pathDistance + FValue(start, end); PriorityQueue<Tile> openSet = new PriorityQueue<Tile>(); openSet.Enqueue(start); int count = 0; //generate path while ( openSet.Count() > 0 ) { count += 1; Tile currentBest = openSet.Dequeue(); currentBest.pathIndex = pathCounter; // if we are at the goal end if (currentBest.position.Equals(end.position)) { success = true; break; } // Give up if we backtrack too far if ((currentBest.pathHeuristic >= start.pathHeuristic*14 && count > 2000) || count > 4000) { break; } // Take current best, generate all possible nodes, push them onto queue foreach (var neighbor in currentBest.neighbors) { if (!unit.CanMove(neighbor.position)) { continue; } double tentativeCost = currentBest.pathDistance + neighbor.tileType.movementCost; if (neighbor.pathIndex < pathCounter) { neighbor.pathIndex = pathCounter; neighbor.pathParent = currentBest; neighbor.pathDistance = tentativeCost; neighbor.pathHeuristic = neighbor.pathDistance + FValue(neighbor, end); openSet.Enqueue(neighbor); } else if (tentativeCost < neighbor.pathDistance) { // Update costs if the current path is better than the existing one neighbor.pathParent = currentBest; neighbor.pathDistance = tentativeCost; neighbor.pathHeuristic = neighbor.pathDistance + FValue(neighbor, end); openSet.HeapifyUp(neighbor); } } } if ( success ) { // Generate path by following parent from end to start path = new List<Position>(); Tile runner = end; while (runner != null) { path.Insert(0, runner.position); runner = runner.pathParent; } } pathCounter += 1; return path; }
public void Attack( Unit attacker, Unit target ) { Debug.Assert(attacker.AttackRange() >= attacker.position.Distance(target.position)); target.health -= Math.Max(1, attacker.AttackStrength() - target.Defense()); if (target.health<=0) // Target dead { RemoveUpdate(target); CacheRemoveUnitAt(target.position); units.Remove(target); unitQuadtrees[target.owner].RemoveUnit(target); target.status = Unit.Status.Dead; } else // I'm not dead yet { // Retaliate! if (target.CanAttack() && target.orders.Count == 0) { OrderAttack(target, attacker); } } }
public Vector2 getHPBarDrawPosition(Unit unit) { Vector2 drawPosition = (unit.GetAnimatedPosition() - tileIndex) * (tilePxSize + pxMod); // add offset for HP bar position drawPosition.Y += tilePxSize + pxMod; return drawPosition; }