/// <summary> /// Check if a position is inside a room and not a wall or invalid /// </summary> /// <param name="gx"></param> /// <param name="gy"></param> /// <param name=""></param> /// <returns></returns> public bool IsInsideRoom(int gx, int gy, GenRoom room = null) { if (room == null) { GenTile tile = GetTile(gx, gy); if (tile != null) { return(tile.NonTypes(GenDetail.DetailType.Wall)); } return(false); } else { GenTile tile = room.GetAtWorldspaceG(gx, gy); if (!(room.Inner.MinX <= gx && room.Inner.MaxX >= gx && room.Inner.MinY <= gy && room.Inner.MaxY >= gy)) { return(false); } if (tile != null) { return(tile.NonTypes(GenDetail.DetailType.Wall)); } return(false); } }
private GenTile[,] GeneticCopy(int numCopies) { CalculateDepthForEachTile(); int totalNumEle = (int)Mathf.Pow(gridAPI.GridSize(), 2); GenTile[,] strands = new GenTile[totalNumEle, numCopies]; Tile tempTile; for (int i = 0; i < totalNumEle; i++) { tempTile = gridAPI.ListEleByIndex(i); for (int j = 0; j < numCopies; j++) { strands[i, j] = new GenTile(); strands[i, j].numMoves = tempTile.GetNumMoves(); strands[i, j].tileDepth = tempTile.GetTileDepth(); strands[i, j].x = tempTile.x; strands[i, j].y = tempTile.y; strands[i, j].index = i; } } return(strands); }
public void AddDetails(int gx, int gy, GenTile tile) { GenTile t = GetAtWorldspaceG(gx, gy); if (t != null && tile != null) { t.Details.AddRange(tile.Details); } }
public void AddDetail(int gx, int gy, GenDetail detail) { GenTile t = GetAtWorldspaceG(gx, gy); if (t != null) { t.Details.Add(detail); } }
public static GenTile Copy(GenTile tile) { GenTile newTile = new GenTile(); foreach (var detail in tile.Details) { newTile.Details.Add(detail.Clone()); } return(newTile); }
public void SetTileAtG(int gx, int gy, GenTile tile) { if (Data.Exists(gx - PosX, gy - PosY)) { if (tile != null) { Data[gx - PosX, gy - PosY] = tile; } } }
public GenTile[,] ResizeTiles(GenTile[,] original, ref int gx, ref int gy) { GenTile[,] empty = new GenTile[WidthT, HeightT]; empty.Place(gx - MinX, gy - MinY, original); gx = MinX; gy = MinY; return(empty); }
public static GenTile[,] Fill(int width, int height, GenTile tile) { GenTile[,] result = new GenTile[width, height]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { result[x, y] = GenTile.Copy(tile); } } return(result); }
public GenTile GetTile(int gx, int gy) { foreach (var item in Rooms) { GenTile tile = item.GetAtWorldspaceG(gx, gy); if (tile != null) { return(tile); } } return(null); }
public GenTile[,] GetTiles(GenRect rect) { GenTile[,] tiles = new GenTile[rect.WidthT, rect.HeightT]; for (int x = 0; x < tiles.GetLength(0); x++) { for (int y = 0; y < tiles.GetLength(1); y++) { tiles[x, y] = GetTile(rect.MinX + x, rect.MinY + y); } } return(tiles); }
public static GenTile GetTileAtG(int gx, int gy, params GenRoom[] rooms) { for (int i = 0; i < rooms.Length; i++) { var room = rooms[i]; GenTile t = room.GetAtWorldspaceG(gx, gy); if (t != null) { return(t); } } return(null); }
public bool CanBeDoor(int gx, int gy, params GenDetail.DetailType[] checkFor) { if (checkFor.Length == 0) { checkFor = new GenDetail.DetailType[] { GenDetail.DetailType.Wall }; } bool horizontal = false; bool vertical = false; int walls = 0; GenTile r = GetTile(gx + 1, gy); if (r == null || r.AnyTypes(checkFor)) { walls++; } GenTile l = GetTile(gx - 1, gy); if (l == null || l.AnyTypes(checkFor)) { walls++; } if ((r == null || r.AnyTypes(checkFor)) && (l == null || l.AnyTypes(checkFor))) { horizontal = true; } GenTile t = GetTile(gx, gy - 1); if (t == null || t.AnyTypes(checkFor)) { walls++; } GenTile b = GetTile(gx, gy + 1); if (b == null || b.AnyTypes(checkFor)) { walls++; } if ((t == null || t.AnyTypes(checkFor)) && (b == null || b.AnyTypes(checkFor))) { vertical = true; } return(walls % 2 == 0 && (horizontal ^ vertical)); }
public List <GenRoom> GetOccupyingRooms(int gx, int gy) { List <GenRoom> tiles = new List <GenRoom>(); foreach (var room in Rooms) { GenTile tile = room.GetAtWorldspaceG(gx, gy); if (tile != null) { tiles.Add(room); } } return(tiles); }
public bool MakeRoom(int x, int y, int xlength, int ylength, Direction direction) { // define the dimensions of the room, it should be at least 4x4 tiles (2x2 for walking on, the rest is walls) int xlen = this.GetRand(4, xlength); int ylen = this.GetRand(4, ylength); // the tile type it's going to be filled with const GenTile Floor = GenTile.DirtFloor; const GenTile Wall = GenTile.DirtWall; // choose the way it's Vector2Intng at var points = GetRoomPoints(x, y, xlen, ylen, direction).ToArray(); // Check if there's enough space left for it if ( points.Any( s => s.y < 0 || s.y > this._ysize || s.x < 0 || s.x > this._xsize || this.GetCellTypeNoOffset(s.x, s.y) != GenTile.Unused)) { return(false); } _logger( string.Format( "Making room:int x={0}, int y={1}, int xlength={2}, int ylength={3}, int direction={4}", x, y, xlength, ylength, direction)); foreach (var p in points) { this.SetCell(p.x, p.y, IsWall(x, y, xlen, ylen, p.x, p.y, direction) ? Wall : Floor); } Vector2Int minPoint = points.Aggregate((previous, current) => previous.x + previous.y < current.x + current.y ? previous : current); Vector2Int maxPoint = points.Aggregate((previous, current) => previous.x + previous.y > current.x + current.y ? previous : current); BoundsInt roomBoundsAfterOffset = new BoundsInt { min = new Vector3Int(minPoint.x, minPoint.y, 0) + _offset, max = new Vector3Int(maxPoint.x + 1, maxPoint.y + 1, 1) + _offset }; Rooms.Add(roomBoundsAfterOffset); // yay, all done return(true); }
public List <GenTile> GetAllTiles(int gx, int gy) { List <GenTile> tiles = new List <GenTile>(); foreach (var room in Rooms) { GenTile tile = room.GetAtWorldspaceG(gx, gy); if (tile != null) { tiles.Add(tile); } } return(tiles); }
public static GenTile[,] GetCopy(this GenTile[,] target) { GenTile[,] result = new GenTile[target.GetLength(0), target.GetLength(1)]; for (int x = 0; x < target.GetLength(0); x++) { for (int y = 0; y < target.GetLength(1); y++) { if (target[x, y] != null) { result[x, y] = GenTile.Copy(target[x, y]); } } } return(result); }
public void FillFloor(char c = '.') { for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { GenTile t = GenTile.GetEmpty(); t.Details.Add(new GenDetail() { Char = c, Type = GenDetail.DetailType.Floor, }); Data[x, y] = t; } } }
/// <summary> /// checks if Position is in the corner (floor, not wall) /// </summary> public bool IsCornerG(int gx, int gy, params GenDetail.DetailType[] checkFor) { if (checkFor.Length == 0) { checkFor = new GenDetail.DetailType[] { GenDetail.DetailType.Wall }; } GenTile tile = GetTile(gx, gy); // if it is a wall we dont need to bother as it is never a corner if (tile == null || tile.AnyTypes(checkFor)) { return(false); } int horizontal = 0; int vertical = 0; GenTile r = GetTile(gx + 1, gy); if (r.AnyTypes(checkFor)) { horizontal++; } GenTile l = GetTile(gx - 1, gy); if (l.AnyTypes(checkFor)) { horizontal++; } GenTile t = GetTile(gx, gy - 1); if (t.AnyTypes(checkFor)) { vertical++; } GenTile b = GetTile(gx, gy + 1); if (b.AnyTypes(checkFor)) { vertical++; } return(horizontal > 0 && vertical > 0); }
public static bool TouchesWall(GenRect rect, GenRoom room) { for (int x = rect.MinX; x <= rect.MaxX; x++) { for (int y = rect.MinY; y <= rect.MaxY; y++) { GenTile check = room.GetAtWorldspaceG(x, y); if (check != null) { if (check.AnyTypes(GenDetail.DetailType.Wall)) { return(true); } } } } return(false); }
public static string Print(this GenData target, bool simple = true) { if (simple) { PrintCount++; GenTile[,] tile = target.TileMap; StringBuilder sb = new StringBuilder(); for (int y = 0; y < tile.GetLength(1); y++) { for (int x = 0; x < tile.GetLength(0); x++) { if (tile[x, y] == null) { sb.Append(' '); continue; } int max = tile[x, y].Details.Max(d => d.Priority); GenDetail toDraw = tile[x, y].Details.Where(d => d.Priority == max).First(); sb.Append(toDraw.Char); } //sb.Append('\n'); } return(sb.ToString()); } else { GenTile[,] work = new GenTile[target.Width, target.Height]; foreach (var room in target.Rooms) { work.Place(room.PosX, room.PosY, room.Data); } target.TileMap = work; return(Print(target)); } }
public GenPositionTile(GenTile tile, Vector2Int positionG) { Tile = tile; PositionG = positionG; }
public bool MakeCorridor(int x, int y, int length, Direction direction) { // define the dimensions of the corridor (er.. only the width and height..) int len = this.GetRand(2, length); const GenTile Floor = GenTile.Corridor; int xtemp; int ytemp = 0; switch (direction) { case Direction.North: // north // check if there's enough space for the corridor // start with checking it's not out of the boundaries if (x < 0 || x > this._xsize) { return(false); } xtemp = x; // same thing here, to make sure it's not out of the boundaries for (ytemp = y; ytemp > (y - len); ytemp--) { if (ytemp < 0 || ytemp > this._ysize) { return(false); // oh boho, it was! } if (GetCellTypeNoOffset(xtemp, ytemp) != GenTile.Unused) { return(false); } } // if we're still here, let's start building Corridors++; for (ytemp = y; ytemp > (y - len); ytemp--) { this.SetCell(xtemp, ytemp, Floor); } break; case Direction.East: // east if (y < 0 || y > this._ysize) { return(false); } ytemp = y; for (xtemp = x; xtemp < (x + len); xtemp++) { if (xtemp < 0 || xtemp > this._xsize) { return(false); } if (GetCellTypeNoOffset(xtemp, ytemp) != GenTile.Unused) { return(false); } } Corridors++; for (xtemp = x; xtemp < (x + len); xtemp++) { this.SetCell(xtemp, ytemp, Floor); } break; case Direction.South: // south if (x < 0 || x > this._xsize) { return(false); } xtemp = x; for (ytemp = y; ytemp < (y + len); ytemp++) { if (ytemp < 0 || ytemp > this._ysize) { return(false); } if (GetCellTypeNoOffset(xtemp, ytemp) != GenTile.Unused) { return(false); } } Corridors++; for (ytemp = y; ytemp < (y + len); ytemp++) { this.SetCell(xtemp, ytemp, Floor); } break; case Direction.West: // west if (ytemp < 0 || ytemp > this._ysize) { return(false); } ytemp = y; for (xtemp = x; xtemp > (x - len); xtemp--) { if (xtemp < 0 || xtemp > this._xsize) { return(false); } if (GetCellTypeNoOffset(xtemp, ytemp) != GenTile.Unused) { return(false); } } Corridors++; for (xtemp = x; xtemp > (x - len); xtemp--) { this.SetCell(xtemp, ytemp, Floor); } break; } // woot, we're still here! let's tell the other guys we're done!! return(true); }
//and here's the one generating the whole map public bool CreateDungeon(Vector3Int gridBoundsMin, int inx, int iny, int inobj) { _offset = gridBoundsMin; this._objects = inobj < 1 ? 10 : inobj; // adjust the size of the map, if it's smaller or bigger than the limits if (inx < 3) { this._xsize = 3; } else if (inx > xmax) { this._xsize = xmax; } else { this._xsize = inx; } if (iny < 3) { this._ysize = 3; } else if (iny > ymax) { this._ysize = ymax; } else { this._ysize = iny; } Console.WriteLine(MsgXSize + this._xsize); Console.WriteLine(MsgYSize + this._ysize); Console.WriteLine(MsgMaxObjects + this._objects); // redefine the map var, so it's adjusted to our new map size this._dungeonMap = new GenTile[this._xsize * this._ysize]; // start with making the "standard stuff" on the map this.Initialize(); /******************************************************************************* * And now the code of the random-map-generation-algorithm begins! *******************************************************************************/ // start with making a room in the middle, which we can start building upon this.MakeRoom(this._xsize / 2, this._ysize / 2, _roomSizeMaxX, _roomSizeMaxY, RandomDirection()); // getrand saken f????r att slumpa fram riktning p?? rummet // keep count of the number of "objects" we've made int currentFeatures = 1; // +1 for the first room we just made // then we sart the main loop for (int countingTries = 0; countingTries < 1000; countingTries++) { // check if we've reached our quota if (currentFeatures == this._objects) { break; } // start with a random wall int newx = 0; int xmod = 0; int newy = 0; int ymod = 0; Direction?validTile = null; // 1000 chances to find a suitable object (room or corridor).. for (int testing = 0; testing < 1000; testing++) { newx = this.GetRand(1, this._xsize - 1); newy = this.GetRand(1, this._ysize - 1); if (GetCellTypeNoOffset(newx, newy) == GenTile.DirtWall || GetCellTypeNoOffset(newx, newy) == GenTile.Corridor) { var surroundings = this.GetSurroundings(new Vector2Int(newx, newy)); // check if we can reach the place var canReach = surroundings.FirstOrDefault(s => s.Item2.Item2 == GenTile.Corridor || s.Item2.Item2 == GenTile.DirtFloor); if (canReach == null) { continue; } validTile = canReach.Item2.Item1; switch (canReach.Item2.Item1) { case Direction.North: xmod = 0; ymod = -1; break; case Direction.East: xmod = 1; ymod = 0; break; case Direction.South: xmod = 0; ymod = 1; break; case Direction.West: xmod = -1; ymod = 0; break; default: throw new InvalidOperationException(); } // check that we haven't got another door nearby, so we won't get alot of openings besides // each other if (GetCellTypeNoOffset(newx, newy + 1) == GenTile.Door) // north { validTile = null; } else if (GetCellTypeNoOffset(newx - 1, newy) == GenTile.Door) // east { validTile = null; } else if (GetCellTypeNoOffset(newx, newy - 1) == GenTile.Door) // south { validTile = null; } else if (GetCellTypeNoOffset(newx + 1, newy) == GenTile.Door) // west { validTile = null; } // if we can, jump out of the loop and continue with the rest if (validTile.HasValue) { break; } } } if (validTile.HasValue) { // choose what to build now at our newly found place, and at what direction int feature = this.GetRand(0, 100); if (feature <= ChanceRoom) { // a new room if (this.MakeRoom(newx + xmod, newy + ymod, 8, 6, validTile.Value)) { currentFeatures++; // add to our quota // then we mark the wall opening with a door this.SetCell(newx, newy, GenTile.Door); // clean up infront of the door so we can reach it this.SetCell(newx + xmod, newy + ymod, GenTile.DirtFloor); } } else if (feature >= ChanceRoom) { // new corridor if (this.MakeCorridor(newx + xmod, newy + ymod, 6, validTile.Value)) { // same thing here, add to the quota and a door currentFeatures++; this.SetCell(newx, newy, GenTile.Door); } } } } /******************************************************************************* * All done with the building, let's finish this one off *******************************************************************************/ AddSprinkles(); // all done with the map generation, tell the user about it and finish Console.WriteLine(MsgNumObjects + currentFeatures); for (int y = 0; y < this._ysize; y++) { for (int x = 0; x < this._xsize; x++) { if (GetCellTypeNoOffset(x, y) == GenTile.Corridor) { List <Vector2Int> neighbours = Vector2IntUtilities.Neighbours8(new Vector2Int(x, y)); foreach (Vector2Int neighbour in neighbours) { GenTile neighbourCell = GetCellTypeNoOffset(neighbour.x, neighbour.y); if (neighbourCell == GenTile.Unused) { SetCell(neighbour.x, neighbour.y, GenTile.StoneWall); } } } } } return(true); }
// setting a tile's type void SetCell(int x, int y, GenTile celltype) { this._dungeonMap[x + this._xsize * y] = celltype; }
void Start() { //Overworld Generation #region Biome Generation //Biome Generation //Calculates each tiles biome values for the entire world //Options: // World can be re-created using seeds only on load // The big float map could be saved and then manually loaded? - not sure how much more effective this will be than doing simple math of perlin noise maps // ? //Value 1: HEIGHT GenerateOverworldBlock(); float[,] height = NoiseMap.GeneratePerlinNoiseMap(WorldSize, WorldSize, levelScale, 0, 0, heightWaves); //Value 2: HEAT float[,] temperature = NoiseMap.GenerateUniformNoiseMap(WorldSize, WorldSize, WorldSize / 2, WorldSize / 2, 0); float[,] randomTemperature = NoiseMap.GeneratePerlinNoiseMap(WorldSize, WorldSize, levelScale, WorldSize, 0, temperatureWaves); float[,] heatMap = new float[WorldSize, WorldSize]; for (int yIndex = 0; yIndex < WorldSize; yIndex++) { for (int xIndex = 0; xIndex < WorldSize; xIndex++) { heatMap[xIndex, yIndex] = temperature[xIndex, yIndex] * randomTemperature[xIndex, yIndex]; heatMap[xIndex, yIndex] += temperatureCurve.Evaluate(height[xIndex, yIndex]) * heatMap[xIndex, yIndex]; heatMap[xIndex, yIndex] = Mathf.Clamp(heatMap[xIndex, yIndex], 0f, 1f); } } //Value 3: MOISTURE float[,] moistureMap = NoiseMap.GeneratePerlinNoiseMap(WorldSize, WorldSize, levelScale, 0, 0, moistureWaves); for (int yIndex = 0; yIndex < WorldSize; yIndex++) { for (int xIndex = 0; xIndex < WorldSize; xIndex++) { moistureMap[xIndex, yIndex] -= this.moistureCurve.Evaluate(height[xIndex, yIndex]) * moistureMap[xIndex, yIndex]; moistureMap[xIndex, yIndex] = Mathf.Clamp(moistureMap[xIndex, yIndex], 0f, 1f); } } //Fill placeholder tile map GenTile[,] generatedtiles = new GenTile[WorldSize, WorldSize]; for (int i = 0; i < WorldSize; i++) { for (int j = 0; j < WorldSize; j++) { Biome chosenBio = BiomeData.Instance.GetBiome(height[i, j], heatMap[i, j], moistureMap[i, j]); generatedtiles[i, j] = new GenTile(i, j, chosenBio); } } #endregion #region Feature Generation //Feature Generation //TODO: this feature generation will need to be chunk related //Tree generation float[,] trees = NoiseMap.GeneratePerlinNoiseMap(WorldSize, WorldSize, 1.1f, 0, 0, NoiseMap.DefaultWaves); for (int i = 0; i < WorldSize; i++) { for (int j = 0; j < WorldSize; j++) { if (generatedtiles[i, j].tileBiome.SpawnTrees) { if (trees[i, j] >= 0.8) { ObjectManager.Instance.AddObjectToGrid(generatedtiles[i, j].tileBiome.Treefab, new Vector3(i, j, 0)); } } } } //Apply features to biome tiles // e.g. village, well, etc. #endregion //TODO: add functionality for a second layer (i.e. a cave layer) with different generation //float[,] caveMap = GenerateCaveBlock(); //Generate for (int i = 0; i < numChunks; i++) { for (int j = 0; j < numChunks; j++) { //gen chunk GenTile[,] chunkMap = new GenTile[Chunk.size, Chunk.size]; for (int k = 0; k < Chunk.size; k++) { for (int z = 0; z < Chunk.size; z++) { chunkMap[k, z] = generatedtiles[k + i * Chunk.size, z + j * Chunk.size]; } } fullchunkmap.Add(new System.Tuple <int, int>(i, j), chunkMap); } } //Save all chunks to disk? i.e. out of ram? //Load current nearby chunks LoadAllChunks(); }
/// <summary> /// checks if Position is in the corner (floor, not wall) /// </summary> public bool IsCornerGR(int gx, int gy, GenRoom room, GenDetail.DetailType[] checkFor = null, GenDetail.DetailType[] noWall = null) { if (checkFor == null) { checkFor = new GenDetail.DetailType[] { GenDetail.DetailType.Wall }; } if (noWall == null) { noWall = new GenDetail.DetailType[] { GenDetail.DetailType.Door }; } bool vertical = false; bool horizontal = false; GenTile tile; if (room != null) { tile = room.GetAtWorldspaceG(gx, gy); if (tile != null) { GenTile check = room.GetAtWorldspaceG(gx + 1, gy); if (check != null && check.AnyTypes(checkFor) && check.NonTypes(noWall)) { horizontal = true; } check = room.GetAtWorldspaceG(gx - 1, gy); if (check != null && check.AnyTypes(checkFor) && check.NonTypes(noWall)) { horizontal = true; } check = room.GetAtWorldspaceG(gx, gy + 1); if (check != null && check.AnyTypes(checkFor) && check.NonTypes(noWall)) { vertical = true; } check = room.GetAtWorldspaceG(gx, gy - 1); if (check != null && check.AnyTypes(checkFor) && check.NonTypes(noWall)) { vertical = true; } return(horizontal && vertical); } return(false); } else { tile = GetTile(gx, gy); if (tile != null) { GenTile check = GetTile(gx + 1, gy); if (check != null && check.AnyTypes(GenDetail.DetailType.Wall)) { horizontal = true; } check = GetTile(gx - 1, gy); if (check != null && check.AnyTypes(GenDetail.DetailType.Wall)) { horizontal = true; } check = GetTile(gx, gy + 1); if (check != null && check.AnyTypes(GenDetail.DetailType.Wall)) { vertical = true; } check = GetTile(gx, gy - 1); if (check != null && check.AnyTypes(GenDetail.DetailType.Wall)) { vertical = true; } return(horizontal && vertical); } return(false); } }
private void PlaceTilesBasingOnDungeon(BoundsInt gridBounds, Dungeon generator) { bool stairsGenerated = false; foreach (Vector3Int position in gridBounds.allPositionsWithin) { Vector2Int position2D = position.ToVector2Int(); GenTile genTile = generator.GetCellType(position2D.x, position2D.y); switch (genTile) { case GenTile.DirtFloor: { _gameContext.DirtTilemap.SetTile(position, Dirt); if (_rng.Check(0.03f)) { _gameContext.EnvironmentTilemap.SetTile(position, _rng.Choice(FloorEnvironmetals)); } if (_rng.Check(0.06f)) { if (Vector2IntUtilities.Neighbours8(position2D).All(n => generator.GetCellType(n.x, n.y) == GenTile.DirtFloor)) { _gameContext.ObjectsTilemap.SetTile(position, _rng.Choice(WallEnvironmetals)); } } break; } case GenTile.Corridor: { _gameContext.DirtTilemap.SetTile(position, Dirt); break; } case GenTile.StoneWall: case GenTile.DirtWall: { _gameContext.WallsTilemap.SetTile(position, Wall); if (_rng.Check(0.04f)) { _gameContext.EnvironmentTilemap.SetTile(position, _rng.Choice(WallAttachmentEnvironmetals)); } break; } case GenTile.Upstairs: { _gameContext.DirtTilemap.SetTile(position, Dirt); _gameContext.EnvironmentTilemap.SetTile(position, StairsUp); _gameContext.WallsTilemap.SetTile(position, null); stairsGenerated = true; break; } case GenTile.Downstairs: { _gameContext.DirtTilemap.SetTile(position, Dirt); break; } case GenTile.Door: { _gameContext.DirtTilemap.SetTile(position, Dirt); GenTile tileToRight = generator.GetCellType(position.x + 1, position.y); bool isHorizontalDoor = tileToRight == GenTile.Corridor || tileToRight == GenTile.DirtFloor; bool doorsAreOpen = _rng.Check(0.3f); if (doorsAreOpen) { _gameContext.EnvironmentTilemap.SetTile(position, isHorizontalDoor ? DoorsHorizontalOpen : DoorsVerticalOpen); } else { _gameContext.WallsTilemap.SetTile(position, isHorizontalDoor ? DoorsHorizontalClosed : DoorsVerticalClosed); } break; } default: { break; } } } if (!stairsGenerated) { BoundsInt randomRoom = _rng.Choice(generator.Rooms); Vector3Int center = BoundsIntUtilities.Center(randomRoom).ToVector3Int(); _gameContext.DirtTilemap.SetTile(center, Dirt); _gameContext.EnvironmentTilemap.SetTile(center, StairsUp); _gameContext.WallsTilemap.SetTile(center, null); Debug.Log("Missing stairs in dungeon! Generating in random room on position: " + center); } }
public static IEnumerator GetSimpleTemple() { GenData temple = new GenData(Random.Range(TempleWidth.start, TempleWidth.end), Random.Range(TempleHeight.start, TempleHeight.end)); List <GenRoom> AutoFillRoom = new List <GenRoom>(); // list of all rooms that are not allowed to be used for door placement List <GenRoom> NoAutoDoor = new List <GenRoom>(); List <GenRoom> SecretRooms = new List <GenRoom>(); GenTile Chest = GenTile.GetEmpty(); Chest.Details.Add(new GenDetail() { Char = '=', Type = GenDetail.DetailType.Entity, Entity = GenDetail.EntityType.Chest }); GenTile pillar = GenTile.GetEmpty(); //pillar.Details.Add(new GenDetail() { Char = '\u01C1', Type = GenDetail.DetailType.Decoration }); pillar.Details.Add(new GenDetail() { Char = 'O', Type = GenDetail.DetailType.Decoration }); GenTile[,] pillars = new GenTile[, ] { { GenTile.Copy(pillar), GenTile.Copy(pillar) }, { GenTile.Copy(pillar), GenTile.Copy(pillar) } }; GenTile Door = GenTile.GetEmpty(); Door.Details.Add(new GenDetail() { Char = '+', Type = GenDetail.DetailType.Door, Entity = GenDetail.EntityType.Door }); GenRoom outer = GenRoom.Sized(temple.Width, temple.Height); outer.FillFloor('+'); outer.SpacePriority = -2; temple.PlaceRoom(0, 0, outer); temple.EdgeWalls('#', outer); // ----------- Log(temple); if (Logging != null) { yield return(new WaitForSeconds(0.25f)); } // ----------- int w = Random.Range(9, 12); int h = Random.Range(10, 16); // EntryHall temple.TryGrowRect(1, outer.Outer.GetCenter().y, w, h, out GenRect EntrySize, false); GenRoom EntryHall = GenRoom.At(EntrySize.MinX, EntrySize.MinY, EntrySize.WidthT, EntrySize.HeightT); EntryHall.FillFloor('.'); temple.PlaceRoom(EntrySize.MinX, EntrySize.MinY, EntryHall); temple.EdgeWalls('#'); EntryHall.GetAtWorldspaceG( EntrySize.MinX + 1, EntrySize.GetCenter().y) .Details .Add(new GenDetail() { Char = '>', Type = GenDetail.DetailType.Entity, Entity = GenDetail.EntityType.StairsDown }); int posX = EntrySize.MinX + 2; int posy = EntrySize.MinY + 2; GenTile[,] sym = GenUtil.GetSymetry(pillars.GetCopy(), ref posX, ref posy, EntryHall, GenUtil.Axis.Horizontal | GenUtil.Axis.Vertical); EntryHall.PlaceDetailsAt(posX, posy, sym); temple.FixOverlap(); // ----------- Log(temple); if (Logging != null) { yield return(new WaitForSeconds(0.25f)); } // ----------- // hall to big thing int whall = Random.Range(10, 25); int hhall = Random.Range(5, 7); int space = Random.Range(2, 4); temple.TryGrowRect(EntrySize.MaxX + 1, EntrySize.GetCenter().y, whall, hhall, out GenRect HallSize); GenRoom PillarHall = GenRoom.Sized(HallSize.WidthT, HallSize.HeightT); PillarHall.FillFloor('.'); PillarHall.SpacePriority = 3; temple.PlaceRoom(HallSize.MinX, HallSize.MinY, PillarHall); temple.EdgeWalls('#', PillarHall); NoAutoDoor.Add(PillarHall); // place doors to the entry if (hhall == 5) { // a single door in the middle PillarHall.AddDetails(HallSize.MinX, HallSize.MinY + 2, GenTile.Copy(Door)); PillarHall.AddDetails(HallSize.MaxX, HallSize.MinY + 2, GenTile.Copy(Door)); } else { // place symetric doors PillarHall.AddDetails(HallSize.MinX, HallSize.MinY + 2, GenTile.Copy(Door)); PillarHall.AddDetails(HallSize.MinX, HallSize.MinY + 3, GenTile.Copy(Door)); PillarHall.AddDetails(HallSize.MaxX, HallSize.MinY + 2, GenTile.Copy(Door)); PillarHall.AddDetails(HallSize.MaxX, HallSize.MinY + 3, GenTile.Copy(Door)); } int currBar = HallSize.MinX + space; GenTile[,] singlePillar = new GenTile[, ] { { GenTile.Copy(pillar) } }; while (temple.IsInsideRoom(currBar, HallSize.MinY + 1, PillarHall)) { int fx = currBar; int fy = HallSize.MinY + 1; GenTile[,] feature = GenUtil.GetSymetry(singlePillar, ref fx, ref fy, PillarHall, GenUtil.Axis.Vertical); PillarHall.PlaceDetailsAt(fx, fy, feature); currBar += space; } temple.FixOverlap(); // ----------- Log(temple); if (Logging != null) { yield return(new WaitForSeconds(0.25f)); } // ----------- // holy water or something int waterHeight = Random.Range(2, 4); int waterWidth = Random.Range(2, 4); int waterPillarWidth = Random.Range(2, 3); int waterRoomHeight = waterHeight + 4 + waterPillarWidth * 2; int waterRoomWidth = waterWidth + 6 + waterPillarWidth * 2; temple.TryGrowRect(HallSize.MaxX + 1, HallSize.GetCenter().y, waterRoomWidth, waterRoomHeight, out GenRect WaterSize, false, GenUtil.Direction4.Top); GenRoom waterRoom = GenRoom.Sized(WaterSize.WidthT, WaterSize.HeightT); waterRoom.FillFloor(); waterRoom.SpacePriority = 2; temple.PlaceRoom(WaterSize.MinX, WaterSize.MinY, waterRoom); temple.EdgeWalls('#', waterRoom); int BackDoorWater = Random.Range(1, waterRoom.Height / 2); waterRoom.AddDetails(WaterSize.MaxX, WaterSize.MinY + BackDoorWater, GenTile.Copy(Door)); waterRoom.AddDetails(WaterSize.MaxX, WaterSize.MaxY - BackDoorWater, GenTile.Copy(Door)); GenTile waterSingle = GenTile.GetEmpty(); waterSingle.Details.Add(new GenDetail() { Char = '~', Type = GenDetail.DetailType.Background }); GenTile[,] water = GenUtil.Fill(waterWidth, waterHeight, waterSingle); waterRoom.PlaceDetailsAt(WaterSize.MinX + 3 + waterPillarWidth, WaterSize.MinY + 2 + waterPillarWidth, water); int waterPX = WaterSize.MinX + 3; int waterPY = WaterSize.MinY + 2; GenTile[,] waterPillarPlace = GenUtil.GetSymetry(pillars.GetCopy(), ref waterPX, ref waterPY, waterRoom, GenUtil.Axis.Horizontal | GenUtil.Axis.Vertical); waterRoom.PlaceDetailsAt(waterPX, waterPY, waterPillarPlace); temple.FixOverlap(); // ----------- Log(temple); if (Logging != null) { yield return(new WaitForSeconds(0.25f)); } // ----------- // pillar spam int spamWidth = Random.Range(10, 20); int spamHeight = WaterSize.HeightT + Random.Range(8, 15); temple.TryGrowRect(WaterSize.MaxX + 1, WaterSize.GetCenter().y, spamWidth, spamHeight, out GenRect SpamSize, true, GenUtil.Direction4.Top); GenRoom Spam = GenRoom.Sized(SpamSize.WidthT, SpamSize.HeightT); Spam.FillFloor(); Spam.SpacePriority = 1; temple.PlaceRoom(SpamSize.MinX, SpamSize.MinY, Spam); temple.EdgeWalls('#', Spam); int spamPX = SpamSize.MinX + 2; int spamPY = SpamSize.MinY + 2; for (int x = spamPX; temple.IsInsideRoom(x, spamPY, Spam); x += 2) { for (int y = spamPY; temple.IsInsideRoom(x, y, Spam); y += 2) { GenTile p = GenTile.Copy(pillar); Spam.AddDetails(x, y, p); } } Spam.AddDetail( SpamSize.MaxX - 1, SpamSize.GetCenter().y, new GenDetail() { Char = '<', Type = GenDetail.DetailType.Entity, Entity = GenDetail.EntityType.StairsUp }); temple.FixOverlap(); // ----------- Log(temple); if (Logging != null) { yield return(new WaitForSeconds(0.25f)); } // ----------- //temple.Rooms.Remove(outer); // we dont have boundries for (int x = outer.Inner.MinX; x < outer.Outer.MaxX; x++) { for (int y = outer.Inner.MinY; y < outer.Outer.MaxY; y++) { outer.RemoveTileAtG(x, y); } } //GenRoom Mark = GenRoom.Sized(0, 0); //Mark.FillFloor('X'); //Mark.SpacePriority = 100; // lets go ham with randomly sized rooms int spawnAttemptsRemaining = 1000; while (spawnAttemptsRemaining-- > 0)// lol the arrow { int rWidth = Random.Range(RandomWidth.start, RandomWidth.end); int rHeight = Random.Range(RandomHeight.start, RandomHeight.end); int rX = Random.Range(2, temple.Width - 2); int rY = Random.Range(2, temple.Height - 2); GenRect rHopeSize = new GenRect(rX, rX + rWidth + 1, rY, rY + rWidth - 1); if (temple.IsInsideRoom(rX, rY) || temple.GetTile(rX, rY) != null) { continue; } temple.TryGrowRect(rX, rY, rWidth, rHeight, out GenRect rSize, true); GenRoom add = GenRoom.Sized(rSize.WidthT, rSize.HeightT); add.FillFloor(); add.SpacePriority = 01; temple.PlaceRoom(rSize.MinX, rSize.MinY, add); AutoFillRoom.Add(add); temple.EdgeWalls('#', add); temple.FixOverlap(); /* * if (rWidth * 2 < rHeight || rHeight * 2 < rWidth) * { * if (Random.Range(0,10)>4) * { * // we are making a hallway * * //TODO: hallway * * temple.PlaceRoom(rX, rY, Mark); * Log(temple); * if (Logging!=null) * { * yield return new WaitForSeconds(0.25f); * } * temple.Rooms.Remove(Mark); * continue; * } * } */ /* * int randomChance = Random.Range(0, 4); * switch (randomChance) * { * case 0: * // random pillars in the room * * for (int i = 0; i < 7 + (rSize.WidthT + rSize.HeightT)/5; i++) * { * int px = Random.Range(rSize.MinX + 1, rSize.MaxX); * int py = Random.Range(rSize.MinY + 1, rSize.MaxY); * add.AddDetails(px, py, pillar); * } * * break; * case 1: * // random water * for (int i = 0; i < 15 + (rSize.WidthT + rSize.HeightT)/3; i++) * { * int px = Random.Range(rSize.MinX + 1, rSize.MaxX); * int py = Random.Range(rSize.MinY + 1, rSize.MaxY); * GenDetail littleWater= new GenDetail() { Char = '~', Type = GenDetail.DetailType.Background}; * add.AddDetail(px, py, littleWater); * } * break; * case 2: * // random room inside if possible else empty * if (rSize.WidthT>=7&& rSize.HeightT >= 7) * { * int insideX = rSize.GetCenter().x; * int insideY = rSize.GetCenter().y; * * temple.TryGrowRect(insideX, insideY, 100, 100, out GenRect insideSize, false); * GenRoom inside = GenRoom.Sized(insideSize.WidthT, insideSize.HeightT); * inside.FillFloor(); * inside.SpacePriority = 2; * temple.PlaceRoom(insideSize.MinX, insideSize.MinY, inside); * temple.EdgeWalls('#',inside); * temple.FixOverlap(); * * } * else * { * for (int i = 0; i < 7; i++) * { * int px = Random.Range(rSize.MinX + 1, rSize.MaxX); * int py = Random.Range(rSize.MinY + 1, rSize.MaxY); * add.AddDetails(px, py, pillar); * } * } * break; * default: * break; * } * * Log(temple); * if (Logging!=null) * { * yield return new WaitForSeconds(0.25f); * } */ } // ----------- Log(temple); if (Logging != null) { yield return(new WaitForSeconds(0.25f)); } // ----------- // now fill the rooms with things var adjList = temple.GetAdjacentRoomMap(); // remove any Room that is too small and have no connections List <GenRoom> tooSmall = new List <GenRoom>(); foreach (var room in temple.Rooms) { if (room.Width >= 5 && room.Height == 3) { tooSmall.Add(room); continue; } if (room.Height >= 5 && room.Width == 3) { tooSmall.Add(room); continue; } if (room.Height <= 3 && room.Width <= 3) { tooSmall.Add(room); continue; } if (adjList[room].Count == 0) { tooSmall.Add(room); continue; } } foreach (var room in tooSmall) { temple.Rooms.Remove(room); } // ----------- Log(temple); if (Logging != null) { yield return(new WaitForSeconds(0.25f)); } // ----------- List <GenRoom> PotentialSecret = new List <GenRoom>(); foreach (var room in temple.Rooms) { if (room.Width + room.Height <= 12) { PotentialSecret.Add(room); } } Debug.Log("potential " + PotentialSecret.Count + "Secret rooms"); // 1 room --> 0,1,2,3 // 2 room --> 4,5 int SecretCount = Mathf.Min(Mathf.FloorToInt(Mathf.Sqrt(Random.Range(1, 6))), PotentialSecret.Count); // this goes to 5 Debug.Log(SecretCount + " Secret rooms chosen"); foreach (var secret in PotentialSecret.GetRandom(SecretCount)) { // we get random door // add a chest // remove it from door spawn GenPositionTile entry = temple.GetDoorableTiles(secret.GetAllTiles()).GetRandom(); secret.AddDetail(entry.PositionG.x, entry.PositionG.y, new GenDetail() { Char = '*', Entity = GenDetail.EntityType.Door, Type = GenDetail.DetailType.Door }); GenPositionTile myChest = secret .GetAllTiles() .Where(t => temple.IsInsideRoom(t.PositionG.x, t.PositionG.y, secret) && temple.IsCornerGR(t.PositionG.x, t.PositionG.y, secret)) .ToList() .GetRandom(); secret.AddDetails(myChest.PositionG.x, myChest.PositionG.y, GenTile.Copy(Chest)); AutoFillRoom.Remove(secret); SecretRooms.Add(secret); NoAutoDoor.Add(secret); } // ----------- Log(temple); if (Logging != null) { yield return(new WaitForSeconds(0.25f)); } // ----------- // go through all other rooms and determin what they are foreach (GenRoom room in AutoFillRoom) { // ----------- Log(temple); if (Logging != null) { yield return(new WaitForSeconds(0.25f)); } // ----------- // pillar hallway if (room.Height <= 7 && room.Height >= 5 && room.Width > 6) { // potential horizontal hallway if (Random.value < 0.4f) { // hallway confirmed // left to right GenTile[,] p = new GenTile[, ] { { GenTile.Copy(pillar) } }; int spacing = Random.Range(2, 5); int tmpX = room.Outer.MinX + spacing; int tmpY = room.Outer.MinY + 1; p = GenUtil.GetSymetry(p, ref tmpX, ref tmpY, room, GenUtil.Axis.Vertical); while (temple.IsInsideRoom(tmpX, tmpY, room)) { room.PlaceDetailsAt(tmpX, tmpY, p); tmpX = tmpX + spacing; } int enemyCount = Random.Range(0, 4); for (int i = 0; i < enemyCount; i++) { SpawnEnemy(temple, room); } int itemCount = Random.Range(-1, 3); for (int i = 0; i < itemCount; i++) { SpawnItem(temple, room, true); } int chestCount = Random.Range(-2, 2); for (int i = 0; i < chestCount; i++) { SpawnChest(temple, room, true); } continue; } } if (room.Width <= 7 && room.Width >= 5 && room.Height > 6) { // potential horizontal hallway if (Random.value < 0.4f) { // hallway confirmed // left to right GenTile[,] p = new GenTile[, ] { { GenTile.Copy(pillar) } }; int spacing = Random.Range(2, 5); int tmpX = room.Outer.MinX + 1; int tmpY = room.Outer.MinY + spacing; p = GenUtil.GetSymetry(p, ref tmpX, ref tmpY, room, GenUtil.Axis.Horizontal); while (temple.IsInsideRoom(tmpX, tmpY, room)) { room.PlaceDetailsAt(tmpX, tmpY, p); tmpY = tmpY + spacing; } int enemyCount = Random.Range(0, 4); for (int i = 0; i < enemyCount; i++) { SpawnEnemy(temple, room); } int itemCount = Random.Range(-1, 3); for (int i = 0; i < itemCount; i++) { SpawnItem(temple, room, true); } int chestCount = Random.Range(-2, 2); for (int i = 0; i < chestCount; i++) { SpawnChest(temple, room, true); } continue; } } if (room.Height >= 8 && room.Width >= 8) { // can either be pillar spam or room in room if (Random.value < 0.6f) { if (Random.value < 0.7f && room.Width % 2 == 1 && room.Height % 2 == 1) { // pillar spam for (int x = 2; x < room.Width - 2; x += 2) { for (int y = 2; y < room.Height - 2; y += 2) { room.AddDetails(room.PosX + x, room.PosY + y, GenTile.Copy(pillar)); } } int enemyCount = Random.Range(0, 5); for (int i = 0; i < enemyCount; i++) { SpawnEnemy(temple, room); } int itemCount = Random.Range(-1, 3); for (int i = 0; i < itemCount; i++) { SpawnItem(temple, room, true); } int chestCount = Random.Range(-3, 3); for (int i = 0; i < chestCount; i++) { SpawnChest(temple, room, true); } } else { // room in room // find where to put the inner room temple.TryGrowRect(room.Inner.GetCenter().x, room.Inner.GetCenter().y, 100, 100, out GenRect InnerSize); if (InnerSize.WidthT >= 4 && InnerSize.HeightT >= 4) { if (InnerSize.WidthT >= 10 || InnerSize.HeightT >= 10) { if (Mathf.Abs(InnerSize.WidthT - InnerSize.HeightT) > 3) { // we want to divide if (InnerSize.WidthT > InnerSize.HeightT) { // divide left and right int singleWidth = InnerSize.WidthT / 2 - 2; // left GenRect LeftRoom = new GenRect(InnerSize.MinX, InnerSize.MinX + singleWidth, InnerSize.MinY, InnerSize.MaxY); // right GenRect RightRoom = new GenRect(InnerSize.MaxX - singleWidth, InnerSize.MaxX, InnerSize.MinY, InnerSize.MaxY); GenRoom left = GenRoom.Sized(LeftRoom.WidthT, LeftRoom.HeightT); left.FillFloor(); left.SpacePriority = 4; GenRoom right = GenRoom.Sized(RightRoom.WidthT, RightRoom.HeightT); right.FillFloor(); right.SpacePriority = 4; temple.PlaceRoom(LeftRoom.MinX, LeftRoom.MinY, left); temple.PlaceRoom(RightRoom.MinX, RightRoom.MinY, right); NoAutoDoor.Add(left); NoAutoDoor.Add(right); temple.EdgeWalls('#', left); temple.EdgeWalls('#', right); temple.FixOverlap(); // ----------- Log(temple); if (Logging != null) { yield return(new WaitForSeconds(0.25f)); } // ----------- var leftDoor = temple.GetDoorableTiles(left.GetAllTiles()).GetRandom(1); var rightDoor = temple.GetDoorableTiles(right.GetAllTiles()).GetRandom(1); for (int i = 0; i < leftDoor.Count; i++) { left.AddDetails(leftDoor[i].PositionG.x, leftDoor[i].PositionG.y, GenTile.Copy(Door)); } for (int i = 0; i < rightDoor.Count; i++) { right.AddDetails(rightDoor[i].PositionG.x, rightDoor[i].PositionG.y, GenTile.Copy(Door)); } SpawnItem(temple, left); SpawnItem(temple, right); if (Random.value < 0.4f) { SpawnItem(temple, right); } if (Random.value < 0.4f) { SpawnItem(temple, left); } if (Random.value < 0.2f) { SpawnChest(temple, left, true); } if (Random.value < 0.2f) { SpawnChest(temple, left, true); } } else { // divide top bot Debug.Log("currently not implemented, sorry"); } } } else { // one single room if (InnerSize.WidthT > 5) { InnerSize = InnerSize.Transform(-1, 0, -1, 0); } if (InnerSize.HeightT > 5) { InnerSize = InnerSize.Transform(0, -1, 0, -1); } Debug.Log("HERE"); GenRoom single = GenRoom.Sized(InnerSize.WidthT, InnerSize.HeightT); single.SpacePriority = 4; single.FillFloor(); NoAutoDoor.Add(single); temple.PlaceRoom(InnerSize.MinX, InnerSize.MinY, single); temple.EdgeWalls('#', single); temple.FixOverlap(); // ----------- Log(temple); if (Logging != null) { yield return(new WaitForSeconds(0.25f)); } // ----------- // double doors var doorables = single.GetAllTiles();// single.GetEdge().ToList(); var theDoors = temple.GetDoorableTiles(doorables).GetRandom(2); for (int i = 0; i < theDoors.Count; i++) { single.AddDetails(theDoors[i].PositionG.x, theDoors[i].PositionG.y, GenTile.Copy(Door)); } SpawnItem(temple, single); if (Random.value < 0.2f) { SpawnChest(temple, single, true); } if (Random.value < 0.2f) { SpawnChest(temple, single, true); } } } SpawnEnemy(temple, room); if (Random.value < 0.5f) { SpawnEnemy(temple, room); } if (Random.value < 0.2f) { SpawnEnemy(temple, room); } } continue; } } // something random //room.FillFloor('~'); SpawnEnemy(temple, room); SpawnEnemy(temple, room); if (Random.value < 0.5f) { SpawnEnemy(temple, room); } if (Random.value < 0.2f) { SpawnEnemy(temple, room); } SpawnItem(temple, room); if (Random.value < 0.3f) { SpawnItem(temple, room); } if (Random.value < 0.3f) { SpawnItem(temple, room); } if (Random.value < 0.4f) { SpawnChest(temple, room); } if (Random.value < 0.1f) { SpawnChest(temple, room); } } List <GenRoom> RequireDoor = new List <GenRoom>(temple.Rooms); foreach (var doo in NoAutoDoor) { RequireDoor.Remove(doo); } List <GenRoom> DoorIteration = new List <GenRoom>(RequireDoor); GenRoom start = EntryHall; Dictionary <GenRoom, List <GenRoom> > adj = temple.GetAdjacentRoomMap(); void RandomDoorTo(GenRoom a, GenRoom b) { var tiles = temple.GetDoorableTiles(temple.GetConnectingTiles(a, b)); var location = tiles.GetRandom(); a.AddDetails(location.PositionG.x, location.PositionG.y, GenTile.Copy(Door)); } while (RequireDoor.Count > 0) { DoorIteration.Clear(); DoorIteration.AddRange(RequireDoor); foreach (var room in DoorIteration) { if (temple.IsReachable(start, room)) { // reachable so we dont have to do a thing RequireDoor.Remove(room); } else { // place random door var available = adj[room]; RandomDoorTo(room, available.GetRandom()); } // ----------- Log(temple); if (Logging != null) { yield return(new WaitForSeconds(0.1f)); } // ----------- } } foreach (var room in adj[Spam].GetRandom(2)) { RandomDoorTo(Spam, room); } Log(temple); Debug.Log("Done"); LastOutput = GenUtil.Print(temple, false); Done?.Invoke(); }
public void Generate() { int minRoomSize = 50; rooms = new HashSet <GenRoom>(); for (int i = 0; i < 7 + ( int )(UnityEngine.Random.value * 4); i++) { GenRoom room = new GenRoom(); room.bounds.width = ((15 + ( int )(UnityEngine.Random.value * 20)) / 2) * 2; room.bounds.height = ((15 + ( int )(UnityEngine.Random.value * 20)) / 2) * 2; rooms.Add(room); } while (true) { bool changed = false; foreach (GenRoom r1 in rooms) { foreach (GenRoom r2 in rooms) { if (r1 == r2) { continue; } Vector2Int p1 = new Vector2Int(r1.bounds.x + r1.bounds.width / 2, r1.bounds.y + r1.bounds.height / 2); Vector2Int p2 = new Vector2Int(r2.bounds.x + r2.bounds.width / 2, r2.bounds.y + r2.bounds.height / 2); if (Math.Pow(Vector2Int.Distance(p1, p2), 2) < 2 * minRoomSize * minRoomSize + 2) { r2.bounds.x += ( int )((UnityEngine.Random.value - 0.5) * 5); r2.bounds.y += ( int )((UnityEngine.Random.value - 0.5) * 2.5); changed = true; break; } } if (changed) { break; } } if (!changed) { break; } } HashSet <GenVertex> Q = new HashSet <GenVertex>(); foreach (GenRoom r in rooms) { Q.Add(new GenVertex(r)); } GenVertex root = null; foreach (GenVertex v in Q) { if (root == null || v.r.bounds.x < root.r.bounds.x) { root = v; } } root.value = 0; HashSet <GenEdge> E = new HashSet <GenEdge>(); HashSet <GenEdge> G = new HashSet <GenEdge>(); HashSet <GenVertex> F = new HashSet <GenVertex>(); foreach (GenVertex r1 in Q) { foreach (GenVertex r2 in Q) { if (r1 == r2) { goto outer; } foreach (GenEdge e in E) { if (e.r2 == r1 && e.r1 == r2) { goto outer; } } E.Add(new GenEdge(r1, r2)); } outer :; } F.Add(root); Q.Remove(root); while (Q.Count > 0) { GenEdge start2 = null; foreach (GenEdge e in E) { if (F.Contains(e.r1) ^ F.Contains(e.r2)) { if (start2 == null || e.dist < start2.dist) { start2 = e; } } } Q.Remove(start2.r2); Q.Remove(start2.r1); F.Add(start2.r2); F.Add(start2.r1); E.Remove(start2); G.Add(start2); if (start2.r1.value < start2.r2.value) { start2.r2.value = ( float )(start2.r1.value + start2.dist); } else { start2.r1.value = ( float )(start2.r2.value + start2.dist); } } // G list of edges // rooms list of rooms HashSet <GenRoom> rooms2 = new HashSet <GenRoom>(); foreach (GenEdge ed in G) { // horizontal float diff1 = ed.r1.r.bounds.y - ed.r2.r.bounds.y - ed.r2.r.bounds.height + TUNNEL_THICKNESS; float diff2 = ed.r2.r.bounds.y - ed.r1.r.bounds.y - ed.r1.r.bounds.height + TUNNEL_THICKNESS; // vertical float diff3 = ed.r1.r.bounds.x - ed.r2.r.bounds.x - ed.r2.r.bounds.width + TUNNEL_THICKNESS; float diff4 = ed.r2.r.bounds.x - ed.r1.r.bounds.x - ed.r1.r.bounds.width + TUNNEL_THICKNESS; if (diff1 < 0 && diff2 < 0) { AddStraightHorizontal(rooms2, ed); } else if (diff3 < 0 && diff4 < 0) { AddStraightVertical(rooms2, ed); } else { AddCurve(rooms2, ed); } } HashSet <Vector2Int> allDoors = new HashSet <Vector2Int>(); foreach (GenRoom r in rooms) { for (int x1 = r.bounds.x; x1 < r.bounds.x + r.bounds.width; x1++) { for (int y1 = r.bounds.y; y1 < r.bounds.y + r.bounds.height; y1++) { int xMode = (x1 == r.bounds.x) ? -1 : (x1 == r.bounds.x + r.bounds.width - 1) ? 1 : 0; int yMode = (y1 == r.bounds.y) ? -1 : (y1 == r.bounds.y + r.bounds.height - 1) ? 1 : 0; r.tiles.Add(new Vector2Int(x1, y1), new GenTile(Room.TileType.WALL, GenTile.GetPosition(xMode, yMode))); } } for (int x1 = r.bounds.x + 1; x1 < r.bounds.x + r.bounds.width - 1; x1++) { for (int y1 = r.bounds.y + 1; y1 < r.bounds.y + r.bounds.height - 1; y1++) { r.tiles[new Vector2Int(x1, y1)].type = Room.TileType.GROUND; } } allDoors.UnionWith(r.AllDoors()); foreach (Vector2Int v in r.doorsDown) { r.tiles[v].type = Room.TileType.DOOR; r.tiles[v].position = GenTile.Position.BOTTOM; } foreach (Vector2Int v in r.doorsUp) { r.tiles[v].type = Room.TileType.DOOR; r.tiles[v].position = GenTile.Position.TOP; } foreach (Vector2Int v in r.doorsLeft) { r.tiles[v].type = Room.TileType.DOOR; r.tiles[v].position = GenTile.Position.LEFT; } foreach (Vector2Int v in r.doorsRight) { r.tiles[v].type = Room.TileType.DOOR; r.tiles[v].position = GenTile.Position.RIGHT; } } path = new GenRoom(); foreach (GenRoom r in rooms2) { for (int x1 = r.bounds.x; x1 < r.bounds.x + r.bounds.width; x1++) { for (int y1 = r.bounds.y; y1 < r.bounds.y + r.bounds.height; y1++) { Vector2Int pos1 = new Vector2Int(x1, y1); if (path.tiles.ContainsKey(pos1)) { path.tiles[pos1].type = Room.TileType.GROUND; } else { path.tiles.Add(pos1, new GenTile(Room.TileType.GROUND)); } Vector2Int pos2 = new Vector2Int(x1 + 1, y1); if (!path.tiles.ContainsKey(pos2) && !allDoors.Contains(pos2)) { path.tiles.Add(pos2, new GenTile(Room.TileType.WALL, GenTile.Position.RIGHT)); } pos2 = new Vector2Int(x1 - 1, y1); if (!path.tiles.ContainsKey(pos2) && !allDoors.Contains(pos2)) { path.tiles.Add(pos2, new GenTile(Room.TileType.WALL, GenTile.Position.LEFT)); } pos2 = new Vector2Int(x1, y1 + 1); if (!path.tiles.ContainsKey(pos2) && !allDoors.Contains(pos2)) { path.tiles.Add(pos2, new GenTile(Room.TileType.WALL, GenTile.Position.TOP)); } pos2 = new Vector2Int(x1, y1 - 1); if (!path.tiles.ContainsKey(pos2) && !allDoors.Contains(pos2)) { path.tiles.Add(pos2, new GenTile(Room.TileType.WALL, GenTile.Position.BOTTOM)); } } } for (int x1 = r.bounds.x; x1 < r.bounds.x + r.bounds.width; x1++) { for (int y1 = r.bounds.y; y1 < r.bounds.y + r.bounds.height; y1++) { Vector2Int pos2 = new Vector2Int(x1 + 1, y1 + 1); if (!path.tiles.ContainsKey(pos2) && !allDoors.Contains(pos2)) { path.tiles.Add(pos2, new GenTile(Room.TileType.WALL, GenTile.Position.TOP_RIGHT)); } pos2 = new Vector2Int(x1 - 1, y1 + 1); if (!path.tiles.ContainsKey(pos2) && !allDoors.Contains(pos2)) { path.tiles.Add(pos2, new GenTile(Room.TileType.WALL, GenTile.Position.TOP_LEFT)); } pos2 = new Vector2Int(x1 + 1, y1 - 1); if (!path.tiles.ContainsKey(pos2) && !allDoors.Contains(pos2)) { path.tiles.Add(pos2, new GenTile(Room.TileType.WALL, GenTile.Position.BOTTOM_RIGHT)); } pos2 = new Vector2Int(x1 - 1, y1 - 1); if (!path.tiles.ContainsKey(pos2) && !allDoors.Contains(pos2)) { path.tiles.Add(pos2, new GenTile(Room.TileType.WALL, GenTile.Position.BOTTOM_LEFT)); } } } if (r.AllDoors().Count > 0) { throw new NotSupportedException("Paths should not have any doors"); } } start = root.r; end = null; foreach (GenRoom r in rooms) { if (end == null || r.bounds.x > end.bounds.x) { end = r; } } rooms.Remove(start); rooms.Remove(end); foreach (GenRoom r in rooms) { GenerateInterior(r); } start.spawnpoints.Add(start.GetCenter()); end.spawnpoints.Add(end.GetCenter()); foreach (Vector2Int v in allDoors) { foreach (GenRoom r in rooms) { for (int x = -TUNNEL_THICKNESS; x < TUNNEL_THICKNESS; x++) { for (int y = -TUNNEL_THICKNESS; y < TUNNEL_THICKNESS; y++) { if (r.tiles.ContainsKey(v + new Vector2Int(x, y)) && r.tiles[v + new Vector2Int(x, y)].type == Room.TileType.ROCK) { r.tiles[v + new Vector2Int(x, y)].type = Room.TileType.GROUND; } } } } { GenRoom r = path; if (r.tiles.ContainsKey(v + new Vector2Int(0, 1)) && r.tiles[v + new Vector2Int(0, 1)].type == Room.TileType.WALL) { r.tiles.Remove(v + new Vector2Int(0, 1)); } if (r.tiles.ContainsKey(v + new Vector2Int(0, -1)) && r.tiles[v + new Vector2Int(0, -1)].type == Room.TileType.WALL) { r.tiles.Remove(v + new Vector2Int(0, -1)); } if (r.tiles.ContainsKey(v + new Vector2Int(1, 0)) && r.tiles[v + new Vector2Int(1, 0)].type == Room.TileType.WALL) { r.tiles.Remove(v + new Vector2Int(1, 0)); } if (r.tiles.ContainsKey(v + new Vector2Int(-1, 0)) && r.tiles[v + new Vector2Int(-1, 0)].type == Room.TileType.WALL) { r.tiles.Remove(v + new Vector2Int(-1, 0)); } } } foreach (GenRoom r in rooms) { MakeRoomRelative(r); } MakeRoomRelative(start); MakeRoomRelative(end); MakeRoomRelative(path); }
public IEnumerator RunGenerationTest() { GenUtil.PrintCount = 0; GenData sym = new GenData(20, 15); GenRoom Hallway = GenRoom.Sized(15, 5); Hallway.FillFloor('.'); Hallway.SpacePriority = 2; sym.PlaceRoom(1, 1, Hallway); TestDrawer.text = sym.Print(false); yield return(new WaitForSeconds(1f)); GenRoom OtherRooom = GenRoom.Sized(8, 10); OtherRooom.FillFloor('.'); OtherRooom.SpacePriority = 3; sym.PlaceRoom(11, 3, OtherRooom); TestDrawer.text = sym.Print(false); yield return(new WaitForSeconds(1f)); sym.EdgeWalls('#'); TestDrawer.text = sym.Print(false); yield return(new WaitForSeconds(1f)); OtherRooom.SpacePriority = 1; sym.FixOverlap(); TestDrawer.text = sym.Print(false); yield return(new WaitForSeconds(1f)); int wantX = 3; int wantY = 2; bool done = false; while (!done) { var got = Hallway.GetAtWorldspaceG(wantX, wantY); if (!sym.IsInsideRoom(wantX, wantY)) { done = true; } else { GenTile tile = GenTile.GetEmpty(); tile.Details.Add(new GenDetail() { Type = GenDetail.DetailType.Decoration, Char = 'O' }); GenTile[,] feature = new GenTile[, ] { { tile } }; int fposX = wantX; int fposY = wantY; GenTile[,] final = GenUtil.GetSymetry(feature, ref fposX, ref fposY, Hallway, GenUtil.Axis.Vertical); Hallway.SetTilesAtG(fposX, fposY, final); TestDrawer.text = sym.Print(false); yield return(new WaitForSeconds(0.5f)); wantX += 2; } } for (int x = 0; x < 20; x++) { for (int y = 0; y < 15; y++) { if (sym.IsCornerG(x, y, GenDetail.DetailType.Wall, GenDetail.DetailType.Decoration)) { GenRoom corner = GenRoom.Sized(1, 1); corner.FillFloor('X'); sym.PlaceRoom(x, y, corner); TestDrawer.text = sym.Print(false); yield return(new WaitForSeconds(0.25f)); } } } /* * GenData data = new GenData(40, 20); * * GenRoom startRoom = GenRoom.Sized(5,8,true); * startRoom.SpacePriority = 0; * * GenRoom room2 = GenRoom.Sized(8, 8, true); * room2.FillFloor('a'); * * GenRoom room3 = GenRoom.Sized(5, 5, true); * room3.FillFloor('b'); * room3.SpacePriority = 2; * * GenRoom room4 = GenRoom.Sized(10, 10, true); * room4.FillFloor('c'); * * data.PlaceRoom(1, 0, startRoom); * data.PlaceRoom(4, 1, room2); * data.PlaceRoom(25, 11, room3); * data.PlaceRoom(23, 3, room4); * * data.FixOverlap(); * data.EdgeWalls('#'); * * data.Print(false); */ }