/* * Populates the collision grid by bucketizing each unit on the map into a cell * around which collisions will be processed */ public List<GameUnit>[,] ConstructCollisionGrid(List<GameUnit> units, Level level) { List<GameUnit>[,] grid = new List<GameUnit>[ (int)level.Width / CELL_SIZE, (int)level.Height / CELL_SIZE]; foreach (GameUnit unit in units) { int x_index = (int)MathHelper.Clamp((unit.Position.X / CELL_SIZE), 0, grid.GetLength(1)-1); int y_index = (int)MathHelper.Clamp((unit.Position.Y / CELL_SIZE), 0, grid.GetLength(0)-1); if (grid[y_index, x_index] == null) { grid[y_index, x_index] = new List<GameUnit>(); } grid[y_index, x_index].Add(unit); } return grid; }
private void UpdateUnit(GameUnit unit, Level level) { if (!unit.Exists) return; // Infection vitality update if (unit.Lost) { unit.InfectionVitality -= INFECTION_RECOVER_SPEED; unit.InfectionVitality = MathHelper.Clamp( unit.InfectionVitality, 0, unit.max_infection_vitality); } else { unit.InfectionVitality += INFECTION_RECOVER_SPEED; unit.InfectionVitality = MathHelper.Clamp( unit.InfectionVitality, 0, unit.max_infection_vitality); } // If infection vitality is 0, convert the unit, or defeat the boss if (unit.InfectionVitality == 0) { if (unit.Type == UnitType.BOSS) { level.BossesDefeated++; unit.Exists = false; } else { ConvertedUnits.Add(unit); } } // Attack cooldown unit.AttackCoolDown = (int)MathHelper.Clamp( --unit.AttackCoolDown, 0, ATTACK_COOLDOWN); // Apply ally attrition if they are outside of range if (unit.Faction == UnitFaction.ALLY && Player != null && !unit.inRange(Player, ALLY_FOLLOW_RANGE)) { unit.Health -= ALLY_ATTRITION; } // Check health if (unit.Health <= 0) { DeadUnits.Add(unit); } }
/* * Calculates and processes all collisions that occur, * using the collision cell optimization structure */ public void Update(List<GameUnit> units, Level level) { cellGrid = ConstructCollisionGrid(units, level); for (int ii = 0; ii < cellGrid.GetLength(0); ii++) { for (int jj = 0; jj < cellGrid.GetLength(1); jj++) { if (cellGrid[ii, jj] != null) { ProcessCollisions(jj, ii, level.Map); } } } }
/* * Update all units */ public void Update(Level level, InputController input_controller) { ConstructCombatGrid(level); //Pathfinder.findPath(level.Map, Player.Front, Player.Front, PLAYER_PATHFIND_FIELD_SIZE, true); //playerLocationField = Pathfinder.pointLocMap; //lostUnits.Clear(); // Handle player logic bool playerFrontBlocked = false; if (Player != null) { playerFrontBlocked = level.Map.rayCastHasObstacle(Player.Position, Player.Front, Map.TILE_SIZE / 3); CheckPlayerInput(input_controller); moveUnit(Player); UpdatePlayer(); } // Handle lost units /* if (lostUnits.Count != 0) { GameUnit captain = lostUnits.First(); captain.Target = Player.Position; //findTarget(captain, Player.Position, level.Map, 100); foreach (GameUnit unit in lostUnits) { if (unit != captain) { unit.Lost = true; unit.Target = captain.Position; unit.NextMove = unit.Target; } } }*/ // Execute moves and actions foreach (GameUnit unit in Units) { setNextMove(unit, level, playerFrontBlocked); // Set next moves setVelocity(unit); moveUnit(unit); ProcessCombat(unit); UpdateUnit(unit, level); } // Convert units foreach (GameUnit unit in ConvertedUnits) { Convert(unit); } ConvertedUnits.Clear(); // Dispose of dead units foreach (GameUnit unit in DeadUnits) { if (unit.Type == UnitType.PLAYER) { Player.Exists = false; Player = null; } else Units.Remove(unit); } DeadUnits.Clear(); }
/* * Construct the combat grid by placing units in cells where * they are in range of other cells */ private void ConstructCombatGrid(Level level) { combatRangeGrid = new List<GameUnit>[ level.Height / COMBAT_GRID_CELL_SIZE, level.Width / COMBAT_GRID_CELL_SIZE]; foreach (GameUnit unit in Units) { int x_index = (int)MathHelper.Clamp((unit.Position.X / COMBAT_GRID_CELL_SIZE), 0, combatRangeGrid.GetLength(1) - 1); int y_index = (int)MathHelper.Clamp((unit.Position.Y / COMBAT_GRID_CELL_SIZE), 0, combatRangeGrid.GetLength(0) - 1); if (combatRangeGrid[y_index, x_index] == null) { combatRangeGrid[y_index, x_index] = new List<GameUnit>(); } combatRangeGrid[y_index, x_index].Add(unit); } if (Player != null) { int x_indexp = (int)MathHelper.Clamp((Player.Position.X / COMBAT_GRID_CELL_SIZE), 0, combatRangeGrid.GetLength(1) - 1); int y_indexp = (int)MathHelper.Clamp((Player.Position.Y / COMBAT_GRID_CELL_SIZE), 0, combatRangeGrid.GetLength(0) - 1); if (combatRangeGrid[y_indexp, x_indexp] == null) { combatRangeGrid[y_indexp, x_indexp] = new List<GameUnit>(); } combatRangeGrid[y_indexp, x_indexp].Add(Player); } }
/* * Determine the next move for this unit with * targeting specific to each unit type AI */ public void setNextMove(GameUnit unit, Level level, bool playerFrontBlocked) { if (unit.Position.X < 0 || unit.Position.Y < 0) return; Vector2 prev_move = unit.NextMove; UnitFaction faction = unit.Faction; // Unit faction, only called once // If an ally unit is lost, do this if (faction == UnitFaction.ALLY && unit.Lost) { if (rand.NextDouble() < 0.01 && Player != null) { unit.Target = Player.Position; findTarget(unit, Player.Position, level.Map, MAX_ASTAR_DIST); } else if(rand.NextDouble() < 0.05) { unit.Target = unit.Position + new Vector2(rand.Next(600) - 300, rand.Next(600) - 300); unit.NextMove = unit.Target; } return; } // Select target bool random_walk = false; switch (unit.Type) { case UnitType.TANK: // tank AI if (Player != null && Player.Exists && faction == UnitFaction.ENEMY && Player.inRange(unit, ENEMY_CHASE_RANGE)) { unit.Target = Player.Position; } else if (rand.NextDouble() < 0.05) { // Random walk random_walk = true; unit.Target = unit.Position + new Vector2(rand.Next(600)-300, rand.Next(600)-300); } if (faction == UnitFaction.ALLY && Player != null) { if (playerFrontBlocked) { unit.Target = Player.Position; } else { unit.Target = Player.Front; } } // Chase the closest enemy in range GameUnit closest = findClosestEnemyInRange(unit, ATTACK_LOCK_RANGE); if (closest != null) { unit.Target = closest.Position; unit.Attacking = closest; } if(faction == UnitFaction.ALLY && Player != null && !Player.inRange(unit, ALLY_FOLLOW_RANGE)) { unit.Target = Player.Position; } break; case UnitType.RANGED: // ranged AI break; case UnitType.FLYING: // flying AI break; default: // Player case, do nothing break; } unit.NextMove = unit.Target; if (unit.HasTarget()) { /* // If the target is the player, use the player location map if (unit.Target.Equals(Player.Position) && Math.Abs(unit.TilePosition.X - Player.TilePosition.X) + Math.Abs(unit.TilePosition.Y - Player.TilePosition.Y) < PLAYER_PATHFIND_FIELD_SIZE) { Vector2 moveToPlayerTile = findMoveToPlayer(unit, level.Map); unit.NextMove = new Vector2(moveToPlayerTile.X * Map.TILE_SIZE, moveToPlayerTile.Y * Map.TILE_SIZE); }*/ // Pathfind to target if necessary if (!random_walk && level.Map.rayCastHasObstacle(unit.Position, unit.Target, unit.Size / 2)) { if (rand.NextDouble() < 0.1) { findTarget(unit, unit.Target, level.Map, MAX_ASTAR_DIST); } else { unit.NextMove = prev_move; } } } }
/* * Initialize units for the specified level */ public void SetLevel(Level level) { Reset(); foreach (GameUnit boss in level.Bosses) { Units.Add(boss); } Player.Position = level.PlayerStart * Map.TILE_SIZE; Player.Health = Player.max_health; Player.InfectionPoints = MAX_PLAYER_CONVERSION_POINTS; }
public Level loadLevel(int num) { //return levels[num]; // TODO Should all be loaded from file List<GameUnit> goals = new List<GameUnit>(); goals.Add(createUnit(UnitType.BOSS, UnitFaction.ENEMY, 1, new Vector2(800, 800), false)); goals.Add(createUnit(UnitType.BOSS, UnitFaction.ENEMY, 1, new Vector2(1000, 200), false)); Level level = new Level(2000, 2000, textures[BACKGROUND1], textures[WALL], goals); level.PlayerStart = new Vector2(2, 2); return level; }
/* * Calculates and processes all collisions that occur, * using the collision cell optimization structure */ public void Update(List<GameUnit> units, Player player, Level level, ItemController item_controller) { ConstructCollisionGrids(units, item_controller.Items, player, level); foreach (GameUnit unit in units) { ProcessCollisions(unit, level.Map); } if (player != null) { ProcessCollisions(player, level.Map); ProcessItems(player, item_controller); } }
/* * Populates the collision grid by bucketizing each unit on the map into a cell * around which collisions will be processed */ public void ConstructCollisionGrids(List<GameUnit> units, List<Item> items, Player player, Level level) { // Construct unit collision grid List<GameUnit>[,] grid = new List<GameUnit>[ (int)level.Width / CELL_SIZE, (int)level.Height / CELL_SIZE]; foreach (GameUnit unit in units) { int x_index = (int)MathHelper.Clamp((unit.Position.X / CELL_SIZE), 0, grid.GetLength(1)-1); int y_index = (int)MathHelper.Clamp((unit.Position.Y / CELL_SIZE), 0, grid.GetLength(0)-1); if (grid[y_index, x_index] == null) { grid[y_index, x_index] = new List<GameUnit>(); } grid[y_index, x_index].Add(unit); } if (player != null) { int x_indexp = (int)MathHelper.Clamp((player.Position.X / CELL_SIZE), 0, grid.GetLength(1) - 1); int y_indexp = (int)MathHelper.Clamp((player.Position.Y / CELL_SIZE), 0, grid.GetLength(0) - 1); if (grid[y_indexp, x_indexp] == null) { grid[y_indexp, x_indexp] = new List<GameUnit>(); } grid[y_indexp, x_indexp].Add(player); cellGrid = grid; } // Contruct item collision grid itemGrid = new List<Item>[(int)level.Width / CELL_SIZE, (int)level.Height / CELL_SIZE]; foreach (Item item in items) { int x_index = (int)MathHelper.Clamp((item.Position.X / CELL_SIZE), 0, grid.GetLength(1) - 1); int y_index = (int)MathHelper.Clamp((item.Position.Y / CELL_SIZE), 0, grid.GetLength(0) - 1); if (itemGrid[y_index, x_index] == null) { itemGrid[y_index, x_index] = new List<Item>(); } itemGrid[y_index, x_index].Add(item); } }