├── .gitignore ├── .vsconfig ├── Config ├── DefaultEditor.ini ├── DefaultEngine.ini ├── DefaultGame.ini ├── DefaultInput.ini └── HoloLens │ └── HoloLensEngine.ini ├── Content ├── Floor_400x400.uasset ├── Maps │ ├── TestBed.umap │ └── W_TestBed.uasset ├── StarterContent │ ├── Architecture │ │ ├── Floor_400x400.uasset │ │ └── Wall_400x400.uasset │ └── Materials │ │ ├── M_Basic_Floor.uasset │ │ └── M_Basic_Wall.uasset └── Wall_400x400.uasset ├── Docs ├── DungeonGenerator_ContentData.mp4 ├── HowToUse.docx ├── HowToUse.pdf └── Images │ ├── 1.png │ ├── BPFunctions.png │ ├── DataTableStructure.png │ ├── FloorTilePivotOffset.png │ ├── Options.png │ ├── RoomTemplateSample.png │ ├── RuntimeGeneration.gif │ ├── VideoOverview.mp4 │ ├── WallFacingX.png │ ├── WallFacingX_Edited.png │ ├── WallFacingY.png │ ├── WallFacingY_Edited.png │ └── WallPivotOffset.png ├── DungeonGeneratorDev.uproject ├── LICENSE ├── Plugins └── DungeonGeneratorPlugin │ ├── Config │ └── FilterPlugin.ini │ ├── Content │ ├── DataTables │ │ ├── DT_RoomTemplates_100.uasset │ │ └── DT_RoomTemplates_400.uasset │ ├── Materials │ │ ├── MI_FloorTile_100.uasset │ │ ├── MI_FloorTile_100_V2.uasset │ │ ├── MI_FloorTile_100_V3.uasset │ │ ├── MI_FloorTile_100_V4.uasset │ │ ├── MI_FloorTile_50.uasset │ │ ├── MI_FloorTile_500.uasset │ │ ├── MI_Wall_100.uasset │ │ ├── MI_Wall_100_V2.uasset │ │ ├── MI_Wall_100_V3.uasset │ │ ├── MI_Wall_100_V4.uasset │ │ ├── MI_Wall_50.uasset │ │ ├── MI_Wall_500.uasset │ │ └── M_Master.uasset │ ├── Meshes │ │ ├── 100cm │ │ │ ├── SM_Floor_100.uasset │ │ │ ├── SM_Wall_100.uasset │ │ │ └── SM_Wall_100_Rotated.uasset │ │ ├── 500cm │ │ │ ├── SM_Floor_500.uasset │ │ │ └── SM_Wall_500.uasset │ │ └── 50cm │ │ │ ├── SM_Floor_50.uasset │ │ │ └── SM_Wall_50.uasset │ └── Textures │ │ └── T_Tiles_1.uasset │ ├── DungeonGeneratorPlugin.uplugin │ ├── Resources │ └── Icon128.png │ └── Source │ └── DungeonGeneratorPlugin │ ├── DungeonGeneratorPlugin.Build.cs │ ├── Private │ ├── DungeonGenerator.cpp │ ├── DungeonGeneratorPlugin.cpp │ └── TileMatrix.cpp │ └── Public │ ├── DungeonGenerator.h │ ├── DungeonGeneratorPlugin.h │ └── TileMatrix.h ├── README.md └── Source ├── DungeonGeneratorDev.Target.cs ├── DungeonGeneratorDev ├── DungeonGeneratorDev.Build.cs ├── DungeonGeneratorDev.cpp ├── DungeonGeneratorDev.h ├── DungeonGeneratorDevGameModeBase.cpp └── DungeonGeneratorDevGameModeBase.h └── DungeonGeneratorDevEditor.Target.cs /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio 2015 user specific files 2 | .vs/ 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | 22 | # Compiled Static libraries 23 | *.lai 24 | *.la 25 | *.a 26 | *.lib 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | *.ipa 33 | 34 | # These project files can be generated by the engine 35 | *.xcodeproj 36 | *.xcworkspace 37 | *.sln 38 | *.suo 39 | *.opensdf 40 | *.sdf 41 | *.VC.db 42 | *.VC.opendb 43 | 44 | # Precompiled Assets 45 | SourceArt/**/*.png 46 | SourceArt/**/*.tga 47 | 48 | # Binary Files 49 | Binaries/* 50 | Plugins/*/Binaries/* 51 | 52 | # Builds 53 | Build/* 54 | 55 | # Whitelist PakBlacklist-.txt files 56 | !Build/*/ 57 | Build/*/** 58 | !Build/*/PakBlacklist*.txt 59 | 60 | # Don't ignore icon files in Build 61 | !Build/**/*.ico 62 | 63 | # Built data for maps 64 | *_BuiltData.uasset 65 | 66 | # Configuration files generated by the Editor 67 | Saved/* 68 | 69 | # Compiled source files for the engine to use 70 | Intermediate/* 71 | Plugins/*/Intermediate/* 72 | 73 | # Cache files for the editor to use 74 | DerivedDataCache/* 75 | -------------------------------------------------------------------------------- /.vsconfig: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "components": [ 4 | "Microsoft.VisualStudio.Component.VC.Tools.ARM64", 5 | "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", 6 | "Microsoft.VisualStudio.Component.Windows10SDK", 7 | "Microsoft.VisualStudio.Workload.CoreEditor", 8 | "Microsoft.VisualStudio.Workload.NativeDesktop", 9 | "Microsoft.VisualStudio.Workload.NativeGame", 10 | "Microsoft.VisualStudio.Workload.Universal" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Config/DefaultEditor.ini: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Config/DefaultEngine.ini: -------------------------------------------------------------------------------- 1 | 2 | 3 | [/Script/EngineSettings.GameMapsSettings] 4 | GameDefaultMap=/Game/Maps/TestBed.TestBed 5 | EditorStartupMap=/Game/Maps/TestBed.TestBed 6 | 7 | [/Script/HardwareTargeting.HardwareTargetingSettings] 8 | TargetedHardwareClass=Desktop 9 | AppliedTargetedHardwareClass=Desktop 10 | DefaultGraphicsPerformance=Maximum 11 | AppliedDefaultGraphicsPerformance=Maximum 12 | 13 | [/Script/Engine.Engine] 14 | +ActiveGameNameRedirects=(OldGameName="TP_Blank",NewGameName="/Script/DungeonGeneratorDev") 15 | +ActiveGameNameRedirects=(OldGameName="/Script/TP_Blank",NewGameName="/Script/DungeonGeneratorDev") 16 | +ActiveClassRedirects=(OldClassName="TP_BlankGameModeBase",NewClassName="DungeonGeneratorDevGameModeBase") 17 | 18 | [/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings] 19 | bEnablePlugin=True 20 | bAllowNetworkConnection=True 21 | SecurityToken=C1050FEF46FA92C3D281539FF46414AE 22 | bIncludeInShipping=False 23 | bAllowExternalStartInShipping=False 24 | bCompileAFSProject=False 25 | bUseCompression=False 26 | bLogFiles=False 27 | bReportStats=False 28 | ConnectionType=USBOnly 29 | bUseManualIPAddress=False 30 | ManualIPAddress= 31 | 32 | -------------------------------------------------------------------------------- /Config/DefaultGame.ini: -------------------------------------------------------------------------------- 1 | 2 | [/Script/EngineSettings.GeneralProjectSettings] 3 | ProjectID=F467CC404759AEB7EF67E98E24AE336D 4 | CopyrightNotice=Copyright (c) 2021 Orfeas Eleftheriou 5 | 6 | -------------------------------------------------------------------------------- /Config/DefaultInput.ini: -------------------------------------------------------------------------------- 1 | [/Script/Engine.InputSettings] 2 | -AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) 3 | -AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) 4 | -AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) 5 | -AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f)) 6 | -AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f)) 7 | -AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f)) 8 | -AxisConfig=(AxisKeyName="Mouse2D",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f)) 9 | +AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 10 | +AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 11 | +AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 12 | +AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 13 | +AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) 14 | +AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) 15 | +AxisConfig=(AxisKeyName="Mouse2D",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False)) 16 | +AxisConfig=(AxisKeyName="MouseWheelAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 17 | +AxisConfig=(AxisKeyName="Gamepad_LeftTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 18 | +AxisConfig=(AxisKeyName="Gamepad_RightTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 19 | +AxisConfig=(AxisKeyName="Gamepad_Special_Left_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 20 | +AxisConfig=(AxisKeyName="Gamepad_Special_Left_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 21 | +AxisConfig=(AxisKeyName="Vive_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 22 | +AxisConfig=(AxisKeyName="Vive_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 23 | +AxisConfig=(AxisKeyName="Vive_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 24 | +AxisConfig=(AxisKeyName="Vive_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 25 | +AxisConfig=(AxisKeyName="Vive_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 26 | +AxisConfig=(AxisKeyName="Vive_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 27 | +AxisConfig=(AxisKeyName="MixedReality_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 28 | +AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 29 | +AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 30 | +AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 31 | +AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 32 | +AxisConfig=(AxisKeyName="MixedReality_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 33 | +AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 34 | +AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 35 | +AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 36 | +AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 37 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 38 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 39 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 40 | +AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 41 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 42 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 43 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 44 | +AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 45 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 46 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 47 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 48 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 49 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 50 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 51 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 52 | +AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 53 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 54 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 55 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 56 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 57 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 58 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 59 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 60 | +AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False)) 61 | bAltEnterTogglesFullscreen=True 62 | bF11TogglesFullscreen=True 63 | bUseMouseForTouch=False 64 | bEnableMouseSmoothing=True 65 | bEnableFOVScaling=True 66 | bCaptureMouseOnLaunch=True 67 | bEnableLegacyInputScales=True 68 | bEnableMotionControls=True 69 | bFilterInputByPlatformUser=False 70 | bShouldFlushPressedKeysOnViewportFocusLost=True 71 | bEnableDynamicComponentInputBinding=True 72 | bAlwaysShowTouchInterface=False 73 | bShowConsoleOnFourFingerTap=True 74 | bEnableGestureRecognizer=False 75 | bUseAutocorrect=False 76 | DefaultViewportMouseCaptureMode=CapturePermanently_IncludingInitialMouseDown 77 | DefaultViewportMouseLockMode=LockOnCapture 78 | FOVScale=0.011110 79 | DoubleClickTime=0.200000 80 | DefaultPlayerInputClass=/Script/EnhancedInput.EnhancedPlayerInput 81 | DefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent 82 | DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.DefaultVirtualJoysticks 83 | -ConsoleKeys=Tilde 84 | +ConsoleKeys=Tilde 85 | 86 | -------------------------------------------------------------------------------- /Config/HoloLens/HoloLensEngine.ini: -------------------------------------------------------------------------------- 1 | 2 | 3 | [/Script/HoloLensPlatformEditor.HoloLensTargetSettings] 4 | bBuildForEmulation=False 5 | bBuildForDevice=True 6 | bUseNameForLogo=True 7 | bBuildForRetailWindowsStore=False 8 | bAutoIncrementVersion=False 9 | bShouldCreateAppInstaller=False 10 | AppInstallerInstallationURL= 11 | HoursBetweenUpdateChecks=0 12 | bEnablePIXProfiling=False 13 | TileBackgroundColor=(B=64,G=0,R=0,A=255) 14 | SplashScreenBackgroundColor=(B=64,G=0,R=0,A=255) 15 | +PerCultureResources=(CultureId="",Strings=(PackageDisplayName="",PublisherDisplayName="",PackageDescription="",ApplicationDisplayName="",ApplicationDescription=""),Images=()) 16 | TargetDeviceFamily=Windows.Holographic 17 | MinimumPlatformVersion= 18 | MaximumPlatformVersionTested=10.0.18362.0 19 | MaxTrianglesPerCubicMeter=500.000000 20 | SpatialMeshingVolumeSize=20.000000 21 | CompilerVersion=Default 22 | Windows10SDKVersion=10.0.18362.0 23 | +CapabilityList=internetClientServer 24 | +CapabilityList=privateNetworkClientServer 25 | +Uap2CapabilityList=spatialPerception 26 | bSetDefaultCapabilities=False 27 | SpatializationPlugin= 28 | ReverbPlugin= 29 | OcclusionPlugin= 30 | SoundCueCookQualityIndex=-1 31 | 32 | -------------------------------------------------------------------------------- /Content/Floor_400x400.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Content/Floor_400x400.uasset -------------------------------------------------------------------------------- /Content/Maps/TestBed.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Content/Maps/TestBed.umap -------------------------------------------------------------------------------- /Content/Maps/W_TestBed.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Content/Maps/W_TestBed.uasset -------------------------------------------------------------------------------- /Content/StarterContent/Architecture/Floor_400x400.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Content/StarterContent/Architecture/Floor_400x400.uasset -------------------------------------------------------------------------------- /Content/StarterContent/Architecture/Wall_400x400.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Content/StarterContent/Architecture/Wall_400x400.uasset -------------------------------------------------------------------------------- /Content/StarterContent/Materials/M_Basic_Floor.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Content/StarterContent/Materials/M_Basic_Floor.uasset -------------------------------------------------------------------------------- /Content/StarterContent/Materials/M_Basic_Wall.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Content/StarterContent/Materials/M_Basic_Wall.uasset -------------------------------------------------------------------------------- /Content/Wall_400x400.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Content/Wall_400x400.uasset -------------------------------------------------------------------------------- /Docs/DungeonGenerator_ContentData.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/DungeonGenerator_ContentData.mp4 -------------------------------------------------------------------------------- /Docs/HowToUse.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/HowToUse.docx -------------------------------------------------------------------------------- /Docs/HowToUse.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/HowToUse.pdf -------------------------------------------------------------------------------- /Docs/Images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/1.png -------------------------------------------------------------------------------- /Docs/Images/BPFunctions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/BPFunctions.png -------------------------------------------------------------------------------- /Docs/Images/DataTableStructure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/DataTableStructure.png -------------------------------------------------------------------------------- /Docs/Images/FloorTilePivotOffset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/FloorTilePivotOffset.png -------------------------------------------------------------------------------- /Docs/Images/Options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/Options.png -------------------------------------------------------------------------------- /Docs/Images/RoomTemplateSample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/RoomTemplateSample.png -------------------------------------------------------------------------------- /Docs/Images/RuntimeGeneration.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/RuntimeGeneration.gif -------------------------------------------------------------------------------- /Docs/Images/VideoOverview.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/VideoOverview.mp4 -------------------------------------------------------------------------------- /Docs/Images/WallFacingX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/WallFacingX.png -------------------------------------------------------------------------------- /Docs/Images/WallFacingX_Edited.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/WallFacingX_Edited.png -------------------------------------------------------------------------------- /Docs/Images/WallFacingY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/WallFacingY.png -------------------------------------------------------------------------------- /Docs/Images/WallFacingY_Edited.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/WallFacingY_Edited.png -------------------------------------------------------------------------------- /Docs/Images/WallPivotOffset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Docs/Images/WallPivotOffset.png -------------------------------------------------------------------------------- /DungeonGeneratorDev.uproject: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "EngineAssociation": "5.4", 4 | "Category": "", 5 | "Description": "", 6 | "Modules": [ 7 | { 8 | "Name": "DungeonGeneratorDev", 9 | "Type": "Runtime", 10 | "LoadingPhase": "Default" 11 | } 12 | ], 13 | "Plugins": [ 14 | { 15 | "Name": "Bridge", 16 | "Enabled": true, 17 | "SupportedTargetPlatforms": [ 18 | "Win64", 19 | "Mac", 20 | "Linux" 21 | ] 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Orfeas Eleftheriou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Config/FilterPlugin.ini: -------------------------------------------------------------------------------- 1 | [FilterPlugin] 2 | ; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and 3 | ; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively. 4 | ; 5 | ; Examples: 6 | ; /README.txt 7 | ; /Extras/... 8 | ; /Binaries/ThirdParty/*.dll 9 | -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/DataTables/DT_RoomTemplates_100.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/DataTables/DT_RoomTemplates_100.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/DataTables/DT_RoomTemplates_400.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/DataTables/DT_RoomTemplates_400.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/MI_FloorTile_100.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/MI_FloorTile_100.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/MI_FloorTile_100_V2.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/MI_FloorTile_100_V2.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/MI_FloorTile_100_V3.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/MI_FloorTile_100_V3.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/MI_FloorTile_100_V4.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/MI_FloorTile_100_V4.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/MI_FloorTile_50.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/MI_FloorTile_50.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/MI_FloorTile_500.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/MI_FloorTile_500.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/MI_Wall_100.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/MI_Wall_100.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/MI_Wall_100_V2.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/MI_Wall_100_V2.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/MI_Wall_100_V3.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/MI_Wall_100_V3.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/MI_Wall_100_V4.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/MI_Wall_100_V4.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/MI_Wall_50.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/MI_Wall_50.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/MI_Wall_500.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/MI_Wall_500.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Materials/M_Master.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Materials/M_Master.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Meshes/100cm/SM_Floor_100.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Meshes/100cm/SM_Floor_100.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Meshes/100cm/SM_Wall_100.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Meshes/100cm/SM_Wall_100.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Meshes/100cm/SM_Wall_100_Rotated.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Meshes/100cm/SM_Wall_100_Rotated.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Meshes/500cm/SM_Floor_500.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Meshes/500cm/SM_Floor_500.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Meshes/500cm/SM_Wall_500.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Meshes/500cm/SM_Wall_500.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Meshes/50cm/SM_Floor_50.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Meshes/50cm/SM_Floor_50.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Meshes/50cm/SM_Wall_50.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Meshes/50cm/SM_Wall_50.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Content/Textures/T_Tiles_1.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Content/Textures/T_Tiles_1.uasset -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/DungeonGeneratorPlugin.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "1.2", 5 | "FriendlyName": "DungeonGeneratorPlugin", 6 | "Description": "A handy dungeon generator", 7 | "Category": "Other", 8 | "CreatedBy": "Orfeas Eleftheriou", 9 | "CreatedByURL": "orfeasel.com", 10 | "DocsURL": "https://github.com/orfeasel/DungeonGenerator/blob/main/Docs/HowToUse.pdf", 11 | "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/3ef6cc9c5400434784446008160cb5c7", 12 | "SupportURL": "https://www.orfeasel.com/contact-me/", 13 | "CanContainContent": true, 14 | "IsBetaVersion": false, 15 | "IsExperimentalVersion": false, 16 | "Installed": false, 17 | "Modules": [ 18 | { 19 | "Name": "DungeonGeneratorPlugin", 20 | "Type": "Runtime", 21 | "LoadingPhase": "Default", 22 | "WhitelistPlatforms": [ 23 | "Win64" 24 | ] 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orfeasel/DungeonGenerator/47b7907bbb3b93a20d9c58f18ba62c1fd021eebb/Plugins/DungeonGeneratorPlugin/Resources/Icon128.png -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Source/DungeonGeneratorPlugin/DungeonGeneratorPlugin.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Orfeas Eleftheriou 2 | 3 | using UnrealBuildTool; 4 | 5 | public class DungeonGeneratorPlugin : ModuleRules 6 | { 7 | public DungeonGeneratorPlugin(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicIncludePaths.AddRange( 12 | new string[] { 13 | // ... add public include paths required here ... 14 | 15 | } 16 | ); 17 | 18 | 19 | PrivateIncludePaths.AddRange( 20 | new string[] { 21 | // ... add other private include paths required here ... 22 | } 23 | ); 24 | 25 | 26 | PublicDependencyModuleNames.AddRange( 27 | new string[] 28 | { 29 | "Core", 30 | //"DungeonGeneratorPlugin" 31 | // ... add other public dependencies that you statically link with here ... 32 | } 33 | ); 34 | 35 | 36 | PrivateDependencyModuleNames.AddRange( 37 | new string[] 38 | { 39 | "CoreUObject", 40 | "Engine", 41 | "Slate", 42 | "SlateCore", 43 | 44 | // ... add private dependencies that you statically link with here ... 45 | } 46 | ); 47 | 48 | 49 | DynamicallyLoadedModuleNames.AddRange( 50 | new string[] 51 | { 52 | // ... add any modules that your module loads dynamically here ... 53 | } 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Source/DungeonGeneratorPlugin/Private/DungeonGenerator.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Orfeas Eleftheriou 2 | 3 | #include "DungeonGenerator.h" 4 | #include "DrawDebugHelpers.h" 5 | #include "Components/StaticMeshComponent.h" 6 | #include "Engine/StaticMesh.h" 7 | #include "Engine/StaticMeshActor.h" 8 | #include "Engine/World.h" 9 | #include "Materials/MaterialInterface.h" 10 | #include "Kismet/GameplayStatics.h" 11 | 12 | DEFINE_LOG_CATEGORY(DungeonGenerator); 13 | 14 | const FName ADungeonGenerator::DUNGEON_MESH_TAG = FName("Orfeas_Dungeon_Generator"); 15 | 16 | float ADungeonGenerator::CalculateFloorTileSize(const UStaticMesh& Mesh) const 17 | { 18 | return FMath::Abs(Mesh.GetBoundingBox().Min.Y) + FMath::Abs(Mesh.GetBoundingBox().Max.Y); 19 | } 20 | 21 | FRotator ADungeonGenerator::CalculateWallRotation(bool bWallFacingXProperty, const FTileMatrix::FWallSpawnPoint& WallSpawnPoint, const FVector& WallPivotOffsetOverride, FVector& LocationOffset) const 22 | { 23 | FRotator WallRotation = FRotator::ZeroRotator; 24 | LocationOffset = FVector(); 25 | 26 | //If the point is generated in a way that is looking at the X axis and the wall is rotated to look at Y make sure to 27 | //rotate the wall and apply an offset 28 | //Note: Points looking at X axis are spread along Y 29 | //WallSpawnPoint.bFacingX = true when the wall is located in an "up/down" tile 30 | if (!bWallFacingXProperty && WallSpawnPoint.bFacingX) 31 | { 32 | WallRotation = FRotator(0.f, -90.f, 0.f); 33 | //LocationOffset.Y += FMath::Abs(WallSMPivotOffset.X); 34 | LocationOffset.Y += FMath::Abs(WallPivotOffsetOverride.X); 35 | } 36 | else if (!WallSpawnPoint.bFacingX && bWallFacingXProperty) 37 | { 38 | WallRotation = FRotator(0.f, -90.f, 0.f); 39 | } 40 | else //No rotation adjustments needed; just apply the original offset 41 | { 42 | //LocationOffset+=WallSMPivotOffset; 43 | LocationOffset += WallPivotOffsetOverride; 44 | } 45 | 46 | 47 | return WallRotation; 48 | } 49 | 50 | void ADungeonGenerator::SpawnDungeonFromDataTable() 51 | { 52 | TArray RoomTemplates; 53 | FString ContextStr; 54 | RoomTemplatesDataTable->GetAllRows(ContextStr, RoomTemplates); 55 | 56 | ensure(RoomTemplates.Num() > 0); 57 | 58 | float DataTableFloorTileSize = CalculateFloorTileSize(*(*RoomTemplates[0]).RoomTileMesh); 59 | 60 | TArray Rooms; 61 | TArray CorridorFloorTiles; 62 | TArray CorridorWalls; 63 | TileMatrix.ProjectTileMapLocationsToWorld(DataTableFloorTileSize, Rooms, CorridorFloorTiles, CorridorWalls); 64 | 65 | //Spawn rooms & walls using a random template from the provided table 66 | for (int32 i = 0; i < Rooms.Num(); i++) 67 | { 68 | FRoomTemplate RoomTemplate = *RoomTemplates[FMath::RandRange(0, RoomTemplates.Num() - 1)]; 69 | 70 | for (int32 j = 0; j < Rooms[i].FloorTileWorldLocations.Num(); j++) 71 | { 72 | FVector WorldSpawnLocation = Rooms[i].FloorTileWorldLocations[j]; 73 | SpawnDungeonMesh(FTransform(FRotator::ZeroRotator, WorldSpawnLocation + RoomTemplate.RoomTilePivotOffset), RoomTemplate.RoomTileMesh, RoomTemplate.RoomTileMeshMaterialOverride); 74 | } 75 | 76 | for (int32 j = 0; j < Rooms[i].WallSpawnPoints.Num(); j++) 77 | { 78 | //FVector WorldSpawnLocation = Rooms[i].WallSpawnPoints[j].WorldLocation; 79 | FVector WallModifiedOffset = FVector(); 80 | FRotator WallRotation = CalculateWallRotation(RoomTemplate.bIsWallFacingX, Rooms[i].WallSpawnPoints[j], RoomTemplate.WallMeshPivotOffset, WallModifiedOffset); 81 | FVector WallSpawnLocation = Rooms[i].WallSpawnPoints[j].WorldLocation + WallModifiedOffset; 82 | SpawnDungeonMesh(FTransform(WallRotation, WallSpawnLocation), RoomTemplate.WallMesh, RoomTemplate.WallMeshMaterialOverride); 83 | } 84 | } 85 | 86 | 87 | //Get the 1st element of the data table to retrieve any pivot offsets 88 | //The 1st row of the data table will be used to create corridors connecting various spawned rooms 89 | FVector FloorTileOffset = RoomTemplates[0]->RoomTilePivotOffset; 90 | UStaticMesh* CorridorFloorTile = RoomTemplates[0]->RoomTileMesh; 91 | UStaticMesh* CorridorWall = RoomTemplates[0]->WallMesh; 92 | 93 | //Spawn floor tiles for corridors 94 | for (int32 i = 0; i < CorridorFloorTiles.Num(); i++) 95 | { 96 | //CorridorFloorTiles[i]+=FloorTileOffset; 97 | SpawnDungeonMesh(FTransform(FRotator::ZeroRotator,CorridorFloorTiles[i] + FloorTileOffset), CorridorFloorTile); 98 | } 99 | 100 | bool bCorridorWallFacingX = RoomTemplates[0]->bIsWallFacingX; 101 | FVector RoomTemplateWallOffset = RoomTemplates[0]->WallMeshPivotOffset; 102 | 103 | //Spawn walls for corridors 104 | for (int32 i = 0; i < CorridorWalls.Num(); i++) 105 | { 106 | FVector WallModifiedOffset = FVector(); 107 | FRotator WallRotation = CalculateWallRotation(bCorridorWallFacingX, CorridorWalls[i], RoomTemplateWallOffset, WallModifiedOffset); 108 | FVector WallSpawnPoint = CorridorWalls[i].WorldLocation + WallModifiedOffset; 109 | 110 | SpawnDungeonMesh(FTransform(WallRotation,WallSpawnPoint), CorridorWall); 111 | } 112 | } 113 | 114 | void ADungeonGenerator::SpawnGenericDungeon(const TArray& FloorTileLocations, const TArray& WallSpawnPoints) 115 | { 116 | for (int32 i = 0; i < FloorTileLocations.Num(); i++) 117 | { 118 | //Draw debug boxes if needed 119 | #if WITH_EDITOR 120 | if (bDebugActive) 121 | { 122 | DrawDebugBox(GetWorld(), FloorTileLocations[i], DebugVertexBoxExtents, DefaultFloorSpawnLocationColor.ToFColor(true), true, 1555.f, 15); 123 | DrawDebugBox(GetWorld(), FloorTileLocations[i] + FloorPivotOffset, DebugVertexBoxExtents, OffsetedFloorSpawnLocationColor.ToFColor(true), true, 1555.f, 15); 124 | } 125 | #endif 126 | 127 | SpawnDungeonMesh(FTransform(FRotator::ZeroRotator, FloorTileLocations[i] + FloorPivotOffset), FloorSM); 128 | } 129 | for (int32 i = 0; i < WallSpawnPoints.Num(); i++) 130 | { 131 | 132 | FVector WallModifiedOffset = FVector(); 133 | FRotator WallRotation = CalculateWallRotation(bWallFacingX, WallSpawnPoints[i], WallSMPivotOffset, WallModifiedOffset); 134 | FVector WallSpawnPoint = WallSpawnPoints[i].WorldLocation + WallModifiedOffset; 135 | 136 | //Draw debug boxes if needed 137 | #if WITH_EDITOR 138 | if (bDebugActive) 139 | { 140 | DrawDebugBox(GetWorld(), WallSpawnPoints[i].WorldLocation, DebugVertexBoxExtents, DefaultWallSpawnLocationColor.ToFColor(true), true, 1555.f, 15); 141 | DrawDebugBox(GetWorld(), WallSpawnPoint, DebugVertexBoxExtents, OffsetedWallSpawnLocationColor.ToFColor(true), true, 1555.f, 15); 142 | } 143 | #endif 144 | 145 | SpawnDungeonMesh(FTransform(WallRotation,WallSpawnPoint),WallSM); 146 | } 147 | 148 | if (OnDungeonSpawned.IsBound()) 149 | { 150 | OnDungeonSpawned.Broadcast(); 151 | } 152 | } 153 | 154 | void ADungeonGenerator::DestroyDungeonMeshes() 155 | { 156 | //Erase previously spawned stuff 157 | TArray SpawnedActors; 158 | //const UWorld* World = GetWorld(); 159 | UGameplayStatics::GetAllActorsOfClassWithTag(this, AActor::StaticClass(), DUNGEON_MESH_TAG, SpawnedActors); 160 | 161 | for (int32 i = SpawnedActors.Num() - 1; i >= 0; i--) 162 | { 163 | if (SpawnedActors[i]) 164 | { 165 | SpawnedActors[i]->Destroy(); 166 | } 167 | } 168 | } 169 | 170 | AStaticMeshActor* ADungeonGenerator::SpawnDungeonMesh(const FTransform& InTransform, UStaticMesh* SMToSpawn, UMaterialInterface* OverrideMaterial) 171 | { 172 | FActorSpawnParameters ActorSpawnParams; 173 | ActorSpawnParams.Owner = this; 174 | 175 | AStaticMeshActor* SMActor = GetWorld()->SpawnActor(AStaticMeshActor::StaticClass(), InTransform, ActorSpawnParams); 176 | if (SMActor) 177 | { 178 | //Only needed for runtime because the editor generates warnings and doesn't assign meshes 179 | //Meshes will switch static if used from within the editor 180 | SMActor->SetMobility(EComponentMobility::Movable); 181 | 182 | SMActor->GetStaticMeshComponent()->SetStaticMesh(SMToSpawn); 183 | 184 | if (OverrideMaterial) 185 | { 186 | SMActor->GetStaticMeshComponent()->SetMaterial(0,OverrideMaterial); 187 | } 188 | 189 | SMActor->Tags.Add(DUNGEON_MESH_TAG); 190 | } 191 | return SMActor; 192 | } 193 | 194 | // Sets default values 195 | ADungeonGenerator::ADungeonGenerator() 196 | { 197 | // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. 198 | PrimaryActorTick.bCanEverTick = false; 199 | 200 | } 201 | 202 | // Called when the game starts or when spawned 203 | void ADungeonGenerator::BeginPlay() 204 | { 205 | Super::BeginPlay(); 206 | } 207 | 208 | #if WITH_EDITOR 209 | void ADungeonGenerator::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) 210 | { 211 | Super::PostEditChangeProperty(PropertyChangedEvent); 212 | 213 | if (FloorSM && bAutoFloorTileSizeGeneration) 214 | { 215 | FloorTileSize = CalculateFloorTileSize(*FloorSM); 216 | } 217 | 218 | } 219 | #endif 220 | 221 | void ADungeonGenerator::GenerateDungeon() 222 | { 223 | 224 | TileMatrix = FTileMatrix(TileMapRows, TileMapColumns); 225 | TileMatrix.MaxRandomAttemptsPerRoom = MaxRandomAttemptsPerRoom; 226 | TileMatrix.SetRoomSize(MinRoomSize, MaxRoomSize); 227 | 228 | TileMatrix.CreateRooms(RoomsToGenerate); 229 | DestroyDungeonMeshes(); 230 | 231 | if (RoomTemplatesDataTable) 232 | { 233 | SpawnDungeonFromDataTable(); 234 | } 235 | else 236 | { 237 | if (!FloorSM) 238 | { 239 | UE_LOG(DungeonGenerator, Warning, TEXT("Cannot generate dungeon")); 240 | UE_LOG(DungeonGenerator, Error, TEXT("Invalid FloorSM. Verify you have assigned a valid floor mesh")); 241 | return; 242 | } 243 | 244 | if (!WallSM) 245 | { 246 | UE_LOG(DungeonGenerator, Warning, TEXT("Cannot generate dungeon")); 247 | UE_LOG(DungeonGenerator, Error, TEXT("Invalid WallSM. Verify you have assigned a valid wall mesh")); 248 | return; 249 | } 250 | 251 | TArray FloorTiles; 252 | TArray WallSpawnPoints; 253 | TileMatrix.ProjectTileMapLocationsToWorld(FloorTileSize, FloorTiles, WallSpawnPoints); 254 | SpawnGenericDungeon(FloorTiles, WallSpawnPoints); 255 | } 256 | } 257 | 258 | void ADungeonGenerator::SetNewRoomSize(int32 NewMinRoomSize, int32 NewMaxRoomSize) 259 | { 260 | MinRoomSize = NewMinRoomSize; 261 | MaxRoomSize = NewMaxRoomSize; 262 | } 263 | 264 | void ADungeonGenerator::SetNewFloorMesh(UStaticMesh* NewFloorMesh, FVector NewFloorPivotOffset, bool bAutoFloorSizeGeneration, float OverrideFloorTileSize) 265 | { 266 | if (NewFloorMesh) 267 | { 268 | FloorSM = NewFloorMesh; 269 | 270 | FloorTileSize = (bAutoFloorTileSizeGeneration) ? CalculateFloorTileSize(*FloorSM) : OverrideFloorTileSize; 271 | FloorPivotOffset = NewFloorPivotOffset; 272 | } 273 | } 274 | 275 | void ADungeonGenerator::SetNewWallMesh(UStaticMesh* NewWallMesh, FVector NewWallSMPivotOffset, bool bIsWallFacingX /*= true*/) 276 | { 277 | if (NewWallMesh) 278 | { 279 | WallSM = NewWallMesh; 280 | WallSMPivotOffset = NewWallSMPivotOffset; 281 | bWallFacingX = bIsWallFacingX; 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Source/DungeonGeneratorPlugin/Private/DungeonGeneratorPlugin.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Orfeas Eleftheriou 2 | 3 | #include "DungeonGeneratorPlugin.h" 4 | #include "DungeonGenerator.h" 5 | 6 | #define LOCTEXT_NAMESPACE "FDungeonGeneratorPluginModule" 7 | 8 | void FDungeonGeneratorPluginModule::StartupModule() 9 | { 10 | // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module 11 | } 12 | 13 | void FDungeonGeneratorPluginModule::ShutdownModule() 14 | { 15 | // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 16 | // we call this function before unloading the module. 17 | } 18 | 19 | #undef LOCTEXT_NAMESPACE 20 | 21 | IMPLEMENT_MODULE(FDungeonGeneratorPluginModule, DungeonGeneratorPlugin) -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Source/DungeonGeneratorPlugin/Private/TileMatrix.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Orfeas Eleftheriou 2 | 3 | #include "TileMatrix.h" 4 | 5 | DEFINE_LOG_CATEGORY(TileMatrixLog); 6 | 7 | int32 FTileMatrix::ManhattanDistance(const Tile& A, const Tile& B) 8 | { 9 | return FMath::Abs(A.Key - B.Key) + FMath::Abs(A.Value - B.Value); 10 | } 11 | 12 | void FTileMatrix::StoreGeneratedRoom(const FRoomTileCollection& InRoom) 13 | { 14 | GeneratedRooms.Add(InRoom); 15 | if (GeneratedRooms.Num() > 1) 16 | { 17 | ConnectRooms(InRoom, GeneratedRooms.Last(1)); 18 | } 19 | } 20 | 21 | void FTileMatrix::ConnectRooms(const FRoomTileCollection& A, const FRoomTileCollection& B) 22 | { 23 | TArray OccupiedTilesA = A.OccupiedTiles; 24 | TArray OccupiedTilesB = B.OccupiedTiles; 25 | 26 | TArray TileConnections; 27 | 28 | //Connect all tiles from room with more tiles to all tiles of room with less tiles 29 | if (OccupiedTilesB.Num() > OccupiedTilesA.Num()) 30 | { 31 | for (int32 i = 0; i < OccupiedTilesB.Num(); i++) 32 | { 33 | for (int32 j = 0; j < OccupiedTilesA.Num(); j++) 34 | { 35 | TileConnections.Add(FTileConnection(OccupiedTilesB[i], OccupiedTilesA[j])); 36 | } 37 | } 38 | } 39 | else 40 | { 41 | for (int32 i = 0; i < OccupiedTilesA.Num(); i++) 42 | { 43 | for (int32 j = 0; j < OccupiedTilesB.Num(); j++) 44 | { 45 | TileConnections.Add(FTileConnection(OccupiedTilesA[i], OccupiedTilesB[j])); 46 | } 47 | } 48 | } 49 | 50 | //Find shortest route 51 | //TODO: If PathLength == 1 rooms already connected 52 | int32 PathLength = MAX_int32; 53 | FTileConnection Path; 54 | 55 | for (int32 i = 0; i < TileConnections.Num(); i++) 56 | { 57 | if (TileConnections[i].Length() < PathLength) 58 | { 59 | Path = TileConnections[i]; 60 | PathLength = TileConnections[i].Length(); 61 | } 62 | } 63 | 64 | Tile PivotTile = Path.Start; 65 | 66 | while (PathLength > 1) 67 | { 68 | TArray NearbyTiles = GetNearbyTiles(PivotTile); 69 | int32 TempPath = MAX_int32; 70 | Tile ClosestTile; 71 | //Get closest tile to target based on the nearby tiles 72 | for (int32 i = 0; i < NearbyTiles.Num(); i++) 73 | { 74 | if (ManhattanDistance(NearbyTiles[i], Path.End) < TempPath) 75 | { 76 | TempPath = ManhattanDistance(NearbyTiles[i], Path.End); 77 | ClosestTile = NearbyTiles[i]; 78 | } 79 | } 80 | 81 | //GLog->Log("Added path on:"+TileToString(ClosestTile)); 82 | OccupyTile(ClosestTile); 83 | PivotTile = ClosestTile; 84 | PathLength = ManhattanDistance(PivotTile, Path.End); 85 | } 86 | 87 | } 88 | 89 | FTileMatrix::FTileMatrix() 90 | { 91 | //Init 92 | RowsNum = -1; 93 | ColumnsNum = -1; 94 | GeneratedRooms.Empty(); 95 | } 96 | 97 | FTileMatrix::FTileMatrix(int32 RowCount, int32 ColumnCount) 98 | { 99 | InitTileMap(RowCount, ColumnCount); 100 | } 101 | 102 | TArray FTileMatrix::GetNearbyTiles(const Tile& InTile) const 103 | { 104 | Tile UpTile = Tile(InTile.Key - 1, InTile.Value); 105 | Tile RightTile = Tile(InTile.Key, InTile.Value + 1); 106 | Tile LeftTile = Tile(InTile.Key, InTile.Value - 1); 107 | Tile DownTile = Tile(InTile.Key + 1, InTile.Value); 108 | 109 | TArray NearbyTiles; 110 | if (IsTileInMap(UpTile)) 111 | { 112 | NearbyTiles.Add(UpTile); 113 | } 114 | if (IsTileInMap(RightTile)) 115 | { 116 | NearbyTiles.Add(RightTile); 117 | } 118 | if (IsTileInMap(LeftTile)) 119 | { 120 | NearbyTiles.Add(LeftTile); 121 | } 122 | if (IsTileInMap(DownTile)) 123 | { 124 | NearbyTiles.Add(DownTile); 125 | } 126 | return NearbyTiles; 127 | } 128 | 129 | void FTileMatrix::InitTileMap(int32 Rows, int32 Columns) 130 | { 131 | RowsNum = Rows; 132 | ColumnsNum = Columns; 133 | 134 | TileMap.Empty(); 135 | for (int32 i = 0; i < Rows; i++) 136 | { 137 | TArray SingleRow; 138 | SingleRow.Reserve(Columns); 139 | for (int32 j = 0; j < Columns; j++) 140 | { 141 | SingleRow.Add(false); 142 | } 143 | TileMap.Add(SingleRow); 144 | } 145 | } 146 | 147 | FString FTileMatrix::TileToString(const Tile& InTile) const 148 | { 149 | return FString("[") + FString::FromInt(InTile.Key) + "," + FString::FromInt(InTile.Value) + FString("]"); 150 | } 151 | 152 | void FTileMatrix::SetRoomSize(int32 NewMinRoomSize, int32 NewMaxRoomSize) 153 | { 154 | MinRoomSize = NewMinRoomSize; 155 | MaxRoomSize = NewMaxRoomSize; 156 | } 157 | 158 | FTileMatrix::Tile FTileMatrix::GetRandomTile() const 159 | { 160 | return Tile(FMath::RandRange(0, RowsNum - 1), FMath::RandRange(0, ColumnsNum - 1)); 161 | } 162 | 163 | bool FTileMatrix::IsTileInMap(const Tile& InTile) const 164 | { 165 | return TileMap.IsValidIndex(InTile.Key) && TileMap[InTile.Key].IsValidIndex(InTile.Value); 166 | } 167 | 168 | bool FTileMatrix::IsTileOccupied(Tile InTile) const 169 | { 170 | if (IsTileInMap(InTile)) 171 | { 172 | return (TileMap[InTile.Key])[InTile.Value]; 173 | } 174 | return false; 175 | } 176 | 177 | bool FTileMatrix::AreTilesValid(const TArray& InTiles) const 178 | { 179 | bool bResult = true; 180 | for (int32 i = 0; i < InTiles.Num(); i++) 181 | { 182 | if (!IsTileInMap(InTiles[i]) || IsTileOccupied(InTiles[i])) 183 | { 184 | return false; 185 | } 186 | } 187 | return bResult; 188 | } 189 | 190 | bool FTileMatrix::GetLeftTile(const Tile& InTile, Tile& LeftTile) const 191 | { 192 | if (IsTileInMap(InTile)) 193 | { 194 | LeftTile = InTile; 195 | LeftTile.Value--; 196 | return IsTileInMap(LeftTile); 197 | } 198 | return false; 199 | } 200 | 201 | bool FTileMatrix::GetRightTile(const Tile& InTile, Tile& RightTile) const 202 | { 203 | if (IsTileInMap(InTile)) 204 | { 205 | RightTile = InTile; 206 | RightTile.Value++; 207 | return IsTileInMap(RightTile); 208 | } 209 | return false; 210 | } 211 | 212 | bool FTileMatrix::GetUpTile(const Tile& InTile, Tile& UpTile) const 213 | { 214 | if (IsTileInMap(InTile)) 215 | { 216 | UpTile = InTile; 217 | UpTile.Key--; 218 | return IsTileInMap(UpTile); 219 | } 220 | return false; 221 | } 222 | 223 | bool FTileMatrix::GetDownTile(const Tile& InTile, Tile& DownTile) const 224 | { 225 | if (IsTileInMap(InTile)) 226 | { 227 | DownTile = InTile; 228 | DownTile.Key++; 229 | return IsTileInMap(DownTile); 230 | } 231 | return false; 232 | } 233 | 234 | TArray FTileMatrix::GenerateWallSpawnPointsFromNearbyTiles(const Tile& CenterTile, float TileSize) const 235 | { 236 | TArray WallSpawnPoints; 237 | 238 | FVector FloorCenter = FVector(CenterTile.Key * TileSize, CenterTile.Value * TileSize, 0); 239 | //up = -x 240 | //left = -y 241 | //down = +x 242 | //right = +y 243 | Tile NearbyTile; 244 | 245 | //Get nearby tile for each direction. 246 | //Store a wall location if: 247 | //The nearby tile isn't occupied OR 248 | //The nearby tile is out of bounds from the tilemap (means we're on the edge of the tiles) 249 | if ((GetUpTile(CenterTile, NearbyTile) && !IsTileOccupied(NearbyTile)) 250 | || !GetUpTile(CenterTile, NearbyTile)) 251 | { 252 | FVector WallLocation = FloorCenter - FVector(TileSize / 2.f, 0.f, 0.f); 253 | WallSpawnPoints.Add(FWallSpawnPoint(WallLocation)); 254 | } 255 | if ((GetRightTile(CenterTile, NearbyTile) && !IsTileOccupied(NearbyTile)) 256 | || !GetRightTile(CenterTile, NearbyTile)) 257 | { 258 | FVector WallLocation = FloorCenter + FVector(0.f, TileSize / 2.f, 0.f); 259 | WallSpawnPoints.Add(FWallSpawnPoint(WallLocation, false)); 260 | } 261 | if ((GetDownTile(CenterTile, NearbyTile) && !IsTileOccupied(NearbyTile)) 262 | || !GetDownTile(CenterTile, NearbyTile)) 263 | { 264 | FVector WallLocation = FloorCenter + FVector(TileSize / 2.f, 0.f, 0.f); 265 | WallSpawnPoints.Add(FWallSpawnPoint(WallLocation)); 266 | } 267 | if ((GetLeftTile(CenterTile, NearbyTile) && !IsTileOccupied(NearbyTile)) 268 | || !GetLeftTile(CenterTile, NearbyTile)) 269 | { 270 | FVector WallLocation = FloorCenter - FVector(0.f, TileSize / 2.f, 0.f); 271 | WallSpawnPoints.Add(FWallSpawnPoint(WallLocation, false)); 272 | } 273 | 274 | return WallSpawnPoints; 275 | } 276 | 277 | void FTileMatrix::OccupyTile(const Tile& InTile) 278 | { 279 | TileMap[InTile.Key][InTile.Value] = true; 280 | } 281 | 282 | bool FTileMatrix::CreateUpperRightRoomExpansion(const Tile& StartTile, int32 ExpansionCount, TArray& RoomTiles) const 283 | { 284 | RoomTiles.Empty(); 285 | Tile NewTile = Tile(StartTile.Key + 1, StartTile.Value); 286 | 287 | for (int32 i = 0; i < ExpansionCount; i++) 288 | { 289 | //We're moving up so decrement the key 290 | //NewTile.Key -= i; 291 | NewTile.Key--; 292 | NewTile.Value = StartTile.Value; 293 | 294 | for (int32 j = 0; j < ExpansionCount; j++) 295 | { 296 | //Moving right so increment the value 297 | NewTile.Value--; 298 | RoomTiles.Add(NewTile); 299 | } 300 | } 301 | return AreTilesValid(RoomTiles); 302 | } 303 | 304 | bool FTileMatrix::CreateLowerRightRoomExpansion(const Tile& StartTile, int32 ExpansionCount, TArray& RoomTiles) const 305 | { 306 | RoomTiles.Empty(); 307 | Tile NewTile = Tile(StartTile.Key - 1, StartTile.Value); 308 | 309 | for (int32 i = 0; i < ExpansionCount; i++) 310 | { 311 | //We're moving down so increment the key 312 | NewTile.Key++; 313 | NewTile.Value = StartTile.Value; 314 | for (int32 j = 0; j < ExpansionCount; j++) 315 | { 316 | //Moving right so increment the value 317 | NewTile.Value++; 318 | RoomTiles.Add(NewTile); 319 | } 320 | } 321 | return AreTilesValid(RoomTiles); 322 | } 323 | 324 | bool FTileMatrix::CreateUpperLeftRoomExpansion(const Tile& StartTile, int32 ExpansionCount, TArray& RoomTiles) const 325 | { 326 | RoomTiles.Empty(); 327 | Tile NewTile = Tile(StartTile.Key - 1, StartTile.Value); 328 | 329 | for (int32 i = 0; i < ExpansionCount; i++) 330 | { 331 | //We're moving up so increment the key 332 | NewTile.Key++; 333 | NewTile.Value = StartTile.Value; 334 | for (int32 j = 0; j < ExpansionCount; j++) 335 | { 336 | //Moving left so decrement the value 337 | NewTile.Value--; 338 | RoomTiles.Add(NewTile); 339 | } 340 | } 341 | return AreTilesValid(RoomTiles); 342 | } 343 | 344 | bool FTileMatrix::CreateLowerLeftRoomExpansion(const Tile& StartTile, int32 ExpansionCount, TArray& RoomTiles) const 345 | { 346 | RoomTiles.Empty(); 347 | Tile NewTile = Tile(StartTile.Key + 1, StartTile.Value); 348 | 349 | for (int32 i = 0; i < ExpansionCount; i++) 350 | { 351 | //We're moving down so decrement the key 352 | NewTile.Key--; 353 | NewTile.Value = StartTile.Value; 354 | 355 | for (int32 j = 0; j < ExpansionCount; j++) 356 | { 357 | //Moving left so decrement the value 358 | NewTile.Value--; 359 | RoomTiles.Add(NewTile); 360 | } 361 | } 362 | 363 | return AreTilesValid(RoomTiles); 364 | } 365 | 366 | bool FTileMatrix::CanPlaceRoomInTileMap(Tile InTile, int32 RoomSize, TArray& TilesToOccupy) const 367 | { 368 | TilesToOccupy.Empty(); 369 | if (!IsTileOccupied(InTile)) 370 | { 371 | if (CreateUpperRightRoomExpansion(InTile, RoomSize, TilesToOccupy)) 372 | { 373 | return true; 374 | } 375 | else if (CreateLowerRightRoomExpansion(InTile, RoomSize, TilesToOccupy)) 376 | { 377 | return true; 378 | } 379 | else if (CreateUpperLeftRoomExpansion(InTile, RoomSize, TilesToOccupy)) 380 | { 381 | return true; 382 | } 383 | else if (CreateLowerLeftRoomExpansion(InTile, RoomSize, TilesToOccupy)) 384 | { 385 | return true; 386 | } 387 | } 388 | return false; 389 | } 390 | 391 | void FTileMatrix::CreateRooms(int32 RoomCount) 392 | { 393 | GeneratedRooms.Empty(); 394 | for (int32 i = 0; i < RoomCount; i++) 395 | { 396 | bool bGeneratedRandomRoom = false; 397 | 398 | for (int32 j = 0; j < MaxRandomAttemptsPerRoom && !bGeneratedRandomRoom; j++) 399 | { 400 | int32 RoomSize = FMath::RandRange(MinRoomSize, MaxRoomSize); 401 | Tile RandomTile = GetRandomTile(); 402 | TArray RoomTiles; 403 | 404 | if (CanPlaceRoomInTileMap(RandomTile, RoomSize, RoomTiles)) 405 | { 406 | //Occupy tiles 407 | for (int32 k = 0; k < RoomTiles.Num(); k++) 408 | { 409 | OccupyTile(RoomTiles[k]); 410 | } 411 | StoreGeneratedRoom(FRoomTileCollection(RoomTiles)); 412 | bGeneratedRandomRoom = true; 413 | } 414 | } 415 | 416 | } 417 | //PrintDebugTileMap(); 418 | } 419 | 420 | void FTileMatrix::PrintDebugTileMap() const 421 | { 422 | UE_LOG(TileMatrixLog, Warning, TEXT(" ---- Printing Debug Tile Map ---- ")); 423 | //GLog->Log(" ---- Printing Debug Tile Map ---- "); 424 | for (int32 i = 0; i < TileMap.Num(); i++) 425 | { 426 | FString Row; 427 | for (int32 j = 0; j < TileMap[i].Num() - 1; j++) 428 | { 429 | FString ElementStr = ((TileMap[i])[j]) ? FString("1") : FString("0"); 430 | ElementStr.Append(" - "); 431 | Row.Append(ElementStr); 432 | } 433 | FString ElementStr = ((TileMap[i])[TileMap[i].Num() - 1]) ? FString("1") : FString("0"); 434 | Row.Append(ElementStr); 435 | 436 | //GLog->Log(Row); 437 | UE_LOG(TileMatrixLog, Warning, TEXT("%s"), *FString(Row)); 438 | } 439 | 440 | UE_LOG(TileMatrixLog, Warning, TEXT(" ---- End Of Printing Debug Tile Map ----")); 441 | //GLog->Log(" ---- End Of Printing Debug Tile Map ----"); 442 | } 443 | 444 | void FTileMatrix::ProjectTileMapLocationsToWorld(float TileSize, TArray& FloorLocations, TArray& WallLocations) 445 | { 446 | FloorLocations.Empty(); 447 | WallLocations.Empty(); 448 | 449 | for (int32 i = 0; i < TileMap.Num(); i++) 450 | { 451 | for (int32 j = 0; j < TileMap[i].Num(); j++) 452 | { 453 | Tile CurrentTile = Tile(i, j); 454 | if (IsTileOccupied(CurrentTile)) 455 | { 456 | FVector FloorCenter = FVector(i * TileSize, j * TileSize, 0); 457 | FloorLocations.Add(FloorCenter); 458 | 459 | TArray WallSpawnPoints = GenerateWallSpawnPointsFromNearbyTiles(CurrentTile, TileSize); 460 | for (int32 k = 0; k < WallSpawnPoints.Num(); k++) 461 | { 462 | WallLocations.Add(WallSpawnPoints[k]); 463 | } 464 | } 465 | } 466 | } 467 | } 468 | 469 | void FTileMatrix::ProjectTileMapLocationsToWorld(float TileSize, TArray& Rooms, TArray& CorridorFloorTiles, TArray& CorridorWalls) 470 | { 471 | //Stores the tiles that belong to rooms. If a tile isn't included in this set then it's a generic tile 472 | //And should be stored in the CorridorFloorTiles array (same goes with its respective walls) 473 | TSet RecordedRoomTiles; 474 | 475 | Rooms.Empty(); 476 | Rooms.Reserve(GeneratedRooms.Num() - 1); 477 | 478 | //Storing each room's tiles into a separate FRoom element 479 | for (int32 i = 0; i < GeneratedRooms.Num(); i++) 480 | { 481 | FRoom NewRoom; 482 | TArray RoomTiles = GeneratedRooms[i].OccupiedTiles; 483 | 484 | for (int32 j = 0; j < RoomTiles.Num(); j++) 485 | { 486 | Tile CurrentTile = RoomTiles[j]; 487 | RecordedRoomTiles.Add(CurrentTile); //Mark this tile as visited 488 | 489 | FVector FloorCenter = FVector(CurrentTile.Key * TileSize, CurrentTile.Value * TileSize, 0); 490 | NewRoom.FloorTileWorldLocations.Add(FloorCenter); 491 | TArray RoomWallSpawnPoints = GenerateWallSpawnPointsFromNearbyTiles(CurrentTile, TileSize); 492 | for (int32 k = 0; k < RoomWallSpawnPoints.Num(); k++) 493 | { 494 | NewRoom.WallSpawnPoints.Add(RoomWallSpawnPoints[k]); 495 | } 496 | 497 | } 498 | Rooms.Add(NewRoom); 499 | } 500 | 501 | for (int32 i = 0; i < TileMap.Num(); i++) 502 | { 503 | for (int32 j = 0; j < TileMap[i].Num(); j++) 504 | { 505 | Tile CurrentTile = Tile(i, j); 506 | if (IsTileOccupied(CurrentTile) && !RecordedRoomTiles.Contains(CurrentTile)) 507 | { 508 | FVector FloorCenter = FVector(i * TileSize, j * TileSize, 0); 509 | CorridorFloorTiles.Add(FloorCenter); 510 | 511 | TArray WallSpawnPoints = GenerateWallSpawnPointsFromNearbyTiles(CurrentTile, TileSize); 512 | for (int32 k = 0; k < WallSpawnPoints.Num(); k++) 513 | { 514 | CorridorWalls.Add(WallSpawnPoints[k]); 515 | } 516 | } 517 | } 518 | } 519 | } 520 | -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Source/DungeonGeneratorPlugin/Public/DungeonGenerator.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Orfeas Eleftheriou 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "GameFramework/Actor.h" 7 | #include "TileMatrix.h" 8 | #include "Engine/DataTable.h" 9 | #include "DungeonGenerator.generated.h" 10 | 11 | DECLARE_LOG_CATEGORY_EXTERN(DungeonGenerator, Log, All); 12 | 13 | class AStaticMeshActor; 14 | class UStaticMesh; 15 | class UMaterialInterface; 16 | 17 | DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnDungeonSpawned); 18 | 19 | USTRUCT(BlueprintType) 20 | struct FRoomTemplate : public FTableRowBase 21 | { 22 | GENERATED_BODY() 23 | 24 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RoomTemplate") 25 | UStaticMesh* RoomTileMesh; 26 | 27 | /** 28 | * If assigned, we're going to replace the default material of the RoomTileMesh with the given mat 29 | * Leave empty in case you want the default material 30 | * Useful in cases where you want the same static mesh but with different material variations as room templates 31 | */ 32 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category= "RoomTemplate") 33 | UMaterialInterface* RoomTileMeshMaterialOverride; 34 | 35 | /** 36 | * Same functionality as FloorPivotOffset - check comments in Source Code or In-Editor Details Panel! 37 | */ 38 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RoomTemplate") 39 | FVector RoomTilePivotOffset; 40 | 41 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RoomTemplate") 42 | UStaticMesh* WallMesh; 43 | 44 | /** 45 | * Used to replace default material of WallMesh 46 | * Check RoomTileMeshMaterialOverride docs for more info 47 | */ 48 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RoomTemplate") 49 | UMaterialInterface* WallMeshMaterialOverride; 50 | 51 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RoomTemplate") 52 | FVector WallMeshPivotOffset; 53 | 54 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RoomTemplate") 55 | bool bIsWallFacingX = true; 56 | }; 57 | 58 | 59 | UCLASS() 60 | class DUNGEONGENERATORPLUGIN_API ADungeonGenerator : public AActor 61 | { 62 | GENERATED_BODY() 63 | 64 | private: 65 | 66 | /** 67 | * The tile matrix we're going to use to generate the floor tile locations and the wall locations / rotations 68 | */ 69 | FTileMatrix TileMatrix; 70 | 71 | /*void SpawnFloorTiles(const TArray& SpawnLocations, UMaterialInterface* MaterialOverride = nullptr); 72 | 73 | void SpawnWallTiles(const TArray& SpawnLocations, UMaterialInterface* MaterialOverride = nullptr);*/ 74 | 75 | /** 76 | * Destroys all previously generated meshes from this dungeon generator 77 | */ 78 | void DestroyDungeonMeshes(); 79 | 80 | /** 81 | * Spawns the assigned floorsm at the given transform 82 | * @param InTransform - the transform to spawn the mesh at 83 | * @param SMToSpawn - the mesh to spawn 84 | * @param OverrideMaterial - if assigned, we're going to replace the 1st default material of SMToSpawn 85 | * @return the spawned mesh. Should check for nullptr 86 | */ 87 | AStaticMeshActor* SpawnDungeonMesh(const FTransform& InTransform, UStaticMesh* SMToSpawn, UMaterialInterface* OverrideMaterial = nullptr); 88 | 89 | /** 90 | * Checks the bounding box of the mesh and returns its extend along Y axis 91 | * @return the extend along Y axis 92 | */ 93 | float CalculateFloorTileSize(const UStaticMesh& Mesh) const; 94 | 95 | /** 96 | * Checks if a wall mesh needs to be rotated by 90 degrees 97 | * @param bWallFacingXProperty - true if the wall mesh we're using is facing the X axis 98 | * @param WallSpawnPoint - the wall spawn point we're using in order to spawn the wall 99 | * @param LocationOffset - in case the wall needs rotating, we're first applying any rotation and then generate a correct location offset based on the original one 100 | * @return the correct rotation of the assigned wall mesh 101 | */ 102 | FRotator CalculateWallRotation(bool bWallFacingXProperty, const FTileMatrix::FWallSpawnPoint& WallSpawnPoint, const FVector& WallPivotOffsetOverride, FVector& LocationOffset) const; 103 | 104 | /** 105 | * Spawns a dungeon using random room templates from a provided data table 106 | * Assumes the data table contains correct values in terms of mesh sizes etc. 107 | */ 108 | void SpawnDungeonFromDataTable(); 109 | 110 | /** 111 | * Spawns a generic dungeon using the same floor mesh and wall mesh for all the rooms/corridors 112 | * @param FloorTileLocation - the locations for each floor tile 113 | * @param WallSpawnPoints - the spawn points for each wall 114 | */ 115 | void SpawnGenericDungeon(const TArray& FloorTileLocations, const TArray& WallSpawnPoints); 116 | 117 | public: 118 | // Sets default values for this actor's properties 119 | ADungeonGenerator(); 120 | 121 | #if WITH_EDITOR 122 | 123 | virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; 124 | 125 | #endif 126 | 127 | /* True if you want the editor to auto-retrieve the extends of the mesh */ 128 | UPROPERTY(EditAnywhere, Category = "Generator Properties") 129 | bool bAutoFloorTileSizeGeneration = true; 130 | 131 | protected: 132 | // Called when the game starts or when spawned 133 | virtual void BeginPlay() override; 134 | 135 | /** 136 | * Number of rows in tile map 137 | * Total size of tile map will be Rows * Columns 138 | */ 139 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Generator Properties") 140 | int32 TileMapRows = 50; 141 | 142 | /** 143 | * Number of columns in tile map 144 | * Total size of tile map will be Rows * Columns 145 | */ 146 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Generator Properties") 147 | int32 TileMapColumns = 50; 148 | 149 | /** 150 | * MinRoomSize is the min number of tiles we're going to use for each room in each direction. 151 | * For instance, a number of 2 means that the min room size can be 2x2 152 | */ 153 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Generator Properties") 154 | int32 MinRoomSize = 5; 155 | 156 | /** 157 | * MaxRoomSize is the max number of tiles we're going to use for each room in each direction. 158 | * For instance, a number of 3 means that the max room size can be 3x3. 159 | */ 160 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Generator Properties") 161 | int32 MaxRoomSize = 7; 162 | 163 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Generator Properties") 164 | int32 RoomsToGenerate = 15; 165 | 166 | /** 167 | * Max Random Attempts for each room. To avoid an infinite loop try to find a fitting room for a location only a certain amount of times. 168 | * If the process fails just proceed to the next room 169 | */ 170 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category= "Generator Properties") 171 | int32 MaxRandomAttemptsPerRoom = 1500; 172 | 173 | /** 174 | * The static mesh for each floor 175 | */ 176 | UPROPERTY(EditAnywhere, Category = "Generator Properties - Floor Settings") 177 | UStaticMesh* FloorSM; 178 | 179 | /** 180 | * Tile size of floor SM. If you manually want to override this setting use the //TODO: Create function 181 | */ 182 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Generator Properties - Floor Settings") 183 | float FloorTileSize; 184 | 185 | /** 186 | * By default, each tile location is pointing at the center of the tile. If your FloorSM isn't 187 | * centered, adjust this value to match your settings 188 | * For instance, if the floor's pivot point is located on the bottom left corner the FloorPivotOffset 189 | * needs to be (-TileSize_X,-TileSize_Y,0) 190 | */ 191 | UPROPERTY(EditAnywhere, Category = "Generator Properties - Floor Settings") 192 | FVector FloorPivotOffset; 193 | 194 | /** 195 | * Static mesh of walls 196 | */ 197 | UPROPERTY(EditAnywhere, Category = "Generator Properties - Wall Settings") 198 | UStaticMesh* WallSM; 199 | 200 | /** 201 | * By default, each wall location is centered at the top,right,left or bottom middle of each tile. If your 202 | * WallSM isn't centered, adjust this value to match your settings 203 | * See FloorPivotOffset for more info regarding this setting. 204 | */ 205 | UPROPERTY(EditAnywhere, Category = "Generator Properties - Wall Settings") 206 | FVector WallSMPivotOffset; 207 | 208 | /** 209 | * If the wall is facing the X axis (ie the wall is extending by default along the Y axis) mark this setting as true and false otherwise 210 | * During wall spawning the generator will make sure to rotate the walls accordingly 211 | */ 212 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Generator Properties - Wall Settings") 213 | bool bWallFacingX = true; 214 | 215 | /** 216 | * A data table describing some room templates in order to spawn various floor tiles & wall meshes 217 | * Assumes that the assigned floor and wall meshes have the same dimensions as the generic floor and wall meshes 218 | */ 219 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Generator Properties") 220 | UDataTable* RoomTemplatesDataTable; 221 | 222 | public: 223 | 224 | /** 225 | * Will assign this tag to each mesh that is spawned by the generator. 226 | * Used to destroy any previously generated dungeons if needed 227 | */ 228 | static const FName DUNGEON_MESH_TAG; 229 | 230 | /** 231 | * Generates a dungeon 232 | */ 233 | UFUNCTION(BlueprintCallable, CallInEditor, Category = "Dungeon Generation") 234 | void GenerateDungeon(); 235 | 236 | /** 237 | * Sets new properties regarding the room size 238 | * @param NewMinRoomSize - the minimum room size (uniform) 239 | * @param NewMaxRoomSize - the maximum room size (uniform) 240 | */ 241 | UFUNCTION(BlueprintCallable, Category = "Dungeon Generation") 242 | void SetNewRoomSize(int32 NewMinRoomSize, int32 NewMaxRoomSize); 243 | 244 | /** 245 | * Assigns a new floor mesh for the dungeon generator 246 | * @param NewFloorMesh - the mesh to use for each floor tile 247 | * @param NewFloorPivotOffset - any offset to apply if the floor tile mesh hasn't a centered pivot point 248 | * @param bAutoFloorSizeGeneration - true if you want the generator to generate the tile size for you 249 | * @param OverrideFloorTileSize - the tile size. Only takes effect when bAutoFloorSizeGeneration is set to false 250 | */ 251 | UFUNCTION(BlueprintCallable, Category = "Dungeon Generation") 252 | void SetNewFloorMesh(UStaticMesh* NewFloorMesh, FVector NewFloorPivotOffset, bool bAutoFloorSizeGeneration = true, float OverrideFloorTileSize = 0.f); 253 | 254 | /** 255 | * Assigns a new wall mesh for the dungeon generator 256 | * @param NewWallMesh - the mesh to use for each wall 257 | * @param NewWallSMPivotOffset - any offset to apply if the wall isn't centered 258 | * @param bIsWallFacingX - true if the wall is facing the X axis (ie it extends along the Y axis), false otherwise 259 | */ 260 | UFUNCTION(BlueprintCallable, Category = "Dungeon Generation") 261 | void SetNewWallMesh(UStaticMesh* NewWallMesh, FVector NewWallSMPivotOffset, bool bIsWallFacingX = true); 262 | 263 | /** 264 | * Called when dungeon generator has finished spawning all the meshes 265 | */ 266 | UPROPERTY(BlueprintAssignable, Category = "Dungeon Generation") 267 | FOnDungeonSpawned OnDungeonSpawned; 268 | 269 | #if WITH_EDITORONLY_DATA 270 | 271 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dungeon Generation - Debug") 272 | bool bDebugActive=false; 273 | 274 | /** 275 | * If debug is active the generator will spawn boxes in each spawn location. 276 | * Adjust the size of the box here and the individual colors below 277 | */ 278 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dungeon Generation - Debug") 279 | FVector DebugVertexBoxExtents; 280 | 281 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dungeon Generation - Debug") 282 | FLinearColor DefaultFloorSpawnLocationColor; 283 | 284 | /** 285 | * If no offset is used this will overlap with DefaultFloorSpawnLocationColor box 286 | */ 287 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dungeon Generation - Debug") 288 | FLinearColor OffsetedFloorSpawnLocationColor; 289 | 290 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dungeon Generation - Debug") 291 | FLinearColor DefaultWallSpawnLocationColor; 292 | 293 | /** 294 | * If no offset is used this will overlap with DefaultWallSpawnLocationColor box 295 | */ 296 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dungeon Generation - Debug") 297 | FLinearColor OffsetedWallSpawnLocationColor; 298 | 299 | #endif 300 | 301 | }; 302 | -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Source/DungeonGeneratorPlugin/Public/DungeonGeneratorPlugin.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Orfeas Eleftheriou 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Modules/ModuleManager.h" 7 | 8 | class FDungeonGeneratorPluginModule : public IModuleInterface 9 | { 10 | 11 | public: 12 | 13 | /** IModuleInterface implementation */ 14 | virtual void StartupModule() override; 15 | virtual void ShutdownModule() override; 16 | }; 17 | -------------------------------------------------------------------------------- /Plugins/DungeonGeneratorPlugin/Source/DungeonGeneratorPlugin/Public/TileMatrix.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Orfeas Eleftheriou 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | DECLARE_LOG_CATEGORY_EXTERN(TileMatrixLog, Log, All); 8 | 9 | /** 10 | * 11 | */ 12 | class DUNGEONGENERATORPLUGIN_API FTileMatrix 13 | { 14 | public: 15 | 16 | /** 17 | * Handy structure which stores a wall spawn point in the world 18 | * Contains a boolean property to determine if we want to rotate the wall later on depending on the assigned wall settings in the Dungeon Generator 19 | */ 20 | struct FWallSpawnPoint 21 | { 22 | /* World location of this point */ 23 | FVector WorldLocation; 24 | 25 | /************************************************************************/ 26 | /* Used to determine which walls to rotate during spawning. */ 27 | /* By default this property is true to sync settings between Dungeon */ 28 | /* Generator. If the wall settings on the Dungeon Generator are flipped */ 29 | /* the correct rotation is determined from the Dungeon Generator */ 30 | /************************************************************************/ 31 | 32 | bool bFacingX; 33 | 34 | FWallSpawnPoint() : WorldLocation(FVector()), bFacingX(true) {} 35 | 36 | FWallSpawnPoint(FVector NewWorldLocation) : WorldLocation(NewWorldLocation), bFacingX(true) {} 37 | 38 | FWallSpawnPoint(FVector NewWorldLocation, bool IsFacingX) : WorldLocation(NewWorldLocation), bFacingX(IsFacingX) {} 39 | }; 40 | 41 | FTileMatrix(); 42 | 43 | FTileMatrix(int32 RowCount, int32 ColumnCount); 44 | 45 | /** 46 | * Returns true if the tile matrix has generated a tilemap 47 | */ 48 | inline bool IsValid() const { return RowsNum > 0 && ColumnsNum > 0; } 49 | 50 | /** 51 | * Initializes tile map to Rows * Columns. 52 | * @param Rows - the total number of rows 53 | * @param Columns - the total number of columns 54 | */ 55 | void InitTileMap(int32 Rows, int32 Columns); 56 | 57 | /** 58 | * Sets the new min and max room sizes. 59 | * Keep in mind that size is uniform ie a value of 2 means that a room will try to occupy 4 tiles (2 in horizontal axis and 2 in vertical) 60 | * @param NewMinRoomSize - the minimum size of the room in terms of tiles 61 | * @param NewMaxRoomSize - the maximum size of the room in terms of tiles 62 | */ 63 | void SetRoomSize(int32 NewMinRoomSize, int32 NewMaxRoomSize); 64 | 65 | /** 66 | * Max Random Attempts for each room. To avoid an infinite loop try to find a fitting room for a location only a certain amount of times. 67 | * If the process fails just proceed to the next room 68 | */ 69 | int32 MaxRandomAttemptsPerRoom = 1500; 70 | 71 | /** 72 | * Will try to create <=RoomCount rooms in the tilemap. 73 | * If you're unlucky with the pseudorandoms you'll get fewer rooms. 74 | * If you're getting a lower room count than what you expect try to fine tune Rows and Columns of TileMap as well as the MaxRandomAttemptsPerRoom 75 | * @param RoomCount - max rooms to generate 76 | */ 77 | void CreateRooms(int32 RoomCount); 78 | 79 | /** 80 | * Prints the generated Tile Map in the console 81 | */ 82 | void PrintDebugTileMap() const; 83 | 84 | /** 85 | * Project the generated Tile Map in the world 86 | * @param TileSize - the size of each tile (ie floor size) 87 | * @param FloorLocations - the world location for every floor tile 88 | * @param WallLocations - the world locations for every wall mesh packed in a FWallSpawnPoint structure to handle any rotations that need to take place 89 | */ 90 | void ProjectTileMapLocationsToWorld(float TileSize, TArray& FloorLocations, TArray& WallLocations); 91 | 92 | struct FRoom 93 | { 94 | TArray FloorTileWorldLocations; 95 | TArray WallSpawnPoints; 96 | }; 97 | 98 | void ProjectTileMapLocationsToWorld(float TileSize, TArray& Rooms, TArray& CorridorFloorTiles, TArray& CorridorWalls); 99 | 100 | protected: 101 | 102 | /** 103 | * Key: row of tile in TileMap 104 | * Value: column of tile in TileMap 105 | */ 106 | typedef TTuple Tile; 107 | 108 | /** 109 | * Manhattan distance / Taxicab metric between two tiles 110 | * @param A the first tile 111 | * @param B the second tile 112 | * @return the distance between A and B 113 | */ 114 | static int32 ManhattanDistance(const Tile& A, const Tile& B); 115 | 116 | /** 117 | * Converts a tile to a readable string 118 | */ 119 | FString TileToString(const Tile& InTile) const; 120 | 121 | private: 122 | 123 | /*TileMap Rows*/ 124 | int32 RowsNum; 125 | /*TileMap Columns*/ 126 | int32 ColumnsNum; 127 | 128 | /** 129 | * Contents of this matrix. 130 | * True values mean that a location / tile is occupied. 131 | * False for tiles that are available 132 | */ 133 | TArray> TileMap; 134 | 135 | 136 | /** 137 | * Room Sizes = tile count in length & width 138 | */ 139 | int32 MinRoomSize = 2; 140 | int32 MaxRoomSize = 4; 141 | 142 | /** 143 | * Gets a random tile from the TileMap 144 | * @return a random tile 145 | */ 146 | Tile GetRandomTile() const; 147 | 148 | /** 149 | * Gets nearby tiles of a tile 150 | * @param InTile - a tile in the tile map 151 | * @return an array of tiles, containing tiles with a distance of 1 in directions up, right, left and down 152 | */ 153 | TArray GetNearbyTiles(const Tile& InTile) const; 154 | 155 | /** 156 | * Checking indices of tile to verify they are inside tile map's indices 157 | */ 158 | bool IsTileInMap(const Tile& InTile) const; 159 | 160 | /** 161 | * Checks if a tile is occupied (ie its location in the TileMap is marked as true) 162 | * @param InTile - the tile to check 163 | * @return true if the corresponding location of the TileMap is marked as true, false otherwise 164 | */ 165 | bool IsTileOccupied(Tile InTile) const; 166 | 167 | /** 168 | * Checks if all provided tiles are: 169 | * Inside the tile map and 170 | * NOT occupied 171 | * @return true if all tiles are inside the tile map and available 172 | */ 173 | bool AreTilesValid(const TArray& InTiles) const; 174 | 175 | /** 176 | * Gets the tile which is located on the left side of a given tile 177 | * @param InTile - the "pivot" tile 178 | * @param LeftTile - the tile which is sitting on the left side of the pivot tile 179 | * @return true, if the LeftTile is within the tilemap, false if we're on an edge case (meaning the InTile is the left-most tile in the tilemap) 180 | */ 181 | bool GetLeftTile(const Tile& InTile, Tile& LeftTile) const; 182 | 183 | /** 184 | * Gets the tile which is located on the right side of a given tile 185 | * @param InTile - the "pivot" tile 186 | * @param RightTile - the tile which is sitting on the right side of the pivot tile 187 | * @return true, if the RightTile is within the tilemap, false if we're on an edge case (meaning the InTile is the right-most tile in the tilemap) 188 | */ 189 | bool GetRightTile(const Tile& InTile, Tile& RightTile) const; 190 | 191 | /** 192 | * Gets the tile which is located above a given tile 193 | * @param InTile - the "pivot" tile 194 | * @param UpTile - the tile which is sitting above the pivot tile 195 | * @return true, if the UpTile is within the tilemap, false if we're on an edge case (meaning the InTile doesn't have a tile above) 196 | */ 197 | bool GetUpTile(const Tile& InTile, Tile& UpTile) const; 198 | 199 | /** 200 | * Gets the tile which is located bellow a given tile 201 | * @param InTile - the "pivot" tile 202 | * @param DownTile - the tile which is sitting bellow the pivot tile 203 | * @return true, if the DownTile is within the tilemap, false if we're on an edge case (meaning the InTile doesn't have a tile bellow) 204 | */ 205 | bool GetDownTile(const Tile& InTile, Tile& DownTile) const; 206 | 207 | TArray GenerateWallSpawnPointsFromNearbyTiles(const Tile& CenterTile, float TileSize) const; 208 | 209 | /** 210 | * Marks the corresponding tilemap tile as true 211 | */ 212 | void OccupyTile(const Tile& InTile); 213 | 214 | /** 215 | * Starts from a location and expands tiles to occupy the same space along up & right directions 216 | * @param StartTile - the starting tile of the expansion 217 | * @param ExpansionCount - the size of tiles to occupy above and right (ie a value of 3 will try to take up 9 tiles in total) 218 | * @param RoomTiles - tiles that correspond to the specific expansion 219 | * @return true, if all RoomTiles are valid, false otherwise 220 | */ 221 | bool CreateUpperRightRoomExpansion(const Tile& StartTile, int32 ExpansionCount, TArray& RoomTiles) const; 222 | 223 | /* See CreateUpperRightRoomExpansion */ 224 | bool CreateLowerRightRoomExpansion(const Tile& StartTile, int32 ExpansionCount, TArray& RoomTiles) const; 225 | 226 | /* See CreateUpperRightRoomExpansion */ 227 | bool CreateUpperLeftRoomExpansion(const Tile& StartTile, int32 ExpansionCount, TArray& RoomTiles) const; 228 | 229 | /* See CreateUpperRightRoomExpansion */ 230 | bool CreateLowerLeftRoomExpansion(const Tile& StartTile, int32 ExpansionCount, TArray& RoomTiles) const; 231 | 232 | /** 233 | * Handy way to store a connection between tiles 234 | */ 235 | struct FTileConnection 236 | { 237 | Tile Start; 238 | Tile End; 239 | 240 | FTileConnection() 241 | { 242 | Start = Tile(0, 0); 243 | End = Tile(0, 0); 244 | } 245 | FTileConnection(const Tile& TileA, const Tile& TileB) : Start(TileA), End(TileB) {} 246 | 247 | inline int32 Length() const { return ManhattanDistance(Start, End); } 248 | }; 249 | 250 | /** 251 | * Handy way of storing separate room tiles in a collection 252 | */ 253 | struct FRoomTileCollection 254 | { 255 | TArray OccupiedTiles; 256 | 257 | FRoomTileCollection() 258 | { 259 | OccupiedTiles.Empty(); 260 | } 261 | FRoomTileCollection(TArray RoomTiles) 262 | { 263 | OccupiedTiles = RoomTiles; 264 | } 265 | }; 266 | 267 | /** 268 | * A collection of GeneratedRooms 269 | */ 270 | TArray GeneratedRooms; 271 | 272 | /** 273 | * Stores a new generated room. 274 | * Once we have more than a single room will also call the ConnectRooms to connect newly spawned rooms 275 | * @param InRoom - the new room we want to store 276 | */ 277 | void StoreGeneratedRoom(const FRoomTileCollection& InRoom); 278 | 279 | /** 280 | * Finds the closest tiles between two rooms and connects them in the shortest possible distance 281 | * @param A - the first room of the connection 282 | * @param B - the second room to connect to first 283 | */ 284 | void ConnectRooms(const FRoomTileCollection& A, const FRoomTileCollection& B); 285 | 286 | /** 287 | * Goes through all possible room expansions in a location to see if a room of a given size can be placed 288 | * in the tilemap 289 | * @param InTile - a tile to use as a starting location for the expansion 290 | * @param RoomSize - uniform size of the room 291 | * @param TilesToOccupy - expanded tiles of the room 292 | * @return true, if the room can be placed in the tilemap, false otherwise 293 | */ 294 | bool CanPlaceRoomInTileMap(Tile InTile, int32 RoomSize, TArray& TilesToOccupy) const; 295 | }; 296 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DungeonGenerator 2 | A (hopefully) handy Unreal Engine 5 Dungeon Generator 3 | 4 | Updated for 5.4 5 | 6 | ![Generator gif showcase](Docs/Images/RuntimeGeneration.gif) 7 | 8 | Read the full docs here: https://github.com/orfeasel/DungeonGenerator/blob/main/Docs/HowToUse.pdf 9 | 10 | ### TL;DR 11 | 12 | - Place the dungeon generator in your level 13 | - Assign a static mesh for your floor tiles to FloorSM 14 | - Assign a static mesh for your walls to WallSM 15 | - Click the generate dungeon button 16 | 17 | ![Options image](Docs/Images/Options.png) 18 | 19 | ### Available BP nodes 20 | 21 | ![BP Nodes](Docs/Images/BPFunctions.png) 22 | -------------------------------------------------------------------------------- /Source/DungeonGeneratorDev.Target.cs: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | using System.Collections.Generic; 5 | 6 | public class DungeonGeneratorDevTarget : TargetRules 7 | { 8 | public DungeonGeneratorDevTarget( TargetInfo Target) : base(Target) 9 | { 10 | Type = TargetType.Game; 11 | DefaultBuildSettings = BuildSettingsVersion.V2; 12 | ExtraModuleNames.AddRange( new string[] { "DungeonGeneratorDev" } ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Source/DungeonGeneratorDev/DungeonGeneratorDev.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class DungeonGeneratorDev : ModuleRules 6 | { 7 | public DungeonGeneratorDev(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" }); 12 | 13 | PrivateDependencyModuleNames.AddRange(new string[] { }); 14 | 15 | PublicIncludePaths.AddRange(new string[] {"DungeonGeneratorDev" }); 16 | 17 | // Uncomment if you are using Slate UI 18 | // PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" }); 19 | 20 | // Uncomment if you are using online features 21 | // PrivateDependencyModuleNames.Add("OnlineSubsystem"); 22 | 23 | // To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Source/DungeonGeneratorDev/DungeonGeneratorDev.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "DungeonGeneratorDev.h" 4 | #include "Modules/ModuleManager.h" 5 | 6 | IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, DungeonGeneratorDev, "DungeonGeneratorDev" ); 7 | -------------------------------------------------------------------------------- /Source/DungeonGeneratorDev/DungeonGeneratorDev.h: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | -------------------------------------------------------------------------------- /Source/DungeonGeneratorDev/DungeonGeneratorDevGameModeBase.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | 4 | #include "DungeonGeneratorDevGameModeBase.h" 5 | 6 | -------------------------------------------------------------------------------- /Source/DungeonGeneratorDev/DungeonGeneratorDevGameModeBase.h: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "GameFramework/GameModeBase.h" 7 | #include "DungeonGeneratorDevGameModeBase.generated.h" 8 | 9 | /** 10 | * 11 | */ 12 | UCLASS() 13 | class DUNGEONGENERATORDEV_API ADungeonGeneratorDevGameModeBase : public AGameModeBase 14 | { 15 | GENERATED_BODY() 16 | 17 | }; 18 | -------------------------------------------------------------------------------- /Source/DungeonGeneratorDevEditor.Target.cs: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | using System.Collections.Generic; 5 | 6 | public class DungeonGeneratorDevEditorTarget : TargetRules 7 | { 8 | public DungeonGeneratorDevEditorTarget( TargetInfo Target) : base(Target) 9 | { 10 | Type = TargetType.Editor; 11 | DefaultBuildSettings = BuildSettingsVersion.V5; 12 | ExtraModuleNames.AddRange( new string[] { "DungeonGeneratorDev" } ); 13 | } 14 | } 15 | --------------------------------------------------------------------------------