public static void AIMovement(StateSpaceComponents spaceComponents, DungeonTile[,] dungeonGrid, Vector2 dungeonDimensions, DijkstraMapTile[,] mapToPlayer) { if (spaceComponents.PlayerComponent.PlayerTookTurn) { // Handle Combat ready AI entities foreach (Guid id in spaceComponents.Entities.Where(c => ((c.ComponentFlags & ComponentMasks.CombatReadyAI) == ComponentMasks.CombatReadyAI)).Select(c => c.Id)) { AIAlignment alignment = spaceComponents.AIAlignmentComponents[id]; AIState state = spaceComponents.AIStateComponents[id]; PositionComponent position = spaceComponents.PositionComponents[id]; switch(state.State) { case AIStates.STATE_ROAMING: position = AISystem.AIRoam(id, position, dungeonGrid, dungeonDimensions, spaceComponents.random); break; case AIStates.STATE_ATTACKING: position = AISystem.AIAttack(id, position, dungeonDimensions, mapToPlayer, spaceComponents.random); break; case AIStates.STATE_FLEEING: position = AISystem.AIFlee(id, position, dungeonDimensions, mapToPlayer, spaceComponents.random); break; } CollisionSystem.TryToMove(spaceComponents, dungeonGrid, position, id); } } }
public static void ShouldPlayerMapRecalc(StateSpaceComponents spaceComponents, DungeonTile[,] dungeonGrid, Vector2 dungeonDimensions, ref DijkstraMapTile[,] playerMap) { if(spaceComponents.PlayerComponent.PlayerTookTurn || spaceComponents.PlayerComponent.PlayerJustLoaded) { CreateDijkstraMapToPlayers(dungeonGrid, dungeonDimensions, spaceComponents, ref playerMap); } }
private static PositionComponent AIFlee(Guid entity, PositionComponent position, Vector2 dungeonDimensions, DijkstraMapTile[,] mapToPlayer, Random random) { int lowestGridTile = 1; List<Vector2> validSpots = new List<Vector2>(); for (int i = (int)position.Position.X - 1; i <= (int)position.Position.X + 1; i++) { for (int j = (int)position.Position.Y - 1; j <= (int)position.Position.Y + 1; j++) { if (i >= 0 && j >= 0 && i < (int)dungeonDimensions.X && j < (int)dungeonDimensions.Y) { if (mapToPlayer[i, j].Weight < DevConstants.Grid.WallWeight) { lowestGridTile = (mapToPlayer[i, j].Weight * -1 < lowestGridTile * -1) ? mapToPlayer[i, j].Weight : lowestGridTile; } } } } for (int i = (int)position.Position.X - 1; i <= (int)position.Position.X + 1; i++) { for (int j = (int)position.Position.Y - 1; j <= (int)position.Position.Y + 1; j++) { if (i >= 0 && j >= 0 && i < (int)dungeonDimensions.X && j < (int)dungeonDimensions.Y && mapToPlayer[i, j].Weight == lowestGridTile) { validSpots.Add(new Vector2(i, j)); } } } return new PositionComponent() { Position = validSpots[random.Next(0, validSpots.Count)] }; }
public static void DrawTiles(Camera camera, SpriteBatch spriteBatch, DungeonTile[,] dungeonGrid, Vector2 dungeonDimensions, int cellSize, Texture2D spriteSheet, DungeonColorInfo colorInfo, DijkstraMapTile[,] mapToPlayer, SpriteFont font, StateSpaceComponents spaceComponents) { Entity player = spaceComponents.Entities.Where(c => (c.ComponentFlags & ComponentMasks.Player) == ComponentMasks.Player).FirstOrDefault(); bool inWater = false; bool inFire = false; if (player != null) { Vector2 playerPos = spaceComponents.PositionComponents[spaceComponents.Entities.Where(c => (c.ComponentFlags & ComponentMasks.Player) == ComponentMasks.Player).First().Id].Position; inWater = dungeonGrid[(int)playerPos.X, (int)playerPos.Y].Type == TileType.TILE_WATER; inFire = dungeonGrid[(int)playerPos.X, (int)playerPos.Y].Type == TileType.TILE_FIRE || (player.ComponentFlags & ComponentMasks.BurningStatus) == ComponentMasks.BurningStatus; } Matrix cameraMatrix = camera.GetMatrix(); Vector2 origin = new Vector2(DevConstants.Grid.TileBorderSize, DevConstants.Grid.TileBorderSize); for (int i = 0; i < (int)dungeonDimensions.X; i++) { for (int j = 0; j < (int)dungeonDimensions.Y; j++) { bool tintFire = inFire || dungeonGrid[i, j].FireIllumination; Vector2 tile = new Vector2((int)i * cellSize, (int)j * cellSize); Rectangle floor = new Rectangle(0 * cellSize, 0 * cellSize, cellSize, cellSize); //Need to be moved eventually Rectangle wall = new Rectangle(0 * cellSize, 0 * cellSize, cellSize, cellSize); //Need to be moved eventually Vector2 bottomRight = Vector2.Transform(new Vector2((i * cellSize) + cellSize, (j * cellSize) + cellSize), cameraMatrix); Vector2 topLeft = Vector2.Transform(new Vector2(i * cellSize, j * cellSize), cameraMatrix); Rectangle cameraBounds = new Rectangle((int)topLeft.X, (int)topLeft.Y, (int)bottomRight.X - (int)topLeft.X, (int)bottomRight.Y - (int)topLeft.Y); if (camera.IsInView(cameraMatrix, cameraBounds)) // check if in view { if (dungeonGrid[i, j].Found && !dungeonGrid[i, j].InRange) { Color colorToLerp = tintFire ? colorInfo.Fire : colorInfo.Water; //Default to water, if fire then change it. switch (dungeonGrid[i, j].Type) { case TileType.TILE_FLATTENEDGRASS: case TileType.TILE_FLOOR: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater || tintFire ? Color.Lerp(colorInfo.Floor, colorToLerp, .3f) : colorInfo.Floor) * .3f, origin: origin); break; case TileType.TILE_ROCK: case TileType.TILE_WALL: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater || tintFire ? Color.Lerp(colorInfo.Wall, colorToLerp, .3f) : colorInfo.Wall) * .3f, origin: origin); break; case TileType.TILE_TALLGRASS: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater || tintFire ? Color.Lerp(colorInfo.TallGrass, colorToLerp, .3f) : colorInfo.TallGrass) * .3f, origin: origin); break; case TileType.TILE_ASH: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater || tintFire ? Color.Lerp(colorInfo.Ash, colorToLerp, .3f) : colorInfo.Ash) * .3f, origin: origin); break; case TileType.TILE_WATER: spriteBatch.Draw(spriteSheet, position: tile, color: (tintFire ? Color.Lerp(colorInfo.Water, colorToLerp, .3f) : colorInfo.Water) * .3f, origin: origin); break; case TileType.TILE_FIRE: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater ? Color.Lerp(colorInfo.Fire, colorToLerp, .3f) : colorInfo.Fire) * .3f, origin: origin); break; } if (!string.IsNullOrEmpty(dungeonGrid[i, j].Symbol)) { Vector2 size = font.MeasureString(dungeonGrid[i, j].Symbol); spriteBatch.DrawString(font, dungeonGrid[i, j].Symbol, new Vector2(i * DevConstants.Grid.CellSize + (int)(DevConstants.Grid.CellSize / 2), (j * DevConstants.Grid.CellSize + (int)(DevConstants.Grid.CellSize / 2))), dungeonGrid[i, j].SymbolColor * .5f, 0f, new Vector2((int)(size.X / 2), (int)(size.Y / 2)), 1f, SpriteEffects.None, 0f); } } else if (dungeonGrid[i, j].InRange && !dungeonGrid[i, j].NewlyFound) { int weight = mapToPlayer[i, j].Weight; double opacity = 1 - (.035 * weight); opacity = (opacity < .4) ? .4 : opacity; opacity = dungeonGrid[i, j].FireIllumination ? .85f : opacity; bool isWall = false; Color colorToLerp = tintFire ? colorInfo.FireInRange : colorInfo.WaterInRange; //Default to water, if fire then change it. switch (dungeonGrid[i, j].Type) { case TileType.TILE_FLATTENEDGRASS: case TileType.TILE_FLOOR: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater || tintFire ? Color.Lerp(colorInfo.FloorInRange, colorToLerp, .55f) : colorInfo.FloorInRange) * (float)opacity, origin: origin); break; case TileType.TILE_ROCK: case TileType.TILE_WALL: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater || tintFire ? Color.Lerp(colorInfo.WallInRange, colorToLerp, .55f) : colorInfo.WallInRange) * .85f, origin: origin); isWall = true; break; case TileType.TILE_TALLGRASS: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater || tintFire ? Color.Lerp(colorInfo.TallGrassInRange, colorToLerp, .55f) : colorInfo.TallGrassInRange) * (float)opacity, origin: origin); break; case TileType.TILE_WATER: spriteBatch.Draw(spriteSheet, position: tile, color: (tintFire ? Color.Lerp(colorInfo.WaterInRange, colorToLerp, .55f) : colorInfo.WaterInRange) * (float)opacity, origin: origin); break; case TileType.TILE_ASH: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater || tintFire ? Color.Lerp(colorInfo.AshInRange, colorToLerp, .55f) : colorInfo.AshInRange) * (float)opacity, origin: origin); break; case TileType.TILE_FIRE: opacity = 0f + (.1f * dungeonGrid[i, j].TurnsToBurn); opacity = (opacity > 1f) ? 1f : opacity; opacity = (opacity < .3f) ? .3f : opacity; spriteBatch.Draw(spriteSheet, position: tile, color: (inWater ? Color.Lerp(colorInfo.FireInRange, colorToLerp, .55f) : colorInfo.FireInRange) * (float)opacity, origin: origin); break; } if (!isWall) { if (!string.IsNullOrEmpty(dungeonGrid[i, j].Symbol)) { Vector2 size = font.MeasureString(dungeonGrid[i, j].Symbol); spriteBatch.DrawString(font, dungeonGrid[i, j].Symbol, new Vector2(i * DevConstants.Grid.CellSize + (int)(DevConstants.Grid.CellSize / 2), (j * DevConstants.Grid.CellSize + (int)(DevConstants.Grid.CellSize / 2))), dungeonGrid[i, j].SymbolColor * (float)opacity, 0f, new Vector2((int)(size.X / 2), (int)(size.Y / 2)), 1f, SpriteEffects.None, 0f); } } else { if (!string.IsNullOrEmpty(dungeonGrid[i, j].Symbol)) { Vector2 size = font.MeasureString(dungeonGrid[i, j].Symbol); spriteBatch.DrawString(font, dungeonGrid[i, j].Symbol, new Vector2(i * DevConstants.Grid.CellSize + (int)(DevConstants.Grid.CellSize / 2), (j * DevConstants.Grid.CellSize + (int)(DevConstants.Grid.CellSize / 2))), dungeonGrid[i, j].SymbolColor * .85f, 0f, new Vector2((int)(size.X / 2), (int)(size.Y / 2)), 1f, SpriteEffects.None, 0f); } } } else if (dungeonGrid[i, j].NewlyFound) { float opacity = dungeonGrid[i, j].Opacity; Color colorToLerp = tintFire ? colorInfo.FireInRange : colorInfo.WaterInRange; //Default to water, if fire then change it. switch (dungeonGrid[i, j].Type) { case TileType.TILE_FLATTENEDGRASS: case TileType.TILE_FLOOR: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater || tintFire ? Color.Lerp(colorInfo.FloorInRange, colorToLerp, .55f) : colorInfo.FloorInRange) * opacity, origin: origin); break; case TileType.TILE_ROCK: case TileType.TILE_WALL: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater || tintFire ? Color.Lerp(colorInfo.WallInRange, colorToLerp, .55f) : colorInfo.WallInRange) * opacity, origin: origin); break; case TileType.TILE_TALLGRASS: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater || tintFire ? Color.Lerp(colorInfo.TallGrassInRange, colorToLerp, .55f) : colorInfo.TallGrassInRange) * opacity, origin: origin); break; case TileType.TILE_ASH: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater || tintFire ? Color.Lerp(colorInfo.AshInRange, colorToLerp, .55f) : colorInfo.AshInRange) * opacity, origin: origin); break; case TileType.TILE_WATER: spriteBatch.Draw(spriteSheet, position: tile, color: (tintFire ? Color.Lerp(colorInfo.WaterInRange, colorToLerp, .55f) : colorInfo.WaterInRange) * opacity, origin: origin); break; case TileType.TILE_FIRE: spriteBatch.Draw(spriteSheet, position: tile, color: (inWater ? Color.Lerp(colorInfo.FireInRange, colorToLerp, .55f) : colorInfo.FireInRange), origin: origin); break; } if (!string.IsNullOrEmpty(dungeonGrid[i, j].Symbol)) { Vector2 size = font.MeasureString(dungeonGrid[i, j].Symbol); spriteBatch.DrawString(font, dungeonGrid[i, j].Symbol, new Vector2(i * DevConstants.Grid.CellSize + (int)(DevConstants.Grid.CellSize / 2), (j * DevConstants.Grid.CellSize + (int)(DevConstants.Grid.CellSize / 2))), dungeonGrid[i, j].SymbolColor * opacity, 0f, new Vector2((int)(size.X / 2), (int)(size.Y / 2)), 1f, SpriteEffects.None, 0f); } if (dungeonGrid[i, j].Opacity > .5) { dungeonGrid[i, j].NewlyFound = false; dungeonGrid[i, j].Found = true; } } } } } }
private static void CreateDijkstraMapToPlayers(DungeonTile[,] dungeonGrid, Vector2 dungeonDimensions, StateSpaceComponents spaceComponents, ref DijkstraMapTile[,] dijkstraMap) { List<Vector2> targets = new List<Vector2>(); //targets are any entities with friendly AI and players foreach(Guid id in spaceComponents.Entities.Where(x => (x.ComponentFlags & Component.COMPONENT_PLAYER) == Component.COMPONENT_PLAYER).Select(x => x.Id)) { targets.Add(spaceComponents.PositionComponents[id].Position); } foreach (Guid id in spaceComponents.Entities.Where(x => (x.ComponentFlags & Component.COMPONENT_AI_ALIGNMENT) == Component.COMPONENT_AI_ALIGNMENT).Select(x => x.Id)) { if(spaceComponents.AIAlignmentComponents[id].Alignment == AIAlignments.ALIGNMENT_FRIENDLY) { targets.Add(spaceComponents.PositionComponents[id].Position); } } //Set up map for (int i = 0; i < dungeonDimensions.X; i++) { for (int j = 0; j < dungeonDimensions.Y; j++) { if (dungeonGrid[i, j].Occupiable) { dijkstraMap[i, j].Weight = DevConstants.Grid.WallWeight -1; } else { dijkstraMap[i, j].Weight = DevConstants.Grid.WallWeight; } if (targets.Contains(new Vector2(i, j))) { dijkstraMap[i, j].Weight = 0; } dijkstraMap[i, j].Checked = false; } } Queue<Vector2> floodQueue = new Queue<Vector2>(); foreach(Vector2 item in targets) { floodQueue.Enqueue(item); } while (floodQueue.Count > 0) { Vector2 pos = floodQueue.Dequeue(); int x = (int)pos.X; int y = (int)pos.Y; int lowestNeighbor = DevConstants.Grid.WallWeight; HashSet<Vector2> toAdd = new HashSet<Vector2>(); for (int k = x - 1; k <= x + 1; k++) { for (int l = y - 1; l <= y + 1; l++) { if (l >= 0 && k >= 0 && l < (int)dungeonDimensions.Y && k < (int)dungeonDimensions.X && dijkstraMap[(int)pos.X, (int)pos.Y].Weight != DevConstants.Grid.WallWeight) { lowestNeighbor = (lowestNeighbor < dijkstraMap[k, l].Weight) ? lowestNeighbor : dijkstraMap[k, l].Weight; if(!dijkstraMap[k,l].Checked) { dijkstraMap[k, l].Checked = true; floodQueue.Enqueue(new Vector2(k, l)); } } } } if (dijkstraMap[x,y].Weight >= lowestNeighbor + 2) { dijkstraMap[x,y].Weight = lowestNeighbor + 1; } } }