Skip to content

SolAnna7/TaurusDungeonGenerator

Repository files navigation

TaurusDungeonGenerator logo

TaurusDungeonGenerator v0.8

A graph based procedural dungeon generator for Unity

Features

  • Abstract graph structure definition
  • Store and load structures from config with PiscesConfigLoader
  • Quick layout generation (not using Unity space!)
  • Reusing dungeon plans by nesting
  • Main path and branch generation
  • Add meta data using tags and properties
  • Optional paths
  • Margin between elements
  • Debug view

System Requirements

  • Unity 2018.4 or later

Dependencies

Installation

  • Clone into the Assets folder of your Unity project
git clone git@github.com:SolAnna7/TaurusDungeonGenerator.git
cd TaurusDungeonGenerator/
git submodule update --init --recursive
  • Download from Unity Asset Store
  • To load the dungeon structures from config files use the PiscesConfigLoader

Usage

Create your room assets
  • Add the Room component to the root Room capture
  • Setup your doors with RoomConnector component RoomConnector capture
  • Collect your rooms into RoomCollection-s for randomized usage
Define your dungeon structure
  • In code
 AbstractDungeonStructure.Builder
     .SetEmbeddedDungeons(new Dictionary<string, AbstractDungeonStructure>
     {
         {
             //branch type 1 definition
             "inline-branch-1",
             AbstractDungeonStructure.Builder.SetStartElement(
                 ConnectionElement("DungeonGenerationTest/Corridors", new RangeI(4, 7))
                     .AddSubElement(
                         NodeElement("DungeonGenerationTest/MiddleRoom")
                     ).Build()).Build()
         },
         {
             //branch type 2 definition
             "inline-branch-2",
             AbstractDungeonStructure.Builder.SetStartElement(
                 ConnectionElement("DungeonGenerationTest/Corridors", new RangeI(2, 5))
                     .AddSubElement(
                         NodeElement("DungeonGenerationTest/CorrX")
                     ).Build()).Build()
         }
     })
     .SetBranchData(new BranchDataWrapper(
         // the types of dungeons used as branches
         new List<string> {"inline-branch-1", "inline-branch-2"},
         // maximum percentage of empty connections where branches will be built
         50f))
     .SetMetaData(StructureMetaData.Builder
         // meta data objects for the structure
         .AddStructureProperty("name", "Realistic dungeon layout")
         .AddStructureProperty("description", "A realistic layout with one miniboss room, one boss room and one to three exits.")
         // tags for the structure
         .AddStructureTag("structure-tag-1")
         .AddStructureTag("structure-tag-2")
         // tags for every element
         .AddGlobalTag("global-node-tag-1")
         .Build())
     // the actual structure of the dungeon graph
     .SetStartElement(
         // a single room chosen from the DungeonGenerationTest/EndRoom RoomCollection
         NodeElement("DungeonGenerationTest/EndRoom")
             // tags for this node
             .SetMetaData(NodeMetaData.Builder.AddTag("entrance").Build())
             .AddSubElement(
                 // a sequence of connected rooms chosen from the DungeonGenerationTest/Corridors RoomCollection
                 // the length of the sequence is between 5 and 10 rooms randomly chosen at generation
                 ConnectionElement("DungeonGenerationTest/Corridors", new RangeI(5, 10))
                     .AddSubElement(
                         NodeElement("DungeonGenerationTest/MiddleRoom")
                             .SetMetaData(NodeMetaData.Builder.AddTag("small-boss-room").Build())
                             .AddSubElement(
                                 ConnectionElement("DungeonGenerationTest/Corridors", new RangeI(5, 10))
                                     .AddSubElement(
                                         NodeElement("DungeonGenerationTest/CorridorsNormalBig")
                                             .AddSubElement(
                                                 ConnectionElement("DungeonGenerationTest/CorridorsBig", new RangeI(3))
                                                     .AddSubElement(
                                                         NodeElement("DungeonGenerationTest/BigRoom")
                                                             .SetMetaData(NodeMetaData.Builder.AddTag("big-boss-room").Build())
                                                             .AddSubElement(
                                                                 NodeElement("DungeonGenerationTest/CorridorsNormalBig")
                                                                     .AddSubElement(
                                                                         ConnectionElement("DungeonGenerationTest/Corridors", new RangeI(5, 10))
                                                                             .AddSubElement(
                                                                                 NodeElement("DungeonGenerationTest/MiddleRoom")
                                                                                     .AddSubElement(
                                                                                         ConnectionElement("DungeonGenerationTest/Corridors", new RangeI(5, 10))
                                                                                             .AddSubElement(NodeElement("DungeonGenerationTest/EndRoom")
                                                                                                 .SetMetaData(NodeMetaData.Builder.AddTag("exit-1-static").Build())
                                                                                                 .Build())
                                                                                             .Build())
                                                                                     .AddSubElement(
                                                                                         ConnectionElement("DungeonGenerationTest/Corridors", new RangeI(5, 10))
                                                                                             // this part of the tree is optional
                                                                                             .SetMetaData(NodeMetaData.Builder.SetOptionalNode().Build())
                                                                                             .AddSubElement(NodeElement("DungeonGenerationTest/EndRoom")
                                                                                                 .SetMetaData(NodeMetaData.Builder
                                                                                                     .AddTag("exit-2-optional")
                                                                                                     // end of an optional tree
                                                                                                     .SetOptionalEndpoint()
                                                                                                     .Build())
                                                                                                 .Build())
                                                                                             .Build())
                                                                                     .AddSubElement(
                                                                                         ConnectionElement("DungeonGenerationTest/Corridors", new RangeI(5, 10))
                                                                                             .SetMetaData(NodeMetaData.Builder.SetOptionalNode().Build())
                                                                                             .AddSubElement(NodeElement("DungeonGenerationTest/EndRoom")
                                                                                                 .SetMetaData(NodeMetaData.Builder
                                                                                                     .AddTag("exit-3-optional")
                                                                                                     .SetOptionalEndpoint()
                                                                                                     .Build())
                                                                                             )))))))))))
             .Build())
     .Build()
 realistic-dungeon-layout-1:
   inline-nested:
     # branch type 1 definition
     inline-branch-1:
       start-node:
         connection: DungeonGenerationTest/Corridors
         length: 4_7
         subs:
           - node: DungeonGenerationTest/MiddleRoom
     # branch type 2 definition
     inline-branch-2:
       start-node:
         connection: DungeonGenerationTest/Corridors
         length: 2_5
         subs:
           - node: DungeonGenerationTest/CorrX
   # the types of dungeons used as branches
   branch-prototypes:
     - inline-branch-1
     - inline-branch-2
   # maximum percentage of empty connections where branches will be built
   branch-max-percent: 50
   # meta data objects for the structure
   structure-properties:
     name: "Realistic dungeon layout"
     description: "A realistic layout with one miniboss room, one boss room and one to three exits."
   # tags for the structure
   structure-tags:
     - structure-tag-1
     - structure-tag-2
   # tags for every element
   global-node-tags:
     - global-node-tag-1
   # the actual structure of the dungeon graph
   start-node:
     # a single room chosen from the DungeonGenerationTest/EndRoom RoomCollection
     node: DungeonGenerationTest/EndRoom
     # tags for this node
     tags:
       - entrance
     subs:
       # a sequence of connected rooms chosen from the DungeonGenerationTest/Corridors RoomCollection
       - connection: DungeonGenerationTest/Corridors
         # the length of the sequence is between 5 and 10 rooms randomly chosen at generation
         length: 5_10
         subs:
           - node: DungeonGenerationTest/MiddleRoom
             tags:
               - small-boss-room
             subs:
               - connection: DungeonGenerationTest/Corridors
                 length: 5_10
                 subs:
                   - node: DungeonGenerationTest/CorridorsNormalBig
                     subs:
                       - connection: DungeonGenerationTest/CorridorsBig
                         length: 3
                         subs:
                           - node: DungeonGenerationTest/BigRoom
                             tags:
                               - big-boss-room
                             subs:
                               - node: DungeonGenerationTest/CorridorsNormalBig
                                 subs:
                                   - connection: DungeonGenerationTest/Corridors
                                     length: 5_10
                                     subs:
                                       - node: DungeonGenerationTest/MiddleRoom
                                         subs:
                                           - connection: DungeonGenerationTest/Corridors
                                             length: 5_10
                                             subs:
                                               - node: DungeonGenerationTest/EndRoom
                                                 optional-end: true
                                                 tags:
                                                   - exit-1-static
                                           - connection: DungeonGenerationTest/Corridors
                                             length: 5_10
                                             # this part of the tree is optional
                                             optional: true
                                             subs:
                                               - node: DungeonGenerationTest/EndRoom
                                                 # end of an optional tree
                                                 optional-end: true
                                                 tags:
                                                   - exit-2-optional
                                           - connection: DungeonGenerationTest/Corridors
                                             length: 5_10
                                             optional: true
                                             subs:
                                               - node: DungeonGenerationTest/EndRoom
                                                 optional-end: true
                                                 tags:
                                                   - exit-3-optional
Parameterise and generate your dungeon, then build it in unity space
PrototypeDungeonGenerator generator = new PrototypeDungeonGenerator(inputStructure, 
                                                                    seed, 
                                                                    new PrototypeDungeonGenerator.GenerationParameters {RequiredOptionalEndpointNumber = optionalPathNumber});
PrototypeDungeon prototypeDungeon = generator.BuildPrototype();
DungeonStructure builtStructure = prototypeDungeon.BuildDungeonInUnitySpace(transform);
πŸŽ†πŸŽ†πŸŽ† Profit πŸŽ†πŸŽ†πŸŽ†

Nested Dungeons

Reuse dungeons as subtrees Can continue with children Can be defined as global (used from any other dungeon) or inline (reusable only in one main dungeon)

example-dungeons:

  global-nestable-dungeon:
    start-node:
      connection: DungeonGenerationTest/Corridors
      length: 1_3
      subs:
        - node: DungeonGenerationTest/MiddleRoom

  nesting-presentation:
    start-node:
      node: DungeonGenerationTest/EndRoom
      subs:
        - connection: DungeonGenerationTest/Corridors
          length: 10_20
          subs:
            - node: DungeonGenerationTest/CorrX
              subs:
                # this nested dungeon continues have child nodes
                - nested: example-dungeons.global-nestable-dungeon
                  subs:
                    - connection: DungeonGenerationTest/Corridors
                      length: 1_3
                      subs:
                        - node: DungeonGenerationTest/EndRoom
                - nested: example-dungeons.global-nestable-dungeon

Branches

After creating the main tree, other low priority paths can be added. This can be used as a way to add complexity and dead-ends to a dungeon. The brances are defined as nested dungeons (global or inline) Set the maximum number of unused connectors where brances are tried to be generated. Either as percent branch-max-percent: 50 or as a number branch-max-num: 12

  realistic-dungeon-layout-1:
    inline-nested:
      # branch type 1 definition
      inline-branch-1:
        start-node:
          connection: DungeonGenerationTest/Corridors
          length: 4_7
          subs:
            - node: DungeonGenerationTest/MiddleRoom
      # branch type 2 definition
      inline-branch-2:
        start-node:
          connection: DungeonGenerationTest/Corridors
          length: 2_5
          subs:
            - node: DungeonGenerationTest/CorrX
    # the types of dungeons used as branches
    branch-prototypes:
      - inline-branch-1
      - inline-branch-2
    # maximum percentage of empty connections where branches will be built
    branch-max-percent: 50
...

Optional paths

Some subtrees of the main path can be marked as optional and nodes inside them as optional-end. At generation the required number of optional endpoints can be set. Use-Case: Reusing the same dungeon with different number of exits.

Margin between elements

Add additional margin between elements This is still an experimental feature

structure.StructureMetaData.MarginUnit = 0.5f;

Debug view

Use the DungeonDebugger static class to

  • Draw in-editor gizmos around the dungeon element with color coded information
  • Generate a debug structure using unity cubes with the same colors
  • Generate debug description text

Debug View

Planned features

v0.9

  • Room repetition control
  • Path straightness/gayness curvedness control

v1.0

  • Unity Editor extension for dungeon structure creation

?

  • Optional handling refactor: Activate optional paths based on room tags
  • Circles in the layout
  • Variables: Define variables (like random ranges) to reuse in the structure
  • Bounding box for the dungeon