Search Unity

  1. Unity 2018.3 is now released.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Our response to Improbable’s blog post (and why you can keep working on your SpatialOS game). Read more here
    Dismiss Notice
  4. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

Random Level Generator

Discussion in '2D' started by Marrt, Jul 21, 2015.

  1. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    517
    Random Tile-based 2D-Dungeons (V0.31)

    -4 dungeons:
    - RoomTemplatePlacer
    - Rooms and Mazes
    - Cave
    - Perlin noise

    Usage:
    - Add the DungeonGenerator Component to a GameObject
    - Call one of the Generate functions from anywhere, all parameters are Optional
    Code (CSharp):
    1. DungeonGenerator.instance.GenerateHauberkDungeon();
    2. DungeonGenerator.instance.GeneratePerlinDungeon();
    3. DungeonGenerator.instance.GenerateCaveDungeon();
    - Be sure to have a Canvas Object in the Hierarchy or you will see no Map

    RoomTemplatePlacer creates RoomTemplates and attempts to place them:
    upload_2015-10-21_10-15-23.png


    HauberkDungeon creates deliberately imperfect mazes with rooms and doors:
    upload_2015-7-23_5-11-17.png
    -i added an option to streamline corridors a bit
    -i added an option to try to connect rooms first (bool tryRoomsFirst)

    Cave creates more cave-like structures:
    upload_2015-7-23_5-10-50.png
    -added nothing, only changed some Datatypes


    Thanks to the other authors:
    http://journal.stuffwithstuff.com/2014/12/21/rooms-and-mazes/
    http://www.evilscience.co.uk/a-c-algorithm-to-build-roguelike-cave-systems-part-1/

    Maybe in future:
    1. http://www.magicaltimebean.com/2014/11/procedural-room-generation-explained/ //done
    2. http://www.roguebasin.com/index.php?title=Basic_BSP_Dungeon_generation


    newest scipts:
    http://forum.unity3d.com/threads/random-level-generator.342587/#post-2742319

    My old scripts are here (my dijkstra was flawed and therefore slow)
     

    Attached Files:

    Last edited: Aug 6, 2016
    jhocking, Xepherys, qqqbbb and 6 others like this.
  2. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,567
    I'm sure some people would find this useful. You could take it much further, or just polish it up as a simpler asset.
     
  3. Zoltern

    Zoltern

    Joined:
    Jun 16, 2015
    Posts:
    14
    For sure! I'd have some uses for that :)
     
  4. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    517
    Added the script to the OP,
    it includes 3 types now, not very tidy yet - but i will improve it the next days after work so i can notify the authors of the source algorithms without blushing...
     
  5. Zoltern

    Zoltern

    Joined:
    Jun 16, 2015
    Posts:
    14
    Awesome! thanks, i'll take a look at this as soon as i get home :)
     
  6. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    517
    Update in OP:
    -Added "tryRoomsFirst" to hauberk dungeon, so rooms are connected first, helps to reduce the dead-end-rooms. People want to feel progress when clearing a room, and always stepping back to the corridor does feel like backtracking
    -Exposed Cave & Perlin variables in Editor

    Next Update may take a while because i am currently doing A* Pathfinding to get the Idea of it.
     
  7. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    517
    Newest Update: RoomTemplatePlacer (My favourite so far)

    -Creates random roomtemplates and then tries to place them next to each other.

    some info:
    Rooms have potential doors so only doors that are used during the placement are actually converted into door tiles. Transitions between rooms (=doors) can be 1x1 or 2x2. A Path is generated at the end, highlighting the 2 rooms that have the longest - shortest path to each other. These rooms can be used to place start and end room to create a dungeon with only a few sidetracks. Due to the door generation there is only a single solution path, with impasse sidetracks instead of multiple branches that lead to the exit, but that could be changed if you would check for overlapping potential doors after everything is placed. But this can also be used since all blue rooms are mandatory and must be passed if the exit is to be reached, you could place story events into them.

    You can also use custom Tile[,] to create template rooms, just be sure that a room consists at least out of some Tile.Floor and has some Tiles that mark potential doors (Tile.DoorNorth, Tile.DoorWest...) as well as adding these doors as Door-Objects in the corresponding "potentialDoor"-list (needed for the placement and the dungeon graph), you can also use the MarkPotentialDoors() function to do this, but the door can be on every valid wall then and you have less control.

    thanks for reading.

    EDIT: Updated to v0.31, had some errors in the referencing (placing altered templates themselves) and pathfinding heuristic had no multiplier for cardinal directions.
     
    Last edited: Oct 22, 2015
    LiberLogic969 likes this.
  8. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    517
    I tinkered around again, i am not finished but i added some stuff and most importantly: fixed my Dijkstra. I used the whole list of nodes at every Min(). Now the list that is using Min() only contains the visited elements like it has to be, therefore it is like 10 times faster...

    Now i create dungeons that can have entrances and exits that terminate at the edge of the map, so transition seem much more game-world-immersive than simple teleporters in the middle of a room. Other things i planned are event placement. On the pic you can see the red and yellow 3x3-squares, those are sidePath- and mandatoryPath-Events. But i have not included the code for them yet.
    upload_2016-8-6_14-0-37.png


    Files (i hope they work on their own, i think i removed all dependencies to my actual project):
     

    Attached Files:

    Last edited: Aug 6, 2016
  9. colin_windmuller

    colin_windmuller

    Joined:
    Aug 18, 2016
    Posts:
    3
    [QUOTE="...i think i removed all dependencies to my actual project):[/QUOTE]
    There are calls to 'PerformanceMeter', but that's all I encountered. Great work, I saw your comment on Bob Nystrom's blog!
     
  10. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    517
    oh well, here it is:
     

    Attached Files:

  11. colin_windmuller

    colin_windmuller

    Joined:
    Aug 18, 2016
    Posts:
    3
    Quick question, is there an easy way to set the hallways to be only 1 tile wide? I'm using Hauberk, if it matters.
     
  12. colin_windmuller

    colin_windmuller

    Joined:
    Aug 18, 2016
    Posts:
    3
    Ah, found it. There's a call to MultiplyDungeon(2);
     
  13. VrTechEx

    VrTechEx

    Joined:
    Aug 4, 2013
    Posts:
    22
    Any Updates? This is very useful Thank you tons !
     
  14. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    517
    Well, i changed Roomdungeons quite a bit on my version here at home, i am unsure if this version is encapsulated enough for public usage.
    I separated the classes into a separate file added some specialities that control some things like:
    - connected dungeons, every dungeon has connections to other dungeons
    - enter direction: control where a transition portal is instantiated, so when leaving a roomdungeon right, you will enter the next dungeon from left, really helps for immersion, now the connected dungeons really feel related
    - sidepaths: i can now control if portals appear on the edge or the screen (as pathways), in the middle of a room (trapdoor, ladder) and if they appear on the mandatory path or not. The mandatory path is the path the player must take to get to the end of a dungeonfamily, so everything in there is unmissable
    - events: i crudely began to add events, events require a certain footprint (lets say it is a 3x3 tile event with a wall at north) and can only be placed in a matching place. It may contain random encounters or story stuff can be placed in sidepaths or mandatory routes

    So it is a pretty neat generator but now requires some prefabs for the portal/pathway trigger spawning and stuff, defining a dungeon is also really cumbersome and errorprone at this point:

    Code (CSharp):
    1. private Dictionary<string,LevelSetup> levels = new Dictionary<string, LevelSetup>(){
    2.         //private    List<LevelSetup> levels = new List<LevelSetup>(){
    3.      
    4.         //game levels                    idEnd        displayName        displayNameSub            sceneToLoadName        type                                isDebug
    5.         {    "brawl",    new LevelSetup( "n/a",        "Brawl",        "Brawl Map 1",            "05 Brawl",            LevelType.PreplacedBlockParsing,    dParamsHall1        )},    //    start of Game    
    6.         {    "start",    new LevelSetup( "n/a",        "Chapter1",        "A Final Beginning",    "01 Beginning",        LevelType.PreplacedBlockParsing,    dParamsHall1        )},    //    start of Game
    7.         {    "boss1",    new LevelSetup( "hub00",    "Susu",            "Ashes To Ashes",        "04 Boss1",            LevelType.PreplacedBlockParsing,    dParamsHall1        )},    //    boss 1
    8.         {    "hall1",    new LevelSetup( "hall2",    "Halls",        "Floor 1",                "03 DungeonLevel",    LevelType.GenRoomTemplate,            dParamsHall1        )},    //    generic Floor
    9.         {    "hall2",    new LevelSetup( "boss1",    "Halls",        "Floor 2",                "03 DungeonLevel",    LevelType.GenRoomTemplate,            dParamsHall1        )},    //    generic Floor
    10.         {    "hub00",    new LevelSetup( "n/a",        "Hub",            "A Forsaken Outpost",    "02 HubRoom",        LevelType.PreplacedBlockParsing,    dParamsHall1        )},    //    generic Floor
    11.         {    "hallH",    new LevelSetup( "hall2",    "Halls",        "Floor 1",                "03 DungeonLevel",    LevelType.GenRoomTemplate,            dParamsHallH        )},    //    generic Floor
    12.      
    13.         //debug levels
    14.         {    "debug",    new LevelSetup( "n/a",        "Debug",        "Debugging",            "Debug",            LevelType.PreplacedBlockParsing,    dParamsTestEast        )},
    15.         {    "light",    new LevelSetup( "n/a",        "Lighttest",    "NormalMaps",            "LightTest",        LevelType.None,                        dParamsTestEast        )}
    16.      
    17.     };
    18.  
    19.  
    20.     //ORDER OF THESE STATIC INITIALIZERS IS CRUCIAL!
    21.     private    static PathRole            rEntr    = PathRole.Entrance;
    22.     private    static PathRole            rExit    = PathRole.Exit;
    23.     private    static PathRole            rMand    = PathRole.Mandatory;
    24.     private    static PathRole            rSide    = PathRole.Sidetrack;
    25.     private    static PathRole            rHide    = PathRole.Hidden;
    26.  
    27.     private    static PortalDirection    pA        = PortalDirection.Any;
    28.     private    static PortalDirection    pX        = PortalDirection.None;
    29.     private    static PortalDirection    pN        = PortalDirection.North;
    30.     private    static PortalDirection    pE        = PortalDirection.East;
    31.     private    static PortalDirection    pS        = PortalDirection.South;
    32.     private    static PortalDirection    pW        = PortalDirection.West;
    33.  
    34.  
    35.     private    static PortalTemplate defaultPortalTemplateAny        = new PortalTemplate( "default",    PathRole.Mandatory, PortalDirection.Any        );
    36.     private    static PortalTemplate defaultPortalTemplateNone        = new PortalTemplate( "default",    PathRole.Mandatory, PortalDirection.None    );
    37.     private    static PortalTemplate defaultPortalTemplateNorth    = new PortalTemplate( "default",    PathRole.Mandatory, PortalDirection.North    );
    38.     private    static PortalTemplate defaultPortalTemplateEast        = new PortalTemplate( "default",    PathRole.Mandatory, PortalDirection.East    );
    39.     private    static PortalTemplate defaultPortalTemplateSouth    = new PortalTemplate( "default",    PathRole.Mandatory, PortalDirection.West    );
    40.     private    static PortalTemplate defaultPortalTemplateWest        = new PortalTemplate( "default",    PathRole.Mandatory, PortalDirection.South    );
    41.  
    42.     private    static List<PortalTemplate> testGatewayTemplate        = new List<PortalTemplate>() { defaultPortalTemplateWest, defaultPortalTemplateAny    };
    43.  
    44.     private    static DungeonParameters dParamsTestEast    = new DungeonParameters( 80, 50, 11, testGatewayTemplate    );
    45.     private    static DungeonParameters dParamsTestSouth    = new DungeonParameters( 80, 50, 11, testGatewayTemplate    );
    46.  
    47.     //first has to be entrance and a direction
    48.     private    static PortalTemplate        portalHall1p1    = new PortalTemplate( "hub00",    rEntr,    pE    );
    49.     private    static PortalTemplate        portalHall1p2    = new PortalTemplate( "hall2",    rExit,    pA    );
    50.     private    static PortalTemplate        portalHall1p3    = new PortalTemplate( "boss1",    rSide,    pA    );
    51.     private    static List<PortalTemplate>    portalsHall1    = new List<PortalTemplate>() { portalHall1p1, portalHall1p2, portalHall1p3    };
    52.     private    static DungeonParameters    dParamsHall1    = new DungeonParameters( 80, 50, 11, portalsHall1    );
    53.  
    54.     private    static PortalTemplate        portalHallHp1    = new PortalTemplate( "hub00",    rEntr,    pS    );
    55.     private    static PortalTemplate        portalHallHp2    = new PortalTemplate( "boss1",    rExit,    pA    );
    56.     private    static List<PortalTemplate>    portalsHallH    = new List<PortalTemplate>() { portalHallHp1, portalHallHp2    };
    57.     private    static DungeonParameters    dParamsHallH    = new DungeonParameters( 80, 50, 11, portalsHallH    );
    58.  
    59.     // ORDER END

    If i improve on that in the next months i will share it again
     
    Last edited: Feb 28, 2017
    VrTechEx likes this.
  15. VrTechEx

    VrTechEx

    Joined:
    Aug 4, 2013
    Posts:
    22
    I really appreciate your answer :3 and algorithm as well :) Thank you ! Looking for your update soon :D
     
  16. J0hn4n

    J0hn4n

    Joined:
    May 11, 2015
    Posts:
    24
    Hi mate nice setup but how i use the map data? i mean how i populate the dungeon?