public static int pathCounter = int.MinValue + 1; // Incremented after every check

        #endregion Fields

        #region Methods

        // Yay C# has generators!
        /// <summary>
        /// A generator that produces positions by doing a breadth first iteration of tiles starting at a given position.
        /// </summary>
        /// <param name="engine">An engine object to get tiles from</param>
        /// <param name="position">The starting position.</param>
        /// <param name="distance">The maximum distance from the starting position.  Or negative for no limit.</param>
        /// <param name="size">The maximum number of tiles traversed.  Or negative for no limit.</param>
        public static IEnumerable<Position> BreadthFirst(Engine engine, Position position, int distance = -1, int size = -1)
        {
            // Reset ONE tile's pathIndex on the map to the minimum value to prevent integer rollover
            int index = pathCounter < 0 ? -pathCounter : pathCounter;
            engine.map.tiles[index % engine.map.width, (index / engine.map.width)%engine.map.height].pathIndex = int.MinValue;

            int localPathCounter = pathCounter++;
            LinkedList<Tile> perimeter = new LinkedList<Tile>();
            perimeter.AddLast(engine.map.GetTileNearestTo(position));
            perimeter.Last.Value.pathDistance = 0;
            while (size != 0 && perimeter.Count > 0)
            {
                Tile top = perimeter.First.Value;
                top.pathIndex = localPathCounter;
                perimeter.RemoveFirst();
                if (distance >= 0 && top.pathDistance > distance)
                {
                    yield break;
                }
                yield return top.position;

                foreach (var neighbor in top.neighbors)
                {
                    if (neighbor.pathIndex < localPathCounter)
                    {
                        perimeter.AddLast(neighbor);
                        neighbor.pathIndex = localPathCounter;
                        neighbor.pathDistance = top.pathDistance + 1;
                    }
                }
                size -= 1;
            }
            // This is not the place for cleanup code
        }
示例#2
0
        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;
        }
示例#3
0
        public Tile AddTile(TileType tileType, Position position)
        {
            if (!map.Inside(position)) return null;

            var newTile = new Tile(GetNextId(), position, tileType);
            map.SetTileAt(position, newTile);
            return newTile;
        }
        public bool Equals(Position obj)
        {
            // If parameter is null return false.
            if (obj == null)
            {
                return false;
            }

            return x == obj.x && y == obj.y;
        }
示例#5
0
        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 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
        }
示例#7
0
        public Unit(int id, Engine engine, UnitType unitType, Position position, Player owner)
        {
            this.id = id;
            this.engine = engine;
            this.type = unitType;
            this.position = position;
            this.previousPosition = position;
            this.nextMove = -1;
            this.owner = owner;

            health = type.maxHealth;
            status = Status.Idle;
            orders = new List<Order>();
            modifiers = new List<UnitModifier>();

            animationStartTick = 0;
            direction = 0;

            currentPath = null;
            currentTargetPosition = null;
        }
示例#8
0
 public bool CanMove(Position targetPosition)
 {
     if (CanMove() && engine.map.Inside(targetPosition))
     {
         var targetUnit = engine.GetUnitAt(targetPosition);
         if (targetUnit != null)
         {
             return targetUnit.owner == owner && targetUnit.CanMove() && targetUnit.orders.Count == 0;
         }
         return true;
     }
     return false;
 }
 // Private methods
 private bool Inside(Position position)
 {
     return position.x >= 0 && position.y >= 0 && position.x < width && position.y < height;
 }
示例#10
0
 private bool Inside(Position position)
 {
     return position.x >= topLeft.x && position.y >= topLeft.y &&
            position.x <= bottomRight.x && position.y <= bottomRight.y;
 }
示例#11
0
 public int Distance(Position other)
 {
     return Math.Abs(other.y - y) + Math.Abs(other.x - x);
 }
示例#12
0
 private void MoveTowards(Position targetPosition)
 {
     if (currentPath == null || currentPath.Count == 0 ||
         !targetPosition.Equals(currentTargetPosition) || !CanMove(currentPath.First()) ||
         (position.Distance(targetPosition) % 11 == 0)) // Every 11 steps make sure that a new best path hasn't magically appeared
     {
         // Try to create a path if the current one is invalid
         currentPath = Pathfinder.FindPath(engine, this, engine.map.GetTileAt(position), engine.map.GetTileAt(targetPosition));
         currentTargetPosition = targetPosition;
         // Remove the first element because we are already there
         if (currentPath != null)
             currentPath.RemoveAt(0);
     }
     if (currentPath != null && currentPath.Count > 0 && currentTargetPosition.Equals(targetPosition) && CanMove(currentPath.First()))
     {
         Position nextStep = currentPath.First();
         currentPath.RemoveAt(0);
         TryToMove(nextStep);
     }
     else
     {
         status = Status.Idle;
         // Retry after moveRetryCooldown ticks
         engine.ScheduleUpdate(moveRetryCooldown, this);
     }
 }
示例#13
0
        // 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);
        }
示例#14
0
 public Unit GetUnitAt(Position position)
 {
     return map.Inside(position) ? unitGrid[position.x, position.y] : null;
 }
 public static Position FindNextStep( Engine engine, Unit unit, Position start, Position end)
 {
     return FindNextStep(engine, unit, engine.map.GetTileAt(start), engine.map.GetTileAt(end));
 }
示例#16
0
            public Chunk(Position position, int width, int height)
            {
                topLeft = position;
                bottomRight = topLeft + new Position(width - 1, height - 1);

                units = new HashSet<Unit>();
                neighbors = new List<Chunk>();
            }
示例#17
0
        public void UnitGroupCommand()
        {
            MouseState mouse = Mouse.GetState();
            KeyboardState keys = Keyboard.GetState();

            Vector2 mouseTile = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);

            mouseTile.X = m.X / (map.GetPxSizeMod()) + map.GetTileIndexX();
            mouseTile.Y = m.Y / (map.GetPxSizeMod()) + map.GetTileIndexY();

            Position mouseGameTilePosition = new Position((int)mouseTile.X, (int)mouseTile.Y);

            Unit clickedUnit = engine.GetUnitAt(mouseGameTilePosition);
            var enumerator = Pathfinder.BreadthFirst(engine, mouseGameTilePosition).GetEnumerator();
            enumerator.MoveNext();
            foreach (Unit unit in selectedUnits)
            {
                if (lastButtonPressed.Equals("None"))
                {
                    // Hold shift to append orders
                    if (keys.IsKeyUp(Keys.LeftShift) && keys.IsKeyUp(Keys.RightShift))
                    {
                        unit.orders.Clear();
                    }

                    // Click on same unit to produce units
                    if (clickedUnit == unit)
                    {
                        if (unit.CanProduce())
                        {
                            engine.OrderProduce(unit, engine.unitTypes[1]);
                        }
                        break;
                    }
                    // Click on other units to attack them
                    else if (clickedUnit != null) // TODO: make it so you don't attack your buddies
                    {
                        if (selectedUnits.Contains(clickedUnit)) //this check makes it so that you can produce without have the other selected units attack
                        {
                            continue;
                        }
                        if (unit.CanAttack())
                        {
                            engine.OrderAttack(unit, clickedUnit);
                        }
                    }
                    else if (unit.CanMove()) // Move units or gather
                    {
                        // Click on a resource node to gather
                        var resource = engine.map.tiles[enumerator.Current.x, enumerator.Current.y].tileType.resourceType;
                        if (resource != TileType.ResourceType.None)
                        {
                            engine.OrderGather(unit, enumerator.Current);
                            enumerator.MoveNext();
                            continue;
                        }

                        // Click on an empty tile to move
                        while (engine.GetUnitAt(enumerator.Current) != null)
                        {
                            enumerator.MoveNext();
                        }
                        engine.OrderMove(unit, enumerator.Current);
                        enumerator.MoveNext();
                    }
                }
                else
                {
                    unit.orders.Clear();
                    switch (lastButtonPressed)
                    {
                        case "Build Town":
                            foreach (Unit u in selectedUnits)
                            {
                                if (u.CanBuild())
                                {
                                    engine.OrderProduce(u, engine.unitTypes[3], mouseGameTilePosition);
                                }
                            }
                            break;
                        case "Build Mine":
                            foreach (Unit u in selectedUnits)
                            {
                                if (u.CanBuild())
                                {
                                    engine.OrderProduce(u, engine.unitTypes[4], mouseGameTilePosition);
                                }
                            }
                            break;
                        case "Produce Knight":
                            foreach (Unit u in selectedUnits)
                            {
                                if (u.CanProduce())
                                {
                                    engine.OrderProduce(u, engine.unitTypes[0]);
                                }
                            }
                            break;
                        case "Produce Archer":
                            foreach (Unit u in selectedUnits)
                            {
                                if (u.CanProduce())
                                {
                                    engine.OrderProduce(u, engine.unitTypes[1]);
                                }
                            }
                            break;
                        case "Produce Peasant":
                            foreach (Unit u in selectedUnits)
                            {
                                if (u.CanProduce())
                                {
                                    engine.OrderProduce(u, engine.unitTypes[2]);
                                }
                            }
                            break;
                        case "Attack":
                            foreach (Unit u in selectedUnits)
                            {
                                if (u.CanProduce())
                                {
                                    engine.OrderProduce(u, engine.unitTypes[2]);
                                }
                            }
                            break;
                        case "Move":
                            foreach (Unit u in selectedUnits)
                            {
                                if (u.CanProduce())
                                {
                                    engine.OrderProduce(u, engine.unitTypes[2]);
                                }
                            }
                            break;
                        case "Gather":
                            foreach (Unit u in selectedUnits)
                            {
                                if (u.CanProduce())
                                {
                                    engine.OrderProduce(u, engine.unitTypes[2]);
                                }
                            }
                            break;
                        case "Stop":
                            foreach (Unit u in selectedUnits)
                            {
                                if (u.CanProduce())
                                {
                                    engine.OrderProduce(u, engine.unitTypes[2]);
                                }
                            }
                            ClearOrders();
                            break;
                        default:

                            break;
                    } //End switch
                    lastButtonPressed = "None";
                }
            }
            if (keys.IsKeyUp(Keys.LeftControl) && keys.IsKeyUp(Keys.RightControl))
            {
                lastButtonPressed = "None";
            }
        }
示例#18
0
 public void AddUnit(Unit unit)
 {
     var chunk = GetChunk(unit.position);
     if (chunk != null) chunk.AddUnit(unit);
     previousUnitPositions[unit] = new Position(unit.position);
 }
示例#19
0
 public int GetMoveCooldown(Position startPosition, Position endPosition)
 {
     // TODO: Account for tile effects, unit modifiers, etc.
     int nominalSpeed = (int)(engine.map.GetTileAt(endPosition).tileType.movementCost * 10.0 / type.movementSpeed);
     return nominalSpeed > 0 ? nominalSpeed : 1;
 }
示例#20
0
 public void OrderGather(Unit gatherer, Position target)
 {
     gatherer.orders.Add(Order.CreateGatherOrder(target));
     ScheduleUpdate(1, gatherer);
 }
示例#21
0
 // Private
 private int CalculateDirection(Position delta)
 {
     bool bottomRight = delta.x > -delta.y;
     bool topRight = delta.x > delta.y;
     if (bottomRight && topRight) return 0;
     if (bottomRight) return 1;
     if (!topRight) return 2;
     return 3;
     // return 1 - delta.x + (delta.y == -1 ? 2 : 0);
 }
示例#22
0
 public double EuclideanDistance(Position other)
 {
     return Math.Sqrt((other.y - y) * (other.y - y) + (other.x - x) * (other.x - x));
 }
示例#23
0
        private void TryToMove(Position targetPosition)
        {
            if (targetPosition != null)
            {
                status = Status.Moving;
                direction = CalculateDirection(targetPosition - position);
                engine.ScheduleUpdate(GetMoveCooldown(position, targetPosition), this);

                var blockingUnit = engine.GetUnitAt(targetPosition);
                if (blockingUnit != null)
                {
                    engine.SwapUnits(this, blockingUnit);
                }
                else
                {
                    engine.MoveUnit(this, targetPosition);
                }
            }
            else
            {
                status = Status.Idle;
                // Retry after moveRetryCooldown ticks
                engine.ScheduleUpdate(moveRetryCooldown, this);
            }
        }
示例#24
0
 private Chunk GetChunk(Position position)
 {
     if (Inside(position))
     {
         return chunks[position.x/chunkWidth, position.y/chunkHeight];
     }
     return null;
 }
示例#25
0
 public Position( Position p )
 {
     x = p.x;
     y = p.y;
 }
示例#26
0
 private void CacheRemoveUnitAt(Position position)
 {
     if (map.Inside(position))
     {
         unitGrid[position.x, position.y] = null;
     }
 }
示例#27
0
 public void OrderMove(Unit unit, Position targetPosition)
 {
     unit.orders.Add(Order.CreateMoveOrder(targetPosition));
     ScheduleUpdate(1, unit);
 }
示例#28
0
 public int GetDistanceFrom(Position position)
 {
     // Calculate point nearest to startPosition inside this chunk
     Position nearestPosition = new Position(Math.Max(topLeft.x, Math.Min(bottomRight.x, position.x)),
         Math.Max(topLeft.y, Math.Min(bottomRight.y, position.y)));
     // Return distance
     return nearestPosition.Distance(position);
 }
示例#29
0
 public int EuclideanDistanceSquared(Position other)
 {
     return (other.y - y)*(other.y - y) + (other.x - x)*(other.x - x);
 }
示例#30
0
 public void OrderProduce(Unit factory, UnitType unitType, Position targetPosition = null)
 {
     factory.orders.Add(Order.CreateProduceOrder(unitType, targetPosition));
     ScheduleUpdate(1, factory);
 }