private Vector2 CalculateExit(Vector2 direction, Vector2 center, Collision.Side s, Vector2 middleOfSide) { Vector2 exitPoint = middleOfSide - center; switch (s) { case Collision.Side.Top: case Collision.Side.Bottom: exitPoint.X = direction.X * (exitPoint.Y / direction.Y); break; case Collision.Side.Left: case Collision.Side.Right: exitPoint.Y = direction.Y * (exitPoint.X / direction.X); break; } return(exitPoint); }
public static Collision.Side Opposite(this Collision.Side side) { switch (side) { case Collision.Side.Bottom: return(Collision.Side.Top); case Collision.Side.Top: return(Collision.Side.Bottom); case Collision.Side.Left: return(Collision.Side.Right); case Collision.Side.Right: return(Collision.Side.Left); default: return(default(Collision.Side)); } }
/// <summary> /// </summary> /// <param name="rect"></param> /// <param name="side"></param> /// <returns>The middle of the side of the rectangle specified.</returns> public static Vector2 GetMiddleOfSide(this Rectangle rect, Collision.Side side) { switch (side) { case Collision.Side.Top: return(new Vector2(rect.Center.X, rect.Top)); case Collision.Side.Bottom: return(new Vector2(rect.Center.X, rect.Bottom - 1)); case Collision.Side.Left: return(new Vector2(rect.Left, rect.Center.Y)); case Collision.Side.Right: return(new Vector2(rect.Right - 1, rect.Center.Y)); default: return(Vector2.Zero); } }
private Collision.Side CalculateExitSide(Room r, Vector2 relVector) { Vector2 center = r.BoundingBox.Center.ToVector2(); //Calculate angles of vector. double relAngle = Math.Atan2(relVector.Y, relVector.X); //Calculate the angles of the line Vector2[] cornerVectors = new Vector2[4]; cornerVectors[0] = new Vector2(r.BoundingBox.Left, r.BoundingBox.Top) - center; cornerVectors[1] = new Vector2(r.BoundingBox.Right, r.BoundingBox.Top) - center; cornerVectors[2] = new Vector2(r.BoundingBox.Right, r.BoundingBox.Bottom) - center; cornerVectors[3] = new Vector2(r.BoundingBox.Left, r.BoundingBox.Bottom) - center; //Use Math.Atan2 to convert vectors to angles. double[] cornerAngles = new double[4]; cornerAngles[0] = Math.Atan2(cornerVectors[0].Y, cornerVectors[0].X); cornerAngles[1] = Math.Atan2(cornerVectors[1].Y, cornerVectors[1].X); cornerAngles[2] = Math.Atan2(cornerVectors[2].Y, cornerVectors[2].X); cornerAngles[3] = Math.Atan2(cornerVectors[3].Y, cornerVectors[3].X); //Calculate Sides based on angle Collision.Side s = default(Collision.Side); if (relAngle >= cornerAngles[0] && relAngle < cornerAngles[1]) { s = Collision.Side.Top; } else if (relAngle >= cornerAngles[1] && relAngle < cornerAngles[2]) { s = Collision.Side.Right; } else if (relAngle >= cornerAngles[2] && relAngle < cornerAngles[3]) { s = Collision.Side.Bottom; } else if (relAngle >= cornerAngles[3] || relAngle < cornerAngles[0]) { s = Collision.Side.Left; } return(s); }
private TileField GenerateTiles(List <Room> rooms, List <Tuple <Room, Room> > hallwayPairs) { //Get the highest coordinates so we know the size of the TileField. int highestX = int.MinValue; int highestY = int.MinValue; foreach (Room r in rooms) { if (r.BoundingBox.Right > highestX) { highestX = r.BoundingBox.Right; } if (r.BoundingBox.Bottom > highestY) { highestY = r.BoundingBox.Bottom; } } //Make the tilefield and fill with default Tiles. TileField tf = new TileField(highestY + 1, highestX + 1, 0, "TileField"); Add(tf); for (int x = 0; x < tf.Columns; x++) { for (int y = 0; y < tf.Rows; y++) { tf.Add(new Tile(), x, y); } } List <Tuple <XNAPoint, XNAPoint> > hallways = new List <Tuple <XNAPoint, XNAPoint> >(); //Find good points for the hallways connect to. foreach (Tuple <Room, Room> pair in hallwayPairs) { Vector2 center1 = pair.Item1.BoundingBox.Center.ToVector2(); Vector2 center2 = pair.Item2.BoundingBox.Center.ToVector2(); //Vector from center of room1 to center of room2 and vice versa Vector2 v1 = center2 - center1; Vector2 v2 = center1 - center2; Collision.Side s1 = CalculateExitSide(pair.Item1, v1); Collision.Side s2 = CalculateExitSide(pair.Item2, v2); v1.Normalize(); v2.Normalize(); XNAPoint cRelExit1 = CalculateExit(v1, center1, s1, pair.Item1.BoundingBox.GetMiddleOfSide(s1)).ToPoint(); XNAPoint cRelExit2 = CalculateExit(v2, center2, s2, pair.Item2.BoundingBox.GetMiddleOfSide(s2)).ToPoint(); XNAPoint absExit1 = cRelExit1 + pair.Item1.BoundingBox.Center; XNAPoint absExit2 = cRelExit2 + pair.Item2.BoundingBox.Center; hallways.Add(new Tuple <XNAPoint, XNAPoint>(absExit1, absExit2)); } //for each room, add floor tiles to the tilefield. for (int i = 0; i < rooms.Count; i++) { Room r = rooms[i]; int width = r.BoundingBox.Width; int height = r.BoundingBox.Height; XNAPoint relCenter = r.BoundingBox.Center - r.BoundingBox.Location; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { Tile tile = LoadFloorTile(); if (x == relCenter.X && y == relCenter.Y) { tile.AddDebugTag("Room", "" + i); } tf.Add(tile, x + r.BoundingBox.X, y + r.BoundingBox.Y); } } } //Generate hallways foreach (Tuple <XNAPoint, XNAPoint> pair in hallways) { //Use the pathfinder to get a path from exitpoint to exitpoint. PathFinder pf = new PathFinder(tf); pf.EnableStraightLines(); List <Tile> path = pf.ShortestPath(tf[pair.Item1.X, pair.Item1.Y] as Tile, tf[pair.Item2.X, pair.Item2.Y] as Tile, tile => true); Tile t = tf[pair.Item1.X, pair.Item1.Y] as Tile; t.AddDebugTag("ExitConnectionPoint", pair.Item2.X + "," + pair.Item2.Y); path.Add(t); //Add a floor tile for every tile in the path. foreach (Tile tile in path) { Tile newTile = LoadFloorTile(); newTile.AddDebugTags(tile.DebugTags); tf.Add(newTile, tile.TilePosition.X, tile.TilePosition.Y); } } //Exchange all remaining background tiles for Wall tiles. for (int x = 0; x < tf.Columns; x++) { for (int y = 0; y < tf.Rows; y++) { Tile currentTile = tf[x, y] as Tile; Tile aboveTile = tf[x, y - 1] as Tile; if (currentTile != null && aboveTile != null && currentTile.TileType == TileType.Background) { Tile newTile = LoadWallTile(x, y); newTile.AddDebugTags(currentTile.DebugTags); tf.Add(newTile, x, y); } } } //Add starttiles for (int p = 0; p < 4; p++) { tf.Add(LoadStartTile(p + 1), rooms[0].Location.ToRoundedPoint().X + 1 + p % 2, rooms[0].Location.ToRoundedPoint().Y + 1 + p / 2); } //Generate EndTile List <Room> forEnd = new List <Room>(); List <Room> usedRooms = new List <Room>(); for (int a = 0; a < hallwayPairs.Count; a++) { if (!forEnd.Contains(hallwayPairs[a].Item1)) { forEnd.Add(hallwayPairs[a].Item1); usedRooms.Add(hallwayPairs[a].Item1); } if (!forEnd.Contains(hallwayPairs[a].Item2)) { forEnd.Add(hallwayPairs[a].Item2); usedRooms.Add(hallwayPairs[a].Item2); } } for (int a = 0; a < hallwayPairs.Count; a++) { if (hallwayPairs[a].Item1 == rooms[0] || hallwayPairs[a].Item2 == rooms[0]) { if (forEnd.Contains(hallwayPairs[a].Item1)) { forEnd.Remove(hallwayPairs[a].Item1); } if (forEnd.Contains(hallwayPairs[a].Item2)) { forEnd.Remove(hallwayPairs[a].Item2); } } } tf.Add(LoadEndTile(), forEnd[0].Location.ToRoundedPoint().X + 1, forEnd[0].Location.ToRoundedPoint().Y + 1); tf.Add(LoadChestTile(levelIndex), forEnd[0].Location.ToRoundedPoint().X + forEnd[0].Size.X - 2, forEnd[0].Location.ToRoundedPoint().Y + 1); //Door spawn for (int i = 0; i < usedRooms.Count; i++) { for (int x = rooms[i].Location.ToRoundedPoint().X; x < rooms[i].Location.ToRoundedPoint().X + rooms[i].Size.X; x++) { if (!tf.IsWall(x, rooms[i].Location.ToRoundedPoint().Y - 1)) { if (tf.IsWall(x + 1, rooms[i].Location.ToRoundedPoint().Y - 1) && tf.IsWall(x - 1, rooms[i].Location.ToRoundedPoint().Y - 1)) { tf.Add(LoadDoorTile(), x, rooms[i].Location.ToRoundedPoint().Y - 1); } } if (!tf.IsWall(x, rooms[i].Location.ToRoundedPoint().Y + rooms[i].Size.Y)) { if (tf.IsWall(x + 1, rooms[i].Location.ToRoundedPoint().Y + rooms[i].Size.Y) && tf.IsWall(x - 1, rooms[i].Location.ToRoundedPoint().Y + rooms[i].Size.Y)) { tf.Add(LoadDoorTile(), x, rooms[i].Location.ToRoundedPoint().Y + rooms[i].Size.Y); } } } } //Test chest spawn int chestAmount = Random.Next(1, 2); usedRooms.Remove(rooms[0]); for (int i = 0; i < chestAmount; i++) { int chestRoom = Random.Next(usedRooms.Count); usedRooms.Remove(rooms[chestRoom]); int xChest = rooms[chestRoom].Location.ToRoundedPoint().X + rooms[chestRoom].Size.X / 2; int yChest = rooms[chestRoom].Location.ToRoundedPoint().Y + rooms[chestRoom].Size.Y / 2; tf.Add(LoadChestTile(levelIndex), xChest, yChest); } //End test //Test enemy spawn int numberOfEnemys = 8; for (int n = 0; n < numberOfEnemys; n++) { Enemy enemy = new Enemy(0, Index, EnemyType.random, "Enemy"); List <GameObject> spawnLocations = tf.FindAll(obj => obj is Tile && (obj as Tile).Passable && !(obj as Tile).Blocked); Tile spawnLocation = spawnLocations[GameEnvironment.Random.Next(spawnLocations.Count)] as Tile; spawnLocation.PutOnTile(enemy); } //End test //Must be last statement, executed after the Tilefield is done. tf.InitSpriteSheetIndexation(); return(tf); }