Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Problem with Procedural Cave Generation (Sebastian Lague Tutorial)

Discussion in 'Scripting' started by keenanwoodall, May 3, 2015.

  1. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    597
    I'm on the sixth episode of his tutorial where we create connections between rooms. When I change the minWallRegionSize variable to a value hat turns a region of walls to a room, I'll get lots of index-out-of-range exceptions. Changing the minRoomSize variable doesn't throw up errors and works perfectly. The error takes me to the second Room constructor, inside the for loops.
    Code (csharp):
    1.  
    2. //Right here. In Monodevelop the error is on line 465, but it might be a different line on the post
    3. if(map[x, y] == 1)
    4.  
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6.  
    7. /// <summary>
    8. /// The MapGenerator class creates a 2d grid of values.
    9. /// The values can be adjusted via other parameters, turning the grid into, what seems like, noise.
    10. /// </summary>
    11. [RequireComponent(typeof(MeshGenerator))]
    12. public class MapGenerator : MonoBehaviour
    13. {
    14.     /// <summary>
    15.     /// The map's width.
    16.     /// </summary>
    17.     public int width = 50;
    18.     /// <summary>
    19.     /// The map's height.
    20.     /// </summary>
    21.     public int height = 50;
    22.     /// <summary>
    23.     /// When the map is randomly filled, it needs to obey a loose guideline of how much should be solid.
    24.     /// </summary>
    25.     [Range(0, 100)]
    26.     public int fillPercentage = 1;
    27.     /// <summary>
    28.     /// If true, the edges of the map will always be solid.
    29.     /// </summary>
    30.     public bool fillEdges = true;
    31.     /// <summary>
    32.     /// This is how thick the edges will be.
    33.     /// </summary>
    34.     public int edgeWidth = 1;
    35.     /// <summary>
    36.     /// Should the rooms be connected?
    37.     /// </summary>
    38.     public bool connectRooms = true;
    39.     /// <summary>
    40.     /// Whether or not the wall regions should be processed.
    41.     /// </summary>
    42.     public bool processWallRegions = false;
    43.     /// <summary>
    44.     /// Any wall region that is made up of less tiles that the minRoomSize will be made empty (set to zero).
    45.     /// </summary>
    46.     public int minWallRegionSize = 50;
    47.     /// <summary>
    48.     /// Whether or not the rooms should be processed.
    49.     /// </summary>
    50.     public bool processRooms = false;
    51.     /// <summary>
    52.     /// Any wall region that is made up of less tiles that the minRoomSize will be made empty (set to zero).
    53.     /// </summary>
    54.     public int minRoomSize = 50;
    55.     /// <summary>
    56.     /// The map will be generated from a seed so that the same map can be recreated via the same number/text.
    57.     /// </summary>
    58.     public string seed;
    59.     /// <summary>
    60.     /// If we don't want to use a custom seed we can have one randomly generated.
    61.     /// </summary>
    62.     public bool useRandomSeed;
    63.    
    64.     [SerializeField]
    65.     /// <summary>
    66.     /// The rules.
    67.     /// </summary>
    68.     public Rules rules;
    69.  
    70.     /// <summary>
    71.     /// This defines a grid of integers, any tile that is equal to 0 will be empty, and any tile that is equal to 1 will be solid.
    72.     /// This grid of numbers will be filled with random 0's and 1's.
    73.     /// </summary>
    74.     private int[,] map;
    75.  
    76.     /// <summary>
    77.     /// The mesh generator.
    78.     /// </summary>
    79.     private MeshGenerator meshGenerator;
    80.    
    81.     void Start()
    82.     {
    83.         meshGenerator = GetComponent<MeshGenerator>();
    84.     }
    85.    
    86.     void Update()
    87.     {
    88.         width = Mathf.Clamp(width, 1, Int32.MaxValue);
    89.         height = Mathf.Clamp(height, 1, Int32.MaxValue);
    90.         edgeWidth = Mathf.Clamp(edgeWidth, 1, Int32.MaxValue);
    91.  
    92.         GenerateMap();
    93.     }
    94.  
    95.     /// <summary>
    96.     /// Generates the map.
    97.     /// </summary>
    98.     private void GenerateMap()
    99.     {
    100.         map = new int[width, height];
    101.         //RandomFillMap is called to fill map with basic data
    102.         RandomFillMap();
    103.  
    104.         //A set of rules will be applied to the grid of data
    105.         ApplyRule();
    106.  
    107.         ProcessRooms();
    108.  
    109.         //If the user wants the edges to be solid...
    110.         if(fillEdges)
    111.         {
    112.             CreateEdge();
    113.         }
    114.         //Now we've finished all of the rule iterations and have the finished grid of data
    115.         //That data will be sent to the MeshGenerator class to be turned into an actual mesh
    116.         meshGenerator.GenerateMesh(map, 1f);
    117.     }
    118.     private void CreateEdge()
    119.     {
    120.         int[,] borderedMap = new int[width + edgeWidth * 2,height + edgeWidth * 2];
    121.         for(int x = 0; x < borderedMap.GetLength(0); x++)
    122.         {
    123.             for(int y = 0; y < borderedMap.GetLength(1); y++)
    124.             {
    125.                 if(x >= edgeWidth && x < width + edgeWidth && y >= edgeWidth && y < height + edgeWidth)
    126.                     borderedMap[x, y] = map[x - edgeWidth, y - edgeWidth];
    127.                 else
    128.                     borderedMap[x,y] = 1;
    129.             }
    130.         }
    131.     }
    132.     private void ProcessRooms()
    133.     {
    134.         List<List<Coord>> wallRegions = GetRegions(1);
    135.         foreach(List<Coord> wallRegion in wallRegions)
    136.         {
    137.             if(wallRegion.Count < minWallRegionSize)
    138.             {
    139.                 foreach(Coord tile in wallRegion)
    140.                 {
    141.                     map[tile.x, tile.y] = 0;
    142.                 }
    143.             }
    144.         }
    145.        
    146.         List<List<Coord>> roomRegions = GetRegions(0);
    147.         List<Room> survivingRooms = new List<Room>();
    148.         foreach(List<Coord> roomRegion in roomRegions)
    149.         {
    150.             if(roomRegion.Count < minRoomSize)
    151.             {
    152.                 foreach(Coord tile in roomRegion)
    153.                 {
    154.                     map[tile.x, tile.y] = 1;
    155.                 }
    156.             }
    157.             else
    158.             {
    159.                 survivingRooms.Add(new Room(roomRegion, map));
    160.             }
    161.         }
    162.        
    163.         ConnectClosestRooms(survivingRooms);
    164.     }
    165.     private void ConnectClosestRooms(List<Room> allRooms)
    166.     {
    167.         int bestDistance = Int32.MaxValue;
    168.         Coord bestTileA = new Coord();
    169.         Coord bestTileB = new Coord();
    170.         Room bestRoomA = new Room();
    171.         Room bestRoomB = new Room();
    172.         bool possibleConnectionFound = false;
    173.  
    174.         //We'll go through all the rooms and compare roomA to find the closest one
    175.         foreach(Room roomA in allRooms)
    176.         {
    177.             //We'll set possibleConnectionFound equal to false so that whenever we move to the next room, it doesn't think it has found a good room
    178.             possibleConnectionFound = false;
    179.             foreach(Room roomB in allRooms)
    180.             {
    181.                 //Then we'll loop through each index in each room
    182.                 for(int tileIndexA = 0; tileIndexA < roomA.edgeTiles.Count; tileIndexA++)
    183.                 {
    184.                     if(roomA == roomB)
    185.                     {
    186.                         continue;
    187.                     }
    188.                     if(roomA.IsConnected(roomB))
    189.                     {
    190.                         possibleConnectionFound = false;
    191.                         break;
    192.                     }
    193.                     for(int tileIndexB = 0; tileIndexB < roomB.edgeTiles.Count; tileIndexB++)
    194.                     {
    195.                         Coord tileA = roomA.edgeTiles[tileIndexA];
    196.                         Coord tileB = roomB.edgeTiles[tileIndexB];
    197.                         int distanceBetweenRooms = (int)(Mathf.Pow(tileA.x - tileB.x, 2) + Mathf.Pow(tileA.y - tileB.y, 2));
    198.  
    199.                         if(distanceBetweenRooms < bestDistance || !possibleConnectionFound)
    200.                         {
    201.                             bestDistance = distanceBetweenRooms;
    202.                             possibleConnectionFound = true;
    203.  
    204.                             bestRoomA = roomA;
    205.                             bestRoomB = roomB;
    206.                             bestTileA = tileA;
    207.                             bestTileB = tileB;
    208.                         }
    209.                     }
    210.                 }
    211.             }
    212.             if(possibleConnectionFound)
    213.                 CreatePassage(bestRoomA, bestRoomB, bestTileA, bestTileB);
    214.         }
    215.     }
    216.     private void CreatePassage(Room roomA, Room RoomB, Coord tileA, Coord tileB)
    217.     {
    218.         Room.ConnectRooms(roomA, RoomB);
    219.         Debug.DrawLine(CoordToWorldPoint(tileA), CoordToWorldPoint(tileB), Color.green);
    220.     }
    221.  
    222.     public Vector3 CoordToWorldPoint(Coord tile)
    223.     {
    224.         return new Vector3(-width / 2 + 0.5f + tile.x, 2f, -height / 2 + 0.5f + tile.y);
    225.     }
    226.     /// <summary>
    227.     /// This method creates the rough data for the ApplyRule method to smooth.
    228.     /// </summary>
    229.     private void RandomFillMap()
    230.     {
    231.         //If a random seed is wanted-
    232.         if(useRandomSeed)
    233.             //Seed is set to the amout of time that the game has been running
    234.             seed = Time.time.ToString();
    235.         //This will return a unique integer, simulating randomness
    236.         //Prng stands for Pseudo Random Number Generator
    237.         System.Random prng = new System.Random(seed.GetHashCode());
    238.        
    239.         //Each index in the maps array of numbers is looped through
    240.         //For every x index-
    241.         for(int x = 0; x < width; x++)
    242.         {
    243.             //Every y index will be iterated through as well
    244.             for(int y = 0; y < height; y++)
    245.             {
    246.                 //Using the if/else notation, the current index will be set to 1 if the generated number is less than fillPercentage,
    247.                 //otherwise it will be set to 0
    248.                 map[x, y] = (prng.Next(0, 100) < fillPercentage) ? 1 : 0;
    249.             }
    250.         }
    251.     }
    252.    
    253.     /// <summary>
    254.     /// ApplyRule lets the user choose and create custom rules that will be applied to the map.
    255.     /// Withought this method, the map would just be boring and look like tv static.
    256.     /// </summary>
    257.     void ApplyRule()
    258.     {
    259.         if(rules.lague.applyRule) rules.lague.ApplyRule(map, this);
    260.         if(rules.mazeWorld.applyRule) rules.mazeWorld.ApplyRule(map, this);
    261.         if(rules.gameOfLife.applyRule) rules.gameOfLife.ApplyRule(map, this);
    262.  
    263.         if(rules.perlinNoise.applyRule) rules.perlinNoise.ApplyRule(map, this);
    264.  
    265.         if(rules.customFunction.applyRule) rules.customFunction.ApplyRule(map, this);
    266.  
    267.         if(rules.quadratic.applyRule) rules.quadratic.ApplyRule(map, this);
    268.  
    269.         if(rules.logOfXPlusY.applyRule) rules.logOfXPlusY.ApplyRule(map, this);
    270.         if(rules.logOfXTimesY.applyRule) rules.logOfXTimesY.ApplyRule(map, this);
    271.         if(rules.logOfXToTheYthPower.applyRule) rules.logOfXToTheYthPower.ApplyRule(map, this);
    272.  
    273.         if(rules.sinOfXPlusY.applyRule) rules.sinOfXPlusY.ApplyRule(map, this);
    274.         if(rules.sinOfXTimesY.applyRule) rules.sinOfXTimesY.ApplyRule(map, this);
    275.         if(rules.sinofXToTheYthPower.applyRule) rules.sinofXToTheYthPower.ApplyRule(map, this);
    276.  
    277.         if(rules.cosOfXPlusY.applyRule) rules.cosOfXPlusY.ApplyRule(map, this);
    278.         if(rules.cosOfXTimesY.applyRule) rules.cosOfXTimesY.ApplyRule(map, this);
    279.         if(rules.cosOfXToTheYthPower.applyRule) rules.cosOfXToTheYthPower.ApplyRule(map, this);
    280.  
    281.         if(rules.tanOfXPlusY.applyRule) rules.tanOfXPlusY.ApplyRule(map, this);
    282.         if(rules.tanOfXTimesY.applyRule) rules.tanOfXTimesY.ApplyRule(map, this);
    283.         if(rules.tanOfXToTheYthPower.applyRule) rules.tanOfXToTheYthPower.ApplyRule(map, this);
    284.     }
    285.     /// <summary>
    286.     /// This method will look at all of the surrounding indices of a given index and see how have a value of 1 (how many are solid).
    287.     /// </summary>
    288.     /// <returns>The surrounding wall count.</returns>
    289.     /// <param name = "indexX">Index x.</param>
    290.     /// <param name = "indexY">Index y.</param>
    291.     public int GetSurroundingWallCount(int indexX, int indexY)
    292.     {
    293.         //This variable will store the amount of surrounding indices that are solid
    294.         int wallCount = 0;
    295.        
    296.         //A 3x3 grid centered on (indexX, indexY) is looped through
    297.         //Each index is checked to see if it is equal to 1
    298.         for(int nX = (indexX - 1); nX <= indexX + 1; nX++)
    299.         {
    300.             for(int nY = (indexY - 1); nY <= indexY + 1; nY++)
    301.             {
    302.                 //Because the surrounding indices will be looped through,
    303.                 //the current index cannot be on the edge of the map or in a corner, if it was Unity would give a null error
    304.                
    305.                 //If this isn't an edge tile-
    306.                 if(IsInMapRange(nX, nY, true))
    307.                 {
    308.                     //If the current index isn't the middle one (the one who's neighbors are being checked)-
    309.                     if(nX != indexX || nY != indexY)
    310.                     {
    311.                         //If the current index is 1, 1 will be added
    312.                         //If it is 0, 0 will be added
    313.                         wallCount += map[nX, nY];
    314.                     }
    315.                 }
    316.                 //Otherwise-
    317.                 else
    318.                     //The amount of surrounding walls will be increased
    319.                     wallCount++;
    320.             }
    321.         }
    322.         return wallCount;
    323.     }
    324.     private List<List<Coord>> GetRegions(int tileType)
    325.     {
    326.         //This is the list of lists of Coords that we'll return
    327.         List<List<Coord>> regions = new List<List<Coord>>();
    328.         //This int array will hold all of the tile indices, and whether or not they've been checked (1 = checked, 0 = unchecked)
    329.         int[,] checkedTiles = new int[width, height];
    330.  
    331.         //Here we'll loop through all of the indices in the map
    332.         for(int x = 0; x < width; x++)
    333.         {
    334.             for(int y = 0; y < height; y++)
    335.             {
    336.                 //If the current tile hasn't been checked and it's the correct tileType...
    337.                 if(checkedTiles[x, y] == 0 && map[x, y] == tileType)
    338.                 {
    339.                     //...We'll create a list of Coords and start the flood-fill algorithm at the current indice's position
    340.                     List<Coord> newRegion = GetRegionTiles(x, y);
    341.                     //...Then we'll add the region we just created to the list of regions
    342.                     regions.Add(newRegion);
    343.                     //...After adding the region, we can intereate through all of it's Coords
    344.                     foreach(Coord tile in newRegion)
    345.                     {
    346.                         //...Add set there corresponding indices in the checkTiles array to equal one (they'll be marked as checked)
    347.                         checkedTiles[tile.x, tile.y] = 1;
    348.                     }
    349.                 }
    350.             }
    351.         }
    352.         return regions;
    353.     }
    354.     private List<Coord> GetRegionTiles(int startX, int startY)
    355.     {
    356.         List<Coord> tiles = new List<Coord>();
    357.         //This int array will hold all of the tile indices, and whether or not they've been checked (1 = checked, 0 = unchecked)
    358.         int[,] checkedTiles = new int[width, height];
    359.         //The type of tile to be added to the list of Coords
    360.         int tileType = map[startX, startY];
    361.         //A queue of coordinates to process
    362.         Queue<Coord> queue = new Queue<Coord>();
    363.         //The first tile to be queued up is the start tile
    364.         queue.Enqueue(new Coord(startX, startY));
    365.         //We'll also set the start tile's index to equal one, marking it as checked
    366.         checkedTiles[startX, startY] = 1;
    367.  
    368.         //While we have items in our queue...
    369.         while(queue.Count > 0)
    370.         {
    371.             //Here we'll create a Coord and set it equal to the oldest item in the queue while simultaneously removing the queue
    372.             Coord tile = queue.Dequeue();
    373.             //Then we'll add the Coord we just created to the list of Coords that we'll return
    374.             tiles.Add(tile);
    375.             //Here we loop through the neighbors above, below, to the right, and to the left
    376.             for(int x = tile.x - 1; x <= tile.x + 1; x++)
    377.             {
    378.                 for(int y = tile.y - 1; y <= tile.y + 1; y++)
    379.                 {
    380.                     //If the current tile index is actually in the map...
    381.                     if(IsInMapRange(x, y, true) && (y == tile.y || x == tile.x))
    382.                     {
    383.                         //...Then, if this tile hasn't been looked at yet and it's the correct tileType
    384.                         if(checkedTiles[x, y] == 0 && map[x, y] == tileType)
    385.                         {
    386.                             //...We'll set it's index in the checkedTiles array to one, indicating that it's been looked at
    387.                             checkedTiles[x, y] = 1;
    388.                             //...And add the Coord to the queue
    389.                             queue.Enqueue(new Coord(x, y));
    390.                         }
    391.                     }
    392.                 }
    393.             }
    394.         }
    395.         return tiles;
    396.     }
    397.     private bool IsInMapRange(int x, int y, bool bordersAreOutOfMap)
    398.     {
    399.         if(bordersAreOutOfMap)
    400.             return x >= edgeWidth && x < width - edgeWidth && y >= edgeWidth && y < height - edgeWidth;
    401.         else
    402.             return x >= 0 && x < width && y >= 0 && y < height;
    403.     }
    404.     public struct Coord
    405.     {
    406.         public int x, y;
    407.  
    408.         public Coord(int x, int y)
    409.         {
    410.             this.x = x;
    411.             this.y = y;
    412.         }
    413.     }
    414.     ///<summary>
    415.     /// This class holds information about a room
    416.     /// </summary>
    417.     public class Room
    418.     {
    419.         /// <summary>
    420.         /// A list of all the tiles in this room.
    421.         /// </summary>
    422.         public List<Coord> tiles;
    423.         /// <summary>
    424.         /// A list of all of the edge tiles.
    425.         /// </summary>
    426.         public List<Coord> edgeTiles;
    427.         /// <summary>
    428.         /// A list of rooms that share a common passage with this room.
    429.         /// </summary>
    430.         public List<Room> connectedRooms;
    431.         /// <summary>
    432.         /// The number of tiles that are in this room
    433.         /// </summary>
    434.         public int roomSize;
    435.  
    436.         /// <summary>
    437.         /// Initializes an empty instance of the <see cref = "MapGenerator+Room"/> class.
    438.         /// </summary>
    439.         public Room(){}
    440.         /// <summary>
    441.         /// Initializes a new instance of the <see cref = "MapGenerator+Room"/> class, with parameters.
    442.         /// </summary>
    443.         /// <param name = "roomTiles">Room tiles.</param>
    444.         /// <param name = "map">Map.</param>
    445.         public Room(List<Coord> roomTiles, int[,] map)
    446.         {
    447.             //We'll initialize set up all of the variables
    448.             tiles = roomTiles;
    449.             roomSize = tiles.Count;
    450.             connectedRooms = new List<Room>();
    451.  
    452.             edgeTiles = new List<Coord>();
    453.             //Here we'll loop through every tile in the room
    454.             foreach(Coord tile in tiles)
    455.             {
    456.                 //Then we'll index through the four neighbors of the current tle index
    457.                 for(int x = tile.x - 1; x <= tile.x + 1; x++)
    458.                 {
    459.                     for(int y = tile.y - 1; y <= tile.y + 1; y++)
    460.                     {
    461.                         //...If the tiles x or y value is equal to the current tile's...
    462.                         if(x == tile.x || y == tile.y)
    463.                         {
    464.                             //...Then we know it isn't diagonal to the current tile index
    465.                             //...And if it is a wall tile
    466.                             if(map[x, y] == 1)
    467.                             {
    468.                                 //...We'll know it's an edge tile and can add it to the list of edge tiles
    469.                                 edgeTiles.Add(tile);
    470.                             }
    471.                         }
    472.                     }
    473.                 }
    474.             }
    475.         }
    476.         public static void ConnectRooms(Room roomA, Room roomB)
    477.         {
    478.             roomA.connectedRooms.Add(roomB);
    479.             roomB.connectedRooms.Add(roomA);
    480.         }
    481.         public bool IsConnected(Room otherRoom)
    482.         {
    483.             return connectedRooms.Contains(otherRoom);
    484.         }
    485.     }
    486.     [Serializable]
    487.     public class Rules
    488.     {
    489.         [SerializeField]
    490.         public Lague lague;
    491.         [SerializeField]
    492.         public MazeWorld mazeWorld;
    493.         [SerializeField]
    494.         public GameOfLife gameOfLife;
    495.  
    496.         [SerializeField]
    497.         public PerlinNoise perlinNoise;
    498.  
    499.         [SerializeField]
    500.         public CustomFunction customFunction;
    501.  
    502.         [SerializeField]
    503.         public Quadratic quadratic;
    504.  
    505.         [SerializeField]
    506.         public LogOfXPlusY logOfXPlusY;
    507.         [SerializeField]
    508.         public LogOfXTimesY logOfXTimesY;
    509.         [SerializeField]
    510.         public LogOfXToTheYthPower logOfXToTheYthPower;
    511.  
    512.         [SerializeField]
    513.         public SinOfXPlusY sinOfXPlusY;
    514.         [SerializeField]
    515.         public SinOfXTimesY sinOfXTimesY;
    516.         [SerializeField]
    517.         public SinOfXToTheYthPower sinofXToTheYthPower;
    518.  
    519.         [SerializeField]
    520.         public SinOfXPlusY cosOfXPlusY;
    521.         [SerializeField]
    522.         public SinOfXTimesY cosOfXTimesY;
    523.         [SerializeField]
    524.         public SinOfXToTheYthPower cosOfXToTheYthPower;
    525.  
    526.         [SerializeField]
    527.         public SinOfXPlusY tanOfXPlusY;
    528.         [SerializeField]
    529.         public SinOfXTimesY tanOfXTimesY;
    530.         [SerializeField]
    531.         public TanOfXToTheYthPower tanOfXToTheYthPower;
    532.  
    533.         [Serializable]
    534.         public class Lague
    535.         {
    536.             public bool applyRule = false;
    537.             public int iterations = 1;
    538.  
    539.             [Range(0, 8)]
    540.             public int surroundingWallCountToBeSolid = 4;
    541.  
    542.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    543.             {
    544.                 if(applyRule)
    545.                 {
    546.                     iterations = Mathf.Clamp(iterations, 1, Int32.MaxValue);
    547.                     for(int i = 0; i < iterations; i++)
    548.                     {
    549.                         for(int x = 0; x < map.GetLength(0); x++)
    550.                         {
    551.                             for(int y = 0; y < map.GetLength(1); y++)
    552.                             {
    553.                                 //We want to know how many neighboring tiles does the current tile index have that are walls
    554.                                 //This will be found via the method GetSurroundingWallCount below
    555.                                 int surroundingWalls = mapGenerator.GetSurroundingWallCount(x, y);
    556.                                
    557.                                 //If the current index is surrounded by a certain amount (ruleValue) of solid tiles it'll be made solid as well
    558.                                 if(surroundingWalls > surroundingWallCountToBeSolid)
    559.                                     map[x, y] = 1;
    560.                                 //Otherwise it'll be made empty, set to 0
    561.                                 else if(surroundingWalls < surroundingWallCountToBeSolid)
    562.                                     map[x, y] = 0;
    563.                             }
    564.                         }
    565.                     }
    566.                 }
    567.                 return;
    568.             }
    569.         }
    570.         [Serializable]
    571.         public class MazeWorld
    572.         {
    573.             public bool applyRule = false;
    574.             public int iterations = 5;
    575.  
    576.             [Range(0, 8)]
    577.             public int neutralNeighborCount = 2;
    578.  
    579.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    580.             {
    581.                 if(applyRule)
    582.                 {
    583.                     iterations = Mathf.Clamp(iterations, 1, Int32.MaxValue);
    584.                     for(int i = 0; i < iterations; i++)
    585.                     {
    586.                         for(int x = 0; x < map.GetLength(0); x++)
    587.                         {
    588.                             for(int y = 0; y < map.GetLength(1); y++)
    589.                             {
    590.                                 //We want to know how many neighboring tiles the current tile index has that are walls
    591.                                 //This will be found via the method GetSurroundingWallCount below
    592.                                 int surroundingWalls = mapGenerator.GetSurroundingWallCount(x, y);
    593.                                
    594.                                 //If the cell is solid-
    595.                                 if(map[x, y] == 1)
    596.                                 {
    597.                                     //If the cell has less than 2 neighbors-
    598.                                     if(surroundingWalls < (neutralNeighborCount - 1))
    599.                                         //It will be made empty (as if caused by under-population)
    600.                                         map[x, y] = 0;
    601.                                     //Otherwise, if the cell has 2 or 3 neighbors-
    602.                                     else if(surroundingWalls > (neutralNeighborCount - 1) && neutralNeighborCount < 4)
    603.                                         //The cell will be made solid (as if it lived on to the next generation)
    604.                                         map[x, y] = 1;
    605.                                     //Otherwise, the cell has more than three neighbors-
    606.                                     else
    607.                                         //And it will be made empty (as if by over-population)
    608.                                         map[x, y] = 0;
    609.                                 }
    610.                                 //Otherwise, the index is empty
    611.                                 else
    612.                                     //If the cell has 3 neighbors
    613.                                     if(surroundingWalls == neutralNeighborCount)
    614.                                         //It will be made solid (as if by reproduction)
    615.                                         map[x, y] = 1;
    616.                             }
    617.                         }
    618.                     }
    619.                 }
    620.                 return;
    621.             }
    622.         }
    623.         [Serializable]
    624.         public class GameOfLife
    625.         {
    626.             public bool applyRule = false;
    627.             public int iterations = 1;
    628.  
    629.             [Range(0, 8)]
    630.             public int neutralNeighborCount = 3;
    631.  
    632.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    633.             {
    634.                 iterations = Mathf.Clamp(iterations, 1, Int32.MaxValue);
    635.                 if(applyRule)
    636.                 {
    637.                     for(int i = 0; i < iterations; i++)
    638.                     {
    639.                         for(int x = 0; x < map.GetLength(0); x++)
    640.                         {
    641.                             for(int y = 0; y < map.GetLength(1); y++)
    642.                             {
    643.                                 //We want to know how many neighboring tiles does the current tile index have that are walls
    644.                                 //This will be found via the method GetSurroundingWallCount below
    645.                                 int surroundingWalls = mapGenerator.GetSurroundingWallCount(x, y);
    646.                                
    647.                                 //If the cell is solid-
    648.                                 if(map[x, y] == 1)
    649.                                 {
    650.                                     //If the cell has less than 2 neighbors-
    651.                                     if(surroundingWalls < (neutralNeighborCount - 1))
    652.                                         //It will be made empty (as if caused by under-population)
    653.                                         map[x, y] = 0;
    654.                                     //Otherwise, if the cell has 2 or 3 neighbors-
    655.                                     else if(surroundingWalls > (neutralNeighborCount - 1) && surroundingWalls < (neutralNeighborCount + 1))
    656.                                         //The cell will be made solid (as if it lived on to the next generation)
    657.                                         map[x, y] = 1;
    658.                                     //Otherwise, the cell has more than three neighbors-
    659.                                     else
    660.                                         //And it will be made empty (as if by over-population)
    661.                                         map[x, y] = 1;
    662.                                 }
    663.                                 //Otherwise, the index is empty
    664.                                 else
    665.                                     //If the cell has 3 neighbors
    666.                                     if(surroundingWalls > (neutralNeighborCount - 1) && surroundingWalls < (neutralNeighborCount + 1))
    667.                                         //It will be made solid (as if by reproduction)
    668.                                         map[x, y] = 1;
    669.                             }
    670.                         }
    671.                     }
    672.                 }
    673.             }
    674.         }
    675.         [Serializable]
    676.         public class PerlinNoise
    677.         {
    678.             public bool applyRule = false;
    679.  
    680.             public bool erase;
    681.             public Vector2 position;
    682.             public float scale = 10f;
    683.  
    684.             [Range(0f, 1f)]
    685.             public float bias = 0.5f;
    686.            
    687.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    688.             {
    689.                 if(applyRule)
    690.                 {
    691.                     scale = Mathf.Clamp(scale, 1f, float.MaxValue);
    692.                     for(int x = 0; x < map.GetLength(0); x++)
    693.                     {
    694.                         for(int y = 0; y < map.GetLength(1); y++)
    695.                         {
    696.                             float value = Mathf.PerlinNoise((x + position.x) / scale, (y + position.y) / scale);
    697.                            
    698.                             if(value > bias)
    699.                             {
    700.                                 if(erase)
    701.                                     map[x, y] = 0;
    702.                                 else
    703.                                     map[x, y] = 1;
    704.                             }
    705.                         }
    706.                     }
    707.                 }
    708.             }
    709.         }  
    710.         [Serializable]
    711.         public class CustomFunction
    712.         {
    713.             public bool applyRule = false;
    714.  
    715.             public bool erase = false;
    716.             [Range(-100, 100)]
    717.             public int xExponent = 1;
    718.  
    719.             public Operator mathOperator;
    720.  
    721.             [Range(-100, 100)]
    722.             public int yExponent = 1;
    723.  
    724.             public enum Operator
    725.             {
    726.                 Add,
    727.                 Multiply,
    728.                 Exponent
    729.             }
    730.             public float bias = 0.5f;
    731.            
    732.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    733.             {
    734.                 if(applyRule)
    735.                 {
    736.                     for(int x = 0; x < map.GetLength(0); x++)
    737.                     {
    738.                         for(int y = 0; y < map.GetLength(1); y++)
    739.                         {
    740.                             float value;
    741.  
    742.                             switch(mathOperator)
    743.                             {
    744.                                 case Operator.Add:
    745.                                     value = (x ^ xExponent) + (y ^ yExponent);
    746.                                     break;
    747.                                 case Operator.Multiply:
    748.                                     value = (x ^ xExponent) * (y ^ yExponent);
    749.                                     break;
    750.                                 case Operator.Exponent:
    751.                                     value = (x ^ xExponent) ^ (y ^ yExponent);
    752.                                     break;
    753.                                 default:
    754.                                     value = 1;
    755.                                     break;
    756.                             }
    757.                            
    758.                             if(value > bias)
    759.                             {
    760.                                 if(erase)
    761.                                     map[x, y] = 0;
    762.                                 else
    763.                                     map[x, y] = 1;
    764.                             }
    765.                         }
    766.                     }
    767.                 }
    768.             }
    769.         }
    770.         [Serializable]
    771.         public class Quadratic
    772.         {
    773.             public bool applyRule = false;
    774.  
    775.             public bool erase = false;
    776.             [Range(-350f, 0f)]
    777.             public float curve = 1f;
    778.            
    779.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    780.             {
    781.                 if(applyRule)
    782.                 {
    783.                     for(int x = 0; x < map.GetLength(0); x++)
    784.                     {
    785.                         for(int y = 0; y < map.GetLength(1); y++)
    786.                         {
    787.                             float value = ((-y + (Mathf.Sqrt((y^2) - 4 * x * curve)))/(2 * x));
    788.                            
    789.                             if(value > 0.5f)
    790.                             {
    791.                                 if(erase)
    792.                                     map[x, y] = 0;
    793.                                 else
    794.                                     map[x, y] = 1;
    795.                             }
    796.                         }
    797.                     }
    798.                 }
    799.             }
    800.         }
    801.         [Serializable]
    802.         public class LogOfXPlusY
    803.         {
    804.             public bool applyRule = false;
    805.  
    806.             public bool erase = false;
    807.             [Range(1f, 5f)]
    808.             public float bias = 0.5f;
    809.  
    810.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    811.             {
    812.                 if(applyRule)
    813.                 {
    814.                     for(int x = 0; x < map.GetLength(0); x++)
    815.                     {
    816.                         for(int y = 0; y < map.GetLength(1); y++)
    817.                         {
    818.                             float value = Mathf.Log(x + y);
    819.                            
    820.                             if(value > bias)
    821.                             {
    822.                                 if(erase)
    823.                                     map[x, y] = 0;
    824.                                 else
    825.                                     map[x, y] = 1;
    826.                             }
    827.                         }
    828.                     }
    829.                 }
    830.             }
    831.         }
    832.         [Serializable]
    833.         public class LogOfXTimesY
    834.         {
    835.             public bool applyRule = false;
    836.  
    837.             //[Range(0f, 5f)]
    838.             public float bias = 0.5f;
    839.            
    840.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    841.             {
    842.                 if(applyRule)
    843.                 {
    844.                     for(int x = 0; x < map.GetLength(0); x++)
    845.                     {
    846.                         for(int y = 0; y < map.GetLength(1); y++)
    847.                         {
    848.                             float value = Mathf.Log(x * y);
    849.                            
    850.                             if(value > bias)
    851.                                 map[x, y] = 1;
    852.                         }
    853.                     }
    854.                 }
    855.             }
    856.         }
    857.         [Serializable]
    858.         public class LogOfXToTheYthPower
    859.         {
    860.             public bool applyRule = false;
    861.  
    862.             //[Range(0f, 5f)]
    863.             public float bias = 0.5f;
    864.            
    865.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    866.             {
    867.                 if(applyRule)
    868.                 {
    869.                     for(int x = 0; x < map.GetLength(0); x++)
    870.                     {
    871.                         for(int y = 0; y < map.GetLength(1); y++)
    872.                         {
    873.                             float value = Mathf.Log(x ^ y);
    874.                            
    875.                             if(value > bias)
    876.                                 map[x, y] = 1;
    877.                         }
    878.                     }
    879.                 }
    880.             }
    881.         }
    882.         [Serializable]
    883.         public class SinOfXPlusY
    884.         {
    885.             public bool applyRule = false;
    886.  
    887.             public bool erase = false;
    888.             [Range(0f, 1f)]
    889.             public float bias = 0.5f;
    890.            
    891.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    892.             {
    893.                 if(applyRule)
    894.                 {
    895.                     for(int x = 0; x < map.GetLength(0); x++)
    896.                     {
    897.                         for(int y = 0; y < map.GetLength(1); y++)
    898.                         {
    899.                             float value = Mathf.Sin(x + y);
    900.  
    901.                             if(value > bias)
    902.                             {
    903.                                 if(erase)
    904.                                     map[x, y] = 0;
    905.                                 else
    906.                                     map[x, y] = 1;
    907.                             }
    908.                         }
    909.                     }
    910.                 }
    911.             }
    912.         }
    913.         [Serializable]
    914.         public class SinOfXTimesY
    915.         {
    916.             public bool applyRule = false;
    917.  
    918.             public bool erase = false;
    919.             [Range(0f, 1f)]
    920.             public float bias = 0.5f;
    921.            
    922.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    923.             {
    924.                 if(applyRule)
    925.                 {
    926.                     for(int x = 0; x < map.GetLength(0); x++)
    927.                     {
    928.                         for(int y = 0; y < map.GetLength(1); y++)
    929.                         {
    930.                             float value = Mathf.Sin(x * y);
    931.  
    932.                             if(value > bias)
    933.                             {
    934.                                 if(erase)
    935.                                     map[x, y] = 0;
    936.                                 else
    937.                                     map[x, y] = 1;
    938.                             }
    939.                         }
    940.                     }
    941.                 }
    942.             }
    943.         }
    944.         [Serializable]
    945.         public class SinOfXToTheYthPower
    946.         {
    947.             public bool applyRule = false;
    948.  
    949.             public bool erase = false;
    950.             [Range(0f, 1f)]
    951.             public float bias = 0.5f;
    952.            
    953.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    954.             {
    955.                 if(applyRule)
    956.                 {
    957.                     for(int x = 0; x < map.GetLength(0); x++)
    958.                     {
    959.                         for(int y = 0; y < map.GetLength(1); y++)
    960.                         {
    961.                             float value = Mathf.Sin(x ^ y);
    962.  
    963.                             if(value > bias)
    964.                             {
    965.                                 if(erase)
    966.                                     map[x, y] = 0;
    967.                                 else
    968.                                     map[x, y] = 1;
    969.                             }
    970.                         }
    971.                     }
    972.                 }
    973.             }
    974.         }
    975.         [Serializable]
    976.         public class CosOfXPlusY
    977.         {
    978.             public bool applyRule = false;
    979.  
    980.             public bool erase = false;
    981.             [Range(0f, 1f)]
    982.             public float bias = 0.5f;
    983.            
    984.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    985.             {
    986.                 if(applyRule)
    987.                 {
    988.                     for(int x = 0; x < map.GetLength(0); x++)
    989.                     {
    990.                         for(int y = 0; y < map.GetLength(1); y++)
    991.                         {
    992.                             float value = Mathf.Cos(x + y);
    993.  
    994.                             if(value > bias)
    995.                             {
    996.                                 if(erase)
    997.                                     map[x, y] = 0;
    998.                                 else
    999.                                     map[x, y] = 1;
    1000.                             }
    1001.                         }
    1002.                     }
    1003.                 }
    1004.             }
    1005.         }
    1006.         [Serializable]
    1007.         public class CosOfXTimesY
    1008.         {
    1009.             public bool applyRule = false;
    1010.  
    1011.             public bool erase = false;
    1012.             [Range(0f, 1f)]
    1013.             public float bias = 0.5f;
    1014.            
    1015.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    1016.             {
    1017.                 if(applyRule)
    1018.                 {
    1019.                     for(int x = 0; x < map.GetLength(0); x++)
    1020.                     {
    1021.                         for(int y = 0; y < map.GetLength(1); y++)
    1022.                         {
    1023.                             float value = Mathf.Cos(x * y);
    1024.  
    1025.                             if(value > bias)
    1026.                             {
    1027.                                 if(erase)
    1028.                                     map[x, y] = 0;
    1029.                                 else
    1030.                                     map[x, y] = 1;
    1031.                             }
    1032.                         }
    1033.                     }
    1034.                 }
    1035.             }
    1036.         }
    1037.         [Serializable]
    1038.         public class CosOfXToTheYthPower
    1039.         {
    1040.             public bool applyRule = false;
    1041.  
    1042.             public bool erase = false;
    1043.             [Range(0f, 1f)]
    1044.             public float bias = 0.5f;
    1045.            
    1046.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    1047.             {
    1048.                 if(applyRule)
    1049.                 {
    1050.                     for(int x = 0; x < map.GetLength(0); x++)
    1051.                     {
    1052.                         for(int y = 0; y < map.GetLength(1); y++)
    1053.                         {
    1054.                             float value = Mathf.Cos(x ^ y);
    1055.  
    1056.                             if(value > bias)
    1057.                             {
    1058.                                 if(erase)
    1059.                                     map[x, y] = 0;
    1060.                                 else
    1061.                                     map[x, y] = 1;
    1062.                             }
    1063.                         }
    1064.                     }
    1065.                 }
    1066.             }
    1067.         }
    1068.         [Serializable]
    1069.         public class TanOfXPlusY
    1070.         {
    1071.             public bool applyRule = false;
    1072.            
    1073.             public bool erase = false;
    1074.             [Range(0f, 1f)]
    1075.             public float bias = 0.5f;
    1076.            
    1077.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    1078.             {
    1079.                 if(applyRule)
    1080.                 {
    1081.                     for(int x = 0; x < map.GetLength(0); x++)
    1082.                     {
    1083.                         for(int y = 0; y < map.GetLength(1); y++)
    1084.                         {
    1085.                             float value = Mathf.Tan(x + y);
    1086.                            
    1087.                             if(value > bias)
    1088.                             {
    1089.                                 if(erase)
    1090.                                     map[x, y] = 0;
    1091.                                 else
    1092.                                     map[x, y] = 1;
    1093.                             }
    1094.                         }
    1095.                     }
    1096.                 }
    1097.             }
    1098.         }
    1099.         [Serializable]
    1100.         public class TanOfXTimesY
    1101.         {
    1102.             public bool applyRule = false;
    1103.            
    1104.             public bool erase = false;
    1105.             [Range(0f, 1f)]
    1106.             public float bias = 0.5f;
    1107.            
    1108.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    1109.             {
    1110.                 if(applyRule)
    1111.                 {
    1112.                     for(int x = 0; x < map.GetLength(0); x++)
    1113.                     {
    1114.                         for(int y = 0; y < map.GetLength(1); y++)
    1115.                         {
    1116.                             float value = Mathf.Tan(x * y);
    1117.                            
    1118.                             if(value > bias)
    1119.                             {
    1120.                                 if(erase)
    1121.                                     map[x, y] = 0;
    1122.                                 else
    1123.                                     map[x, y] = 1;
    1124.                             }
    1125.                         }
    1126.                     }
    1127.                 }
    1128.             }
    1129.         }
    1130.         [Serializable]
    1131.         public class TanOfXToTheYthPower
    1132.         {
    1133.             public bool applyRule = false;
    1134.            
    1135.             public bool erase = false;
    1136.             [Range(0f, 1f)]
    1137.             public float bias = 0.5f;
    1138.            
    1139.             public void ApplyRule(int[,] map, MapGenerator mapGenerator)
    1140.             {
    1141.                 if(applyRule)
    1142.                 {
    1143.                     for(int x = 0; x < map.GetLength(0); x++)
    1144.                     {
    1145.                         for(int y = 0; y < map.GetLength(1); y++)
    1146.                         {
    1147.                             float value = Mathf.Tan(x ^ y);
    1148.                            
    1149.                             if(value > bias)
    1150.                             {
    1151.                                 if(erase)
    1152.                                     map[x, y] = 0;
    1153.                                 else
    1154.                                     map[x, y] = 1;
    1155.                             }
    1156.                         }
    1157.                     }
    1158.                 }
    1159.             }
    1160.         }
    1161.     }
    1162. }
     
  2. SebastianLague

    SebastianLague

    Joined:
    Aug 31, 2014
    Posts:
    111
    Hi there. The error is occurring because it is searching for neighbour tiles outside of the map bounds. This is because in your implementation rooms can extend right to the edge of the map. I recommend changing the code inside the for loops of the RandomFillMap method to this:

    Code (CSharp):
    1.     // Ensure that all rooms are enclosed in the map area
    2.     if (x == 0 || x == width-1 || y == 0 || y == height -1) {
    3.         map[x,y] = 1;
    4.     }
    5.     else {
    6.     //Using the if/else notation, the current index will be set to 1 if the generated number is less than fillPercentage,
    7.     //otherwise it will be set to 0
    8.         map[x, y] = (prng.Next(0, 100) < fillPercentage) ? 1 : 0;
    9.     }
     
    Mashimaro7 likes this.
  3. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    597
    Code (CSharp):
    1.  
    2. if(x == tile.x || y == tile.y)
    3. {
    4.    //The error points to the line below
    5.    if(map[x, y] == 1)
    6.    {
    7.       edgeTiles.Add(tile);
    8.    }
    9. }
    10.  
     
  4. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    597
    Ok, so I changed the Rule constructor code to check if the current tile exists. But now if I change the minWallRegion (wallRegionThreshold), Unity freezes. Does it have to do with the while-loop? Do I need to clear the queue outside of the while-loop so that when I call the method on the next frame it doesn't add the same stuff to it again? Though, I guess clearing the queue will prevent it from doing anything
    Code (csharp):
    1.  
    2. public class Room
    3.     {
    4.         /// <summary>
    5.         /// A list of all the tiles in this room.
    6.         /// </summary>
    7.         public List<Coord> tiles;
    8.         /// <summary>
    9.         /// A list of all of the edge tiles.
    10.         /// </summary>
    11.         public List<Coord> edgeTiles;
    12.         /// <summary>
    13.         /// A list of rooms that share a common passage with this room.
    14.         /// </summary>
    15.         public List<Room> connectedRooms;
    16.         /// <summary>
    17.         /// The number of tiles that are in this room
    18.         /// </summary>
    19.         public int roomSize;
    20.  
    21.         /// <summary>
    22.         /// Initializes an empty instance of the <see cref = "MapGenerator+Room"/> class.
    23.         /// </summary>
    24.         public Room(){}
    25.         /// <summary>
    26.         /// Initializes a new instance of the <see cref = "MapGenerator+Room"/> class, with parameters.
    27.         /// </summary>
    28.         /// <param name = "roomTiles">Room tiles.</param>
    29.         /// <param name = "map">Map.</param>
    30.         public Room(List<Coord> roomTiles, int[,] map, int edgeWidth)
    31.         {
    32.             //We'll initialize set up all of the variables
    33.             tiles = roomTiles;
    34.             roomSize = tiles.Count;
    35.             connectedRooms = new List<Room>();
    36.  
    37.             edgeTiles = new List<Coord>();
    38.             //Here we'll loop through every tile in the room
    39.             foreach(Coord tile in tiles)
    40.             {
    41.                 //Then we'll index through the four neighbors of the current tle index
    42.                 for(int x = tile.x - 1; x <= tile.x + 1; x++)
    43.                 {
    44.                     for(int y = tile.y - 1; y <= tile.y + 1; y++)
    45.                     {
    46.                         if(x < map.GetLength(0) - edgeWidth && x >= edgeWidth && y < map.GetLength(1) - edgeWidth && y >= edgeWidth)
    47.                         {
    48.                             //...If the tiles x or y value is equal to the current tile's...
    49.                             if(x == tile.x || y == tile.y)
    50.                             {
    51.                                 //...Then we know it isn't diagonal to the current tile index
    52.                                 //...And if it is a wall tile
    53.                                 if(map[x, y] == 1)
    54.                                 {
    55.                                     //...We'll know it's an edge tile and can add it to the list of edge tiles
    56.                                     edgeTiles.Add(tile);
    57.                                 }
    58.                             }
    59.                         }
    60.                     }
    61.                 }
    62.             }
    63.         }
    64.         public static void ConnectRooms(Room roomA, Room roomB)
    65.         {
    66.             roomA.connectedRooms.Add(roomB);
    67.             roomB.connectedRooms.Add(roomA);
    68.         }
    69.         public bool IsConnected(Room otherRoom)
    70.         {
    71.             return connectedRooms.Contains(otherRoom);
    72.         }
    73.     }
     
  5. SebastianLague

    SebastianLague

    Joined:
    Aug 31, 2014
    Posts:
    111
    I'll have a look in the morning, but did you try making the change I suggested? Because that is the root of this error.
     
  6. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    597
    Yeah I did, but I still got the error. I'll try adding it back and seeing if your change, accompanied with mine, fixes it. Once again, I really appreciate your help :)
    [Edit]
    I removed my added code which stops Unity from freezing, but I'm now getting the error again. Here's the error, just in-case it has changed:
    IndexOutOfRangeException: Array index is out of range.
    MapGenerator+Room..ctor (System.Collections.Generic.List`1 roomTiles, System.Int32[,] map, Int32 edgeWidth) (at Assets/Code/Cave Generation/MapGenerator.cs:476)
    MapGenerator.ProcessRooms () (at Assets/Code/Cave Generation/MapGenerator.cs:159)
    MapGenerator.GenerateMap () (at Assets/Code/Cave Generation/MapGenerator.cs:107)
    MapGenerator.Update () (at Assets/Code/Cave Generation/MapGenerator.cs:92)
     
    Last edited: May 4, 2015
  7. lexagon41

    lexagon41

    Joined:
    Jun 15, 2019
    Posts:
    1
    hi when i did the same code that you did in episode 1, the caves wouldn't even show, the screen just darkened and after a few seconds it switched to gamer view but there was no map. is there anything i could do to help the code work?
     
  8. Vivraan

    Vivraan

    Joined:
    Feb 2, 2018
    Posts:
    26
    The issue I run into is
    • The debug lines never show up
    • Index out of range is thrown seemingly randomly, and always from within
      ConnectClosestRooms
      - the chance increases for higher fill percent and reduces if region size thresholds are provided
    The offending code (haven't placed breakpoints to debug yet) is:

    Code (CSharp):
    1.  
    2. private void ProcessRooms(in int wallSizeThreshold, in int roomSizeThreshold)
    3. {
    4.     var wallRegions = GetRegions(TileType.Wall);
    5.  
    6.     foreach (var wallRegion in wallRegions)
    7.     {
    8.         if (wallRegion.Count < wallSizeThreshold)
    9.         {
    10.             foreach (var tile in wallRegion)
    11.             {
    12.                 map[tile.x, tile.y] = TileType.Room;
    13.             }
    14.         }
    15.     }
    16.  
    17.     var roomRegions = GetRegions(TileType.Room);
    18.     var survivingRooms = new List<Room>();
    19.  
    20.     foreach (var roomRegion in roomRegions)
    21.     {
    22.         if (roomRegion.Count < roomSizeThreshold)
    23.         {
    24.             foreach (var tile in roomRegion)
    25.             {
    26.                 map[tile.x, tile.y] = TileType.Wall;
    27.             }
    28.         }
    29.         else
    30.         {
    31.             survivingRooms.Add(new Room(roomRegion, map));
    32.         }
    33.     }
    34.     ConnectClosestRooms(survivingRooms);
    35. }
    36.  
    37. void ConnectClosestRooms(in List<Room> allRooms)
    38. {
    39.     int bestDistance = 0;
    40.     (int x, int y) bestTileA = (0, 0), bestTileB = (0, 0);
    41.     var bestRoomA = new Room();
    42.     var bestRoomB = new Room();
    43.     bool possibleConnectionFound = false;
    44.  
    45.     foreach (var roomA in allRooms)
    46.     {
    47.         possibleConnectionFound = false;
    48.  
    49.         foreach (var roomB in allRooms)
    50.         {
    51.             if (roomA.IsConnected(roomB))
    52.             {
    53.                 possibleConnectionFound = false;
    54.                 break;
    55.             }
    56.             if (roomA != roomB)
    57.             {
    58.                 for (int tileIndexA = 0; tileIndexA < roomA.edgeTiles.Count; ++tileIndexA)
    59.                 {
    60.                     for (int tileIndexB = 0; tileIndexB < roomA.edgeTiles.Count; ++tileIndexB)
    61.                     {
    62.                         var tileA = roomA.edgeTiles[tileIndexA];
    63.                         var tileB = roomB.edgeTiles[tileIndexB];
    64.  
    65.                         int sqDistanceBetweenRooms = (int)(Mathf.Pow(tileA.x - tileB.x, 2) + Mathf.Pow(tileA.y - tileB.y, 2));
    66.                         if (sqDistanceBetweenRooms < bestDistance || !possibleConnectionFound)
    67.                         {
    68.                             bestDistance = sqDistanceBetweenRooms;
    69.                             possibleConnectionFound = true;
    70.                             bestTileA = tileA;
    71.                             bestTileB = tileB;
    72.                             bestRoomA = roomA;
    73.                             bestRoomB = roomB;
    74.                         }
    75.                     }
    76.                 }
    77.             }
    78.         }
    79.  
    80.         if (possibleConnectionFound)
    81.         {
    82.             CreatePassage(bestRoomA, bestRoomB, bestTileA, bestTileB);
    83.         }
    84.     }
    85. }
    86.  
    The fun thing is that this segment works absolutely normally from the repository code.
     
    Last edited: Oct 16, 2019