diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..56e4a58
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,146 @@
+# Change Log
+
+## [Unreleased] -1.5.1 (15)
+### Changes
+### 変更点
+
+## 20231010-1.5.0 (14)
+### Changes
+### 変更点
+
+## 20230930-1.4.8 (13)
+### Changes
+* Fixed a bug when the start room was not set
+### 変更点
+* スタート部屋を未設定の時の不具合を修正
+
+## 20230920-1.4.7 (12)
+### Changes
+* Register dungeon mesh in DungeonPartsDatabase asset
+* Fixed some bugs
+### 変更点
+* DungeonPartsDatabaseアセットにダンジョンのメッシュを登録
+* いくつかの不具合を修正
+
+## 20230908-1.4.6 (11)
+### Changes
+* Support for Unreal Engine 5.3
+* Unreal Engine 4 no longer supported
+* Support for loading sublevels in the start and finish rooms
+* Added plug-in content
+### 変更点
+* Unreal Engine 5.3に対応
+* Unreal Engine 4のサポートを終了
+* スタート部屋、ゴール部屋のサブレベル読み込みに対応
+* プラグインコンテンツの追加
+
+## 20230901-1.4.5 (10)
+### Changes
+* Modified to generate dungeons on a flat surface if room merging or room margins are less than 1
+* Added minimap information asset
+* Added world space to texture space conversion class
+* modified paths for plugin content
+* Added sample data to plugin, eliminated dungeon hierarchy specification
+* Fixed cache misalignment in system tags
+* Started network functionality verification
+* Moved PlayerStart off center of start room if more than one PlayerStart was installed
+### 変更点
+* 部屋の結合または部屋の余白が1以下ならば平面にダンジョンを生成するように修正
+* ミニマップ情報アセットを追加
+* ワールド空間からテクスチャ空間への変換クラスを追加
+* プラグインコンテンツのパスを修正
+* プラグインにサンプルデータを追加、ダンジョンの階層指定を廃止
+* システムタグのキャッシュずれを修正
+* ネットワーク機能検証開始
+* PlayerStartが複数設置されていた場合はスタート部屋の中心からずらして配置
+
+
+## 20230801-1.4.4 (9)
+### Changes
+* Interior Decorator beta version released
+* Added interior assets
+* Fixed some bugs
+### 変更点
+* インテリアデコレーターベータ版リリース
+* インテリアアセットを追加
+* いくつかの不具合を修正
+
+
+## 20230514-1.4.3 (8)
+### Changes
+* Interior Decorator Verification
+* Removed sample models as plug-in assets were added
+### 変更点
+* インテリアデコレーターの検証
+* プラグインアセットを追加に伴ってサンプルモデルを削除
+
+
+## 20230514-1.4.2 (7)
+### Changes
+* UE5.2 support
+* Supports sub-level merging
+* Copy LevelStreaming actors in editor mode to level
+### 変更点
+* Unreal Engine 5.2に対応
+* サブレベルのマージに対応
+* エディタモードの LevelStreamingアクターをレベルにコピー
+
+
+## 20230409-v1.4.1 (6)
+### Changes
+* Confirmed that the package can be created.
+* Add a test that generates pre-created sublevels in the room.
+* Add a test for vertical margins.
+* Add a test generation of minimap texture assets.
+### 変更点
+* パッケージが作成できることを確認
+* 部屋にあらかじめ作成されたサブレベルを生成するテスト
+* 垂直マージンのテスト
+* ミニマップのテクスチャアセットの生成テスト
+
+
+## 20230403-v1.4.0 (5)
+### Changes
+* Generate mini-maps in two types of pixel size and resolution (dots/meters)
+### 変更点
+* ミニマップをピクセルサイズと解像度(ドット/メートル)の二種類から生成
+
+
+## 20230321-v1.3.1 (4)
+### Changes
+* Fixed mini-map generationo fail.
+### 変更点
+* ミニマップ生成時にクラッシュする問題を修正
+
+
+## 20230319-v1.3.0 (3)
+### Changes
+* Supports mini-maps
+### 変更点
+* ミニマップに対応
+
+
+## 20230316-v1.2.0 (2)
+### Changes
+* Compatible with Unreal Engine 4.27.2
+### 変更点
+* Unreal Engine 4.27.2に対応
+
+
+## 20230308-v1.0.1 (1)
+### Changes
+* Fixed hang-up when referencing minimap textures when dungeon creation fails.
+* Changed random room placement method to be more randomly distributed.
+* Improved dungeon creation speed.
+### 変更点
+* ダンジョン生成に失敗した時にミニマップのテクスチャを参照するとハングアップする問題を修正
+* 部屋のランダム配置方法をよりランダムに分散するよう変更
+* ダンジョン生成速度を改善
+
+
+## 20230303-v1.0.0 (0)
+### Changes
+* Initial release version
+### 変更点
+* 初回リリース版
+
diff --git a/Document/DungeonGenerator.doxyfile b/Document/DungeonGenerator.doxyfile
index 9184afe..fa662d6 100644
--- a/Document/DungeonGenerator.doxyfile
+++ b/Document/DungeonGenerator.doxyfile
@@ -1,4 +1,4 @@
-# Doxyfile 1.9.3
+# Doxyfile 1.9.6
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -12,6 +12,16 @@
# For lists, items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (\" \").
+#
+# Note:
+#
+# Use doxygen to compare the used configuration file with the template
+# configuration file:
+# doxygen -x [configFile]
+# Use doxygen to compare the used configuration file with the template
+# configuration file without replacing the environment variables or CMake type
+# replacement variables:
+# doxygen -x_noenv [configFile]
#---------------------------------------------------------------------------
# Project related configuration options
@@ -32,19 +42,19 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
-PROJECT_NAME = DungeonGenerator
+PROJECT_NAME = "Dungeon Generator"
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 0.01
+PROJECT_NUMBER = 1.4.2
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.
-PROJECT_BRIEF =
+PROJECT_BRIEF = "Procedural 3D dungeon generator plugin for Unreal Engine 4 & 5. Easy generation of levels, mini-maps and missions."
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
@@ -60,16 +70,28 @@ PROJECT_LOGO =
OUTPUT_DIRECTORY = ./doxygen
-# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
+# sub-directories (in 2 levels) under the output directory of each output format
+# and will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
+# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
+# control the number of sub-directories.
# The default value is: NO.
CREATE_SUBDIRS = NO
+# Controls the number of sub-directories that will be created when
+# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
+# level increment doubles the number of directories, resulting in 4096
+# directories at level 8 which is the default and also the maximum value. The
+# sub-directories are organized in 2 levels, the first level always has a fixed
+# number of 16 directories.
+# Minimum value: 0, maximum value: 8, default value: 8.
+# This tag requires that the tag CREATE_SUBDIRS is set to YES.
+
+CREATE_SUBDIRS_LEVEL = 8
+
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
@@ -81,14 +103,14 @@ ALLOW_UNICODE_NAMES = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
+# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
+# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
+# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
+# English messages), Korean, Korean-en (Korean with English messages), Latvian,
+# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
+# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
+# Swedish, Turkish, Ukrainian and Vietnamese.
# The default value is: English.
OUTPUT_LANGUAGE = English
@@ -357,7 +379,7 @@ AUTOLINK_SUPPORT = YES
# diagrams that involve STL classes more complete and accurate.
# The default value is: NO.
-BUILTIN_STL_SUPPORT = NO
+BUILTIN_STL_SUPPORT = YES
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
@@ -452,7 +474,7 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
-# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
+# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
# during processing. When set to 0 doxygen will based this on the number of
# cores available in the system. You can set it explicitly to a value larger
# than 0 to get more control over the balance between CPU load and processing
@@ -546,7 +568,8 @@ HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option
-# has no effect if EXTRACT_ALL is enabled.
+# will also hide undocumented C++ concepts if enabled. This option has no effect
+# if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
@@ -577,14 +600,15 @@ INTERNAL_DOCS = NO
# filesystem is case sensitive (i.e. it supports files in the same directory
# whose names only differ in casing), the option must be set to YES to properly
# deal with such files in case they appear in the input. For filesystems that
-# are not case sensitive the option should be be set to NO to properly deal with
+# are not case sensitive the option should be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES.
-# The default value is: system dependent.
+# Possible values are: SYSTEM, NO and YES.
+# The default value is: SYSTEM.
CASE_SENSE_NAMES = NO
@@ -658,14 +682,14 @@ SORT_BRIEF_DOCS = NO
# detailed member documentation.
# The default value is: NO.
-SORT_MEMBERS_CTORS_1ST = NO
+SORT_MEMBERS_CTORS_1ST = YES
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
# of group names into alphabetical order. If set to NO the group names will
# appear in their defined order.
# The default value is: NO.
-SORT_GROUP_NAMES = NO
+SORT_GROUP_NAMES = YES
# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
# fully-qualified names, including namespaces. If set to NO, the class list will
@@ -836,6 +860,14 @@ WARN_IF_INCOMPLETE_DOC = YES
WARN_NO_PARAMDOC = NO
+# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
+# undocumented enumeration values. If set to NO, doxygen will accept
+# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: NO.
+
+WARN_IF_UNDOC_ENUM_VAL = NO
+
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
@@ -851,10 +883,21 @@ WARN_AS_ERROR = NO
# and the warning text. Optionally the format may contain $version, which will
# be replaced by the version of the file (if it could be obtained via
# FILE_VERSION_FILTER)
+# See also: WARN_LINE_FORMAT
# The default value is: $file:$line: $text.
WARN_FORMAT = "$file:$line: $text"
+# In the $text part of the WARN_FORMAT command it is possible that a reference
+# to a more specific place is given. To make it easier to jump to this place
+# (outside of doxygen) the user can define a custom "cut" / "paste" string.
+# Example:
+# WARN_LINE_FORMAT = "'vi $file +$line'"
+# See also: WARN_FORMAT
+# The default value is: at line $line of file $file.
+
+WARN_LINE_FORMAT = "at line $line of file $file"
+
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
# messages should be written. If left blank the output is written to standard
# error (stderr). In case the file specified cannot be opened for writing the
@@ -881,10 +924,21 @@ INPUT = ../Source
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# See also: INPUT_FILE_ENCODING
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
+# character encoding on a per file pattern basis. Doxygen will compare the file
+# name with each pattern and apply the encoding instead of the default
+# INPUT_ENCODING) if there is a match. The character encodings are a list of the
+# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
+# "INPUT_ENCODING" for further information on supported encodings.
+
+INPUT_FILE_ENCODING =
+
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories.
@@ -1033,6 +1087,11 @@ IMAGE_PATH =
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
#
+# Note that doxygen will use the data processed and written to standard output
+# for further processing, therefore nothing else, like debug statements or used
+# commands (so in case of a Windows batch file always use @echo OFF), should be
+# written to standard output.
+#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
@@ -1074,6 +1133,15 @@ FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
+# The Fortran standard specifies that for fixed formatted Fortran code all
+# characters from position 72 are to be considered as comment. A common
+# extension is to allow longer lines before the automatic comment starts. The
+# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
+# be processed before the automatic comment starts.
+# Minimum value: 7, maximum value: 10000, default value: 72.
+
+FORTRAN_COMMENT_AFTER = 72
+
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
@@ -1211,10 +1279,11 @@ CLANG_DATABASE_PATH =
ALPHABETICAL_INDEX = YES
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
+# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
+# that should be ignored while generating the index headers. The IGNORE_PREFIX
+# tag works for classes, function and member names. The entity will be placed in
+# the alphabetical list under the first letter of the entity name that remains
+# after removing the prefix.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
@@ -1293,7 +1362,12 @@ HTML_STYLESHEET =
# Doxygen will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
-# list). For an example see the documentation.
+# list).
+# Note: Since the styling of scrollbars can currently not be overruled in
+# Webkit/Chromium, the styling will be left out of the default doxygen.css if
+# one or more extra stylesheets have been specified. So if scrollbar
+# customization is desired it has to be added explicitly. For an example see the
+# documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
@@ -1308,6 +1382,19 @@ HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
+# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
+# should be rendered with a dark or light theme.
+# Possible values are: LIGHT always generate light mode output, DARK always
+# generate dark mode output, AUTO_LIGHT automatically set the mode according to
+# the user preference, use light mode if no preference is set (the default),
+# AUTO_DARK automatically set the mode according to the user preference, use
+# dark mode if no preference is set and TOGGLE allow to user to switch between
+# light and dark mode via a button.
+# The default value is: AUTO_LIGHT.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE = AUTO_LIGHT
+
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a color-wheel, see
@@ -1606,7 +1693,7 @@ DISABLE_INDEX = NO
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
-GENERATE_TREEVIEW = NO
+GENERATE_TREEVIEW = YES
# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
@@ -1618,7 +1705,7 @@ GENERATE_TREEVIEW = NO
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
-FULL_SIDEBAR = NO
+FULL_SIDEBAR = YES
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.
@@ -1671,17 +1758,6 @@ HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10
-# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT = YES
-
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details.
@@ -2276,7 +2352,8 @@ SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by the
-# preprocessor.
+# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
+# RECURSIVE has no effect here.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH =
@@ -2400,26 +2477,38 @@ HAVE_DOT = NO
DOT_NUM_THREADS = 0
-# When you want a differently looking font in the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
+# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
+# subgraphs. When you want a differently looking font in the dot files that
+# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
+# For details please see Node,
+# Edge and Graph Attributes specification You need to make sure dot is able
+# to find the font, which can be done by putting it in a standard location or by
+# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font. Default graphviz fontsize is 14.
+# The default value is: fontname=Helvetica,fontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES.
-DOT_FONTNAME = Helvetica
+DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
+# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
+# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. Complete documentation about
+# arrows shapes.
+# The default value is: labelfontname=Helvetica,labelfontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES.
-DOT_FONTSIZE = 10
+DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
+# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
+# around nodes set 'shape=plain' or 'shape=plaintext' Shapes specification
+# The default value is: shape=box,height=0.2,width=0.4.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
+
+# You can set the path where dot can find font specified with fontname in
+# DOT_COMMON_ATTR and others dot attributes.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTPATH =
@@ -2445,7 +2534,8 @@ CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
+# groups, showing the direct groups dependencies. See also the chapter Grouping
+# in the manual.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2661,18 +2751,6 @@ DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT = NO
-
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
diff --git a/DungeonGenerator.uplugin b/DungeonGenerator.uplugin
index ab7f8f5..bc2257c 100644
--- a/DungeonGenerator.uplugin
+++ b/DungeonGenerator.uplugin
@@ -1,17 +1,17 @@
{
"FileVersion": 3,
- "Version": 7,
- "VersionName": "1.4.2",
- "FriendlyName": "DungeonGenerator",
+ "Version": 14,
+ "VersionName": "1.5.0",
+ "FriendlyName": "Procedural 3D Dungeon Generator",
"Description": "Procedural 3D dungeon generator plugin. Easy generation of levels, mini-maps and missions.",
"Category": "Procedural",
"CreatedBy": "Narcis Software",
- "CreatedByURL": "https://happy-game-dev.undo.jp/",
- "DocsURL": "https://github.com/shun126/DungeonGenerator/wiki/",
+ "CreatedByURL": "https://github.com/shun126/UE5-DungeonGeneratorDemo",
+ "DocsURL": "https://github.com/shun126/UE5-DungeonGeneratorDemo/wiki",
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/36a8b87d859f44439cfe1515975d7197",
- "SupportURL": "https://github.com/shun126/DungeonGenerator/discussions/",
+ "SupportURL": "https://github.com/shun126/UE5-DungeonGeneratorDemo/discussions/",
"CanContainContent": false,
- "IsBetaVersion": false,
+ "IsBetaVersion": true,
"IsExperimentalVersion": false,
"Installed": false,
"Modules": [
@@ -19,9 +19,6 @@
"Name": "DungeonGenerator",
"Type": "Runtime",
"LoadingPhase": "Default",
- "WhitelistPlatforms": [
- "Win64"
- ],
"PlatformAllowList": [
"Win64"
]
@@ -30,12 +27,9 @@
"Name": "DungeonGeneratorEditor",
"Type": "UncookedOnly",
"LoadingPhase": "Default",
- "WhitelistPlatforms": [
- "Win64"
- ],
"PlatformAllowList": [
"Win64"
]
}
]
-}
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 709426f..067a931 100644
--- a/README.md
+++ b/README.md
@@ -46,13 +46,15 @@ The dungeon generator was based on Vazgriz's algorithm. You can read more about
This is an easy to use. Simply drop the DungeonGenerateActor into your level, set the grid scale and number of rooms and start generating out your structures. Please read the [Wiki](https://github.com/shun126/DungeonGenerator/wiki) for more information.
# 🔧 Requirements
-* [Unreal Engine 5.1.1 or Unreal Engine 4.27.2](https://www.unrealengine.com/)
+* [Unreal Engine 5.3.1 or Unreal Engine 4.27.2](https://www.unrealengine.com/)
* [Visual Studio 2022](https://visualstudio.microsoft.com/)
# 📜 License
-* GPL-3.0
+you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
-[UnrealEngine marketplace](https://www.unrealengine.com/marketplace/slug/36a8b87d859f44439cfe1515975d7197) is releasing it under Epic license. If you need a license other than the GPL, please consider it. Proceeds will be used to fund the development of our game.
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied arranty of MERCHANTABILITY or FITNESS FOR A ARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+Or, [UnrealEngine marketplace](https://www.unrealengine.com/marketplace/slug/36a8b87d859f44439cfe1515975d7197) is releasing it under Epic license. If you need a license other than the GPL, please consider it. Proceeds will be used to fund the development of our game.
## This is the screenshot of our game
diff --git a/Samples/.gitignore b/Samples/.gitignore
deleted file mode 100644
index fd399d3..0000000
--- a/Samples/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-!*.obj
diff --git a/Samples/Base.mtl b/Samples/Base.mtl
deleted file mode 100644
index ff7a5f6..0000000
--- a/Samples/Base.mtl
+++ /dev/null
@@ -1,4 +0,0 @@
-# Exported from 3D Builder
-
-newmtl Gray_0
-Kd 0.5 0.5 0.5
diff --git a/Samples/SM_BaseFloor.obj b/Samples/SM_BaseFloor.obj
deleted file mode 100644
index e1d8706..0000000
--- a/Samples/SM_BaseFloor.obj
+++ /dev/null
@@ -1,30 +0,0 @@
-# Exported from 3D Builder
-mtllib Base.mtl
-
-o Object.1
-v -2.000000 0.25000000 -2.000000
-v -2.000000 0.25000000 2.000000
-v 2.000000 0.25000000 -2.000000
-v 2.000000 0.25000000 2.000000
-v -2.000000 0.000000 -2.000000
-v -2.000000 0.000000 2.000000
-v 2.000000 0.000000 -2.000000
-v 2.000000 0.000000 2.000000
-
-usemtl Green_0
-# Top
-f 1 2 3
-f 3 2 4
-# Front
-f 2 6 4
-f 4 6 8
-# Right
-f 4 8 3
-f 3 8 7
-# Left
-f 1 5 2
-f 2 5 6
-# Back
-f 1 3 5
-f 5 3 7
-
diff --git a/Samples/SM_BasePillar.obj b/Samples/SM_BasePillar.obj
deleted file mode 100644
index 767104c..0000000
--- a/Samples/SM_BasePillar.obj
+++ /dev/null
@@ -1,26 +0,0 @@
-# Exported from 3D Builder
-mtllib Base.mtl
-
-o Object.1
-v -0.25 4.000000 -0.25
-v -0.25 4.000000 0.25
-v 0.25 4.000000 -0.25
-v 0.25 4.000000 0.25
-v -0.25 0.000000 -0.25
-v -0.25 0.000000 0.25
-v 0.25 0.000000 -0.25
-v 0.25 0.000000 0.25
-
-usemtl Green_0
-f 1 2 3
-f 3 2 4
-f 2 6 4
-f 4 6 8
-f 4 8 3
-f 3 8 7
-f 2 5 6
-f 2 1 5
-f 1 3 5
-f 5 3 7
-f 5 7 8
-f 5 8 6
\ No newline at end of file
diff --git a/Samples/SM_BaseRoof.obj b/Samples/SM_BaseRoof.obj
deleted file mode 100644
index 92468fb..0000000
--- a/Samples/SM_BaseRoof.obj
+++ /dev/null
@@ -1,24 +0,0 @@
-# Exported from 3D Builder
-mtllib Base.mtl
-
-o Object.1
-v -2.000000 4.000000 -2.000000
-v -2.000000 4.000000 2.000000
-v 2.000000 4.000000 -2.000000
-v 2.000000 4.000000 2.000000
-v -2.000000 3.900000 -2.000000
-v -2.000000 3.900000 2.000000
-v 2.000000 3.900000 -2.000000
-v 2.000000 3.900000 2.000000
-
-usemtl Green_0
-f 2 6 4
-f 4 6 8
-f 4 8 3
-f 3 8 7
-f 2 5 6
-f 2 1 5
-f 1 3 5
-f 5 3 7
-f 5 7 8
-f 5 8 6
diff --git a/Samples/SM_BaseSlope.obj b/Samples/SM_BaseSlope.obj
deleted file mode 100644
index 3f03b62..0000000
--- a/Samples/SM_BaseSlope.obj
+++ /dev/null
@@ -1,18 +0,0 @@
-# Exported from 3D Builder
-mtllib Base.mtl
-
-o Object.1
-v -2.000000 4.000000 -6.000000
-v 2.000000 4.000000 -6.000000
-v -2.000000 0.000000 -6.000000
-v -2.000000 0.000000 2.000000
-v 2.000000 0.000000 -6.000000
-v 2.000000 0.000000 2.000000
-
-usemtl Green_0
-f 1 4 6
-f 1 6 2
-f 2 6 5
-f 1 3 4
-f 1 2 3
-f 2 5 3
diff --git a/Samples/SM_BaseWall.obj b/Samples/SM_BaseWall.obj
deleted file mode 100644
index e7599d6..0000000
--- a/Samples/SM_BaseWall.obj
+++ /dev/null
@@ -1,26 +0,0 @@
-# Exported from 3D Builder
-mtllib Base.mtl
-
-o Object.1
-v -2.000000 4.000000 -0.15000
-v -2.000000 4.000000 0.15000
-v 2.000000 4.000000 -0.15000
-v 2.000000 4.000000 0.15000
-v -2.000000 0.000000 -0.15000
-v -2.000000 0.000000 0.15000
-v 2.000000 0.000000 -0.15000
-v 2.000000 0.000000 0.15000
-
-usemtl Green_0
-f 1 2 3
-f 3 2 4
-f 2 6 4
-f 4 6 8
-f 4 8 3
-f 3 8 7
-f 2 5 6
-f 2 1 5
-f 1 3 5
-f 5 3 7
-f 5 7 8
-f 5 8 6
\ No newline at end of file
diff --git a/Source/DungeonGenerator/Private/BuildInfomation.h b/Source/DungeonGenerator/Private/BuildInfomation.h
new file mode 100644
index 0000000..1eef392
--- /dev/null
+++ b/Source/DungeonGenerator/Private/BuildInfomation.h
@@ -0,0 +1,20 @@
+/*
+This is automatically generated file.
+DO NOT EDIT THIS FILE.
+\author Shun Moriya
+\copyright 2023- Shun Moriya
+All Rights Reserved.
+*/
+#pragma once
+#define JENKINS_BUILD_NUMBER "UNDEFINED NUMBER"
+#define JENKINS_BUILD_ID "LOCAL BUILD"
+#define JENKINS_NODE_NAME "UNDEFINED NODE"
+#define JENKINS_JOB_NAME "UNDEFINED JOB NAME"
+#define JENKINS_BUILD_TAG "UNDEFINED BUILD TAG"
+#define JENKINS_JOB_TAG "UNDEFINED JOB TAG"
+#define JENKINS_GIT_BRANCH "UNDEFINED BRANCH"
+#define JENKINS_GIT_COMMIT "UNDEFINED COMMIT"
+#define JENKINS_UUID "3da61b40-1fba-7757-b07f-110de2a901e3"
+#define JENKINS_LICENSE "GPL v3"
+#define JENKINS_FOR_DEVELOP 1
+#define JENKINS_FOR_RELEASE 0
diff --git a/Source/DungeonGenerator/Private/Core/Aisle.h b/Source/DungeonGenerator/Private/Core/Aisle.h
index 1bc7ce9..cb04ef7 100644
--- a/Source/DungeonGenerator/Private/Core/Aisle.h
+++ b/Source/DungeonGenerator/Private/Core/Aisle.h
@@ -9,6 +9,7 @@ All Rights Reserved.
#pragma once
#include "Identifier.h"
#include
+#include
namespace dungeon
{
diff --git a/Source/DungeonGenerator/Private/Core/Debug/Debug.cpp b/Source/DungeonGenerator/Private/Core/Debug/Debug.cpp
index cc4f530..911532c 100644
--- a/Source/DungeonGenerator/Private/Core/Debug/Debug.cpp
+++ b/Source/DungeonGenerator/Private/Core/Debug/Debug.cpp
@@ -1,5 +1,8 @@
/**
-デバッグに関するソースファイル
+Debug function source files
+
+To prevent conflicts with other Windows macros,
+do not include this file from the header.
\author Shun Moriya
\copyright 2023- Shun Moriya
@@ -9,7 +12,7 @@ All Rights Reserved.
#include "Debug.h"
#include
-// ログマクロ
+// log macro
#if UE_BUILD_DEBUG + UE_BUILD_DEVELOPMENT + UE_BUILD_TEST + UE_BUILD_SHIPPING > 0
DEFINE_LOG_CATEGORY(DungeonGeneratorLogger);
#else
@@ -22,8 +25,9 @@ namespace dungeon
#if UE_BUILD_DEBUG + UE_BUILD_DEVELOPMENT + UE_BUILD_TEST + UE_BUILD_SHIPPING == 0
#if defined(_WINDOWS) && (defined(_DEBUG) || defined(DEBUG))
/**
- VisualStudioの出力ウィンドウに出力します
- ソースファイルからのみincludeされる前提なのでstatic関数で良い
+ Output to VisualStudio output window
+ Assumed to be included only from source files,
+ so static functions are fine.
*/
extern void OutputDebugStringWithArgument(const char* pszFormat, ...)
{
@@ -41,9 +45,6 @@ namespace dungeon
#endif
#endif
- /**
- BMPファイル生成
- */
namespace bmp
{
Canvas::Canvas() noexcept
@@ -104,11 +105,11 @@ namespace dungeon
return 0;
}
- // ヘッダ部分を生成、書き込み
+ // Generate and write header section
fwrite(&mBmpHeader, sizeof(BMPFILEHEADER), 1, fp);
fwrite(&mBmpInfo, sizeof(BMPINFOHEADER), 1, fp);
- // データ部分を一行ずつ書き込み
+ // Write the data part line by line
for (int64_t i = static_cast(mHeight) - 1; i >= 0; --i)
{
fwrite(&mRgbImage.get()[i * mWidth], sizeof(RGBCOLOR), mWidth, fp);
diff --git a/Source/DungeonGenerator/Private/Core/Debug/Debug.h b/Source/DungeonGenerator/Private/Core/Debug/Debug.h
index cb09067..fc72696 100644
--- a/Source/DungeonGenerator/Private/Core/Debug/Debug.h
+++ b/Source/DungeonGenerator/Private/Core/Debug/Debug.h
@@ -1,7 +1,8 @@
/**
-デバッグに関するヘッダーファイル
+Debug function header files
-他のWindowsマクロと衝突を防ぐため、このファイルをヘッダーからincludeしないで下さい。
+To prevent conflicts with other Windows macros,
+do not include this file from the header.
\author Shun Moriya
\copyright 2023- Shun Moriya
@@ -27,7 +28,7 @@ All Rights Reserved.
#define UE_BUILD_SHIPPING 0
#endif
-// ログマクロ
+// log macro
#if UE_BUILD_DEBUG + UE_BUILD_DEVELOPMENT + UE_BUILD_TEST + UE_BUILD_SHIPPING > 0
#include
DECLARE_LOG_CATEGORY_EXTERN(DungeonGeneratorLogger, Log, All);
@@ -53,11 +54,17 @@ DECLARE_LOG_CATEGORY_EXTERN(DungeonGeneratorLogger, Log, All);
namespace dungeon
{
/**
- VisualStudioの出力ウィンドウに出力します
- ソースファイルからのみincludeされる前提なのでstatic関数で良い
+ @addtogroup Debug
+ @{
+ */
+
+ /*!
+ Output to VisualStudio output window
+ Assumed to be included only from source files, so static functions are fine.
*/
extern void OutputDebugStringWithArgument(const char* pszFormat, ...);
+ //! Microsoft Windows Bitmap Image Implementation
namespace bmp
{
#pragma pack(1)
@@ -94,55 +101,42 @@ namespace dungeon
#pragma pack()
/**
- キャンバスクラス
+ Microsoft Windows Bitmap canvas class
*/
class Canvas
{
public:
- // コントラクタ
Canvas() noexcept;
-
- /**
- コンストラクタ
- */
Canvas(const uint32_t width, const uint32_t height) noexcept;
-
- // デストラクタ
virtual ~Canvas() = default;
- /**
- 画像データの生成
- */
+ //! Generate image data
void Create(const uint32_t width, const uint32_t height) noexcept;
- /*
- 画像データの吐き出し
- */
+ //! Saves image data to a file
int Write(const std::string& filename) noexcept;
- /**
- 点の描画
- */
+ //! Draw point
void Put(int32_t x, int32_t y, const RGBCOLOR color) noexcept;
- /**
- 矩形の描画
- */
+ //! Draw rectangle
void Rectangle(int32_t left, int32_t top, int32_t right, int32_t bottom, const RGBCOLOR color) noexcept;
- /**
- フレームの描画
- */
+ //! Draw frame
void Frame(int32_t left, int32_t top, int32_t right, int32_t bottom, const RGBCOLOR color) noexcept;
private:
BMPFILEHEADER mBmpHeader;
BMPINFOHEADER mBmpInfo;
- uint32_t mWidth; // 横幅
- uint32_t mHeight; // 縦幅
+ uint32_t mWidth;
+ uint32_t mHeight;
- std::unique_ptr mRgbImage; // 画像データの本体
+ std::unique_ptr mRgbImage;
};
}
+
+ /**
+ @}
+ */
}
diff --git a/Source/DungeonGenerator/Private/Core/Debug/Stopwatch.h b/Source/DungeonGenerator/Private/Core/Debug/Stopwatch.h
index ddd677c..9b8ec6c 100644
--- a/Source/DungeonGenerator/Private/Core/Debug/Stopwatch.h
+++ b/Source/DungeonGenerator/Private/Core/Debug/Stopwatch.h
@@ -1,20 +1,41 @@
#pragma once
#include
-class Stopwatch
+namespace dungeon
{
-public:
- Stopwatch()
+ /**
+ @addtogroup Debug
+ @{
+ */
+
+ //! Measure time
+ class Stopwatch
+ {
+ public:
+ //! Start time measurement
+ Stopwatch();
+
+ //! Start time measurement
+ void Start();
+
+ //! Get elapsed time
+ double Lap();
+
+ private:
+ std::chrono::system_clock::time_point mStartTime;
+ };
+
+ inline Stopwatch::Stopwatch()
{
Start();
}
- void Start()
+ inline void Stopwatch::Start()
{
mStartTime = std::chrono::system_clock::now();
}
- double Lap()
+ inline double Stopwatch::Lap()
{
const auto now = std::chrono::system_clock::now();
const auto delta = now - mStartTime;
@@ -23,6 +44,7 @@ class Stopwatch
return static_cast(nano) / 1000000000.0;
}
-private:
- std::chrono::system_clock::time_point mStartTime;
-};
+ /**
+ @}
+ */
+}
diff --git a/Source/DungeonGenerator/Private/Core/DelaunayTriangulation3D.h b/Source/DungeonGenerator/Private/Core/DelaunayTriangulation3D.h
index 8505f03..d45d37b 100644
--- a/Source/DungeonGenerator/Private/Core/DelaunayTriangulation3D.h
+++ b/Source/DungeonGenerator/Private/Core/DelaunayTriangulation3D.h
@@ -17,6 +17,10 @@ All Rights Reserved.
namespace dungeon
{
+ /**
+ @addtogroup PathSelection
+ @{
+ */
/**
三次元ドロネー三角形分割クラス
@@ -64,6 +68,9 @@ namespace dungeon
private:
std::vector mTriangles;
};
+ /**
+ @}
+ */
}
#include "DelaunayTriangulation3D.inl"
diff --git a/Source/DungeonGenerator/Private/Core/Direction.h b/Source/DungeonGenerator/Private/Core/Direction.h
index 6511a34..bf1d9b9 100644
--- a/Source/DungeonGenerator/Private/Core/Direction.h
+++ b/Source/DungeonGenerator/Private/Core/Direction.h
@@ -7,11 +7,17 @@ All Rights Reserved.
*/
#pragma once
-#include "Core/Math/Random.h"
#include
+#include
namespace dungeon
{
+ class Random;
+
+ /**
+ @addtogroup PathGeneration
+ @{
+ */
/**
方向クラス
*/
@@ -128,11 +134,14 @@ namespace dungeon
ランダムな方向を取得します
\return ランダムな方向
*/
- static Direction CreateFromRandom(Random& random) noexcept;
+ static Direction CreateFromRandom(const std::shared_ptr& random) noexcept;
private:
Index mIndex;
};
+ /**
+ @}
+ */
}
#include "Direction.inl"
diff --git a/Source/DungeonGenerator/Private/Core/Direction.inl b/Source/DungeonGenerator/Private/Core/Direction.inl
index 20f2dc5..1bc870d 100644
--- a/Source/DungeonGenerator/Private/Core/Direction.inl
+++ b/Source/DungeonGenerator/Private/Core/Direction.inl
@@ -7,6 +7,7 @@ All Rights Reserved.
*/
#pragma once
+#include "Core/Math/Random.h"
namespace dungeon
{
@@ -82,8 +83,8 @@ namespace dungeon
return GetVector(mIndex);
}
- inline Direction Direction::CreateFromRandom(Random& random) noexcept
+ inline Direction Direction::CreateFromRandom(const std::shared_ptr& random) noexcept
{
- return Direction(static_cast(random.Get() % 4));
+ return Direction(static_cast(random->Get(4)));
}
}
diff --git a/Source/DungeonGenerator/Private/Core/DrawLots.h b/Source/DungeonGenerator/Private/Core/DrawLots.h
index b96f8f5..522e693 100644
--- a/Source/DungeonGenerator/Private/Core/DrawLots.h
+++ b/Source/DungeonGenerator/Private/Core/DrawLots.h
@@ -6,7 +6,8 @@
All Rights Reserved.
*/
-#include
+#include "Math/Random.h"
+#include
#include
namespace dungeon
@@ -15,9 +16,8 @@ namespace dungeon
重み付き抽選
*/
template
- InputIterator DrawLots(InputIterator first, InputIterator last, Predicate pred) noexcept
+ InputIterator DrawLots(const std::shared_ptr& random, InputIterator first, InputIterator last, Predicate pred) noexcept
{
- std::random_device random;
std::size_t totalWeight = 0;
struct Entry final
@@ -42,15 +42,12 @@ namespace dungeon
}
// TODO: specify random numbers externally.
- const std::size_t rnd = random() % totalWeight;
-
- for (const auto& weight : weights)
- {
- // cppcheck-suppress [useStlAlgorithm]
- if (rnd < weight.mWeight)
- return weight.mBody;
- }
-
- return last;
+ const std::size_t rnd = random->Get(totalWeight);
+ const auto i = std::find_if(weights.begin(), weights.end(), [rnd](const Entry& weight)
+ {
+ return rnd < weight.mWeight;
+ }
+ );
+ return i != weights.end() ? i->mBody : last;
}
}
diff --git a/Source/DungeonGenerator/Private/Core/GateFinder.h b/Source/DungeonGenerator/Private/Core/GateFinder.h
index 99f56c6..f85aa3b 100644
--- a/Source/DungeonGenerator/Private/Core/GateFinder.h
+++ b/Source/DungeonGenerator/Private/Core/GateFinder.h
@@ -13,6 +13,10 @@ All Rights Reserved.
namespace dungeon
{
+ /**
+ @addtogroup PathGeneration
+ @{
+ */
class GateFinder
{
public:
@@ -36,4 +40,7 @@ namespace dungeon
std::vector> mOpenGates;
std::vector> mCloseGates;
};
+ /**
+ @}
+ */
}
diff --git a/Source/DungeonGenerator/Private/Core/GenerateParameter.h b/Source/DungeonGenerator/Private/Core/GenerateParameter.h
index 00c6ab2..533d1c8 100644
--- a/Source/DungeonGenerator/Private/Core/GenerateParameter.h
+++ b/Source/DungeonGenerator/Private/Core/GenerateParameter.h
@@ -7,10 +7,12 @@ All Rights Reserved.
*/
#pragma once
-#include "Core/Math/Random.h"
+#include
namespace dungeon
{
+ class Random;
+
/**
デフォルトダンジョン生成パラメータクラス
*/
@@ -19,7 +21,7 @@ namespace dungeon
/**
コンストラクタ
*/
- GenerateParameter() = default;
+ GenerateParameter();
/**
デストラクタ
@@ -27,61 +29,66 @@ namespace dungeon
~GenerateParameter() = default;
/**
- ダンジョンの階層
+ ダンジョンの階層の候補
+ 部屋の初期生成数であり、最終的に生成される階層の数ではありません。
*/
- uint8_t GetNumberOfCandidateFloors() const noexcept { return mNumberOfCandidateFloors; }
+ uint8_t GetNumberOfCandidateFloors() const noexcept;
/**
生成する部屋の数の候補
部屋の初期生成数であり、最終的に生成される部屋の数ではありません。
*/
- uint8_t GetNumberOfCandidateRooms() const noexcept { return mNumberOfCandidateRooms; }
+ uint8_t GetNumberOfCandidateRooms() const noexcept;
/**
部屋の最小の幅
*/
- uint32_t GetMinRoomWidth() const noexcept { return mMinRoomWidth; }
+ uint32_t GetMinRoomWidth() const noexcept;
/**
部屋の最大の幅
*/
- uint32_t GetMaxRoomWidth() const noexcept { return mMaxRoomWidth; }
+ uint32_t GetMaxRoomWidth() const noexcept;
/**
部屋の最小の奥行き
*/
- uint32_t GetMinRoomDepth() const noexcept { return mMinRoomDepth; }
+ uint32_t GetMinRoomDepth() const noexcept;
/**
部屋の最大の奥行き
*/
- uint32_t GetMaxRoomDepth() const noexcept { return mMaxRoomDepth; }
+ uint32_t GetMaxRoomDepth() const noexcept;
/**
部屋の最小の高さ
*/
- uint32_t GetMinRoomHeight() const noexcept { return mMinRoomHeight; }
+ uint32_t GetMinRoomHeight() const noexcept;
/**
部屋の最大の高さ
*/
- uint32_t GetMaxRoomHeight() const noexcept { return mMaxRoomHeight; }
+ uint32_t GetMaxRoomHeight() const noexcept;
/**
部屋と部屋の水平方向の余白
*/
- uint32_t GetHorizontalRoomMargin() const noexcept { return mHorizontalRoomMargin; };
+ uint32_t GetHorizontalRoomMargin() const noexcept;
/**
部屋と部屋の垂直方向の余白
*/
- uint32_t GetVerticalRoomMargin() const noexcept { return mVerticalRoomMargin; };
+ uint32_t GetVerticalRoomMargin() const noexcept;
/**
乱数発生
*/
- Random& GetRandom() const noexcept { return const_cast(this)->mRandom; }
+ std::shared_ptr GetRandom() noexcept;
+ /**
+ 乱数発生
+ */
+ std::shared_ptr GetRandom() const noexcept;
@@ -89,91 +96,101 @@ namespace dungeon
/**
ダンジョンの幅
*/
- uint32_t GetWidth() const noexcept { return mWidth; }
+ uint32_t GetWidth() const noexcept;
/**
ダンジョンの奥行き
*/
- uint32_t GetDepth() const noexcept { return mDepth; }
+ uint32_t GetDepth() const noexcept;
/**
ダンジョンの高さ
*/
- uint32_t GetHeight() const noexcept { return mHeight; }
+ uint32_t GetHeight() const noexcept;
+
+
+ bool IsGenerateStartRoomReserved() const noexcept;
+ bool IsGenerateGoalRoomReserved() const noexcept;
+
+
+
/**
ダンジョンの幅
*/
- uint32_t mWidth = 0;
+ uint32_t mWidth;
/**
ダンジョンの奥行き
*/
- uint32_t mDepth = 0;
+ uint32_t mDepth;
/**
ダンジョンの高さ
*/
- uint32_t mHeight = 3;
-
+ uint32_t mHeight;
/**
- 生成する階層の候補
+ 生成する階層の数の候補
+ 最終的に生成される階層の数ではありません。
*/
- uint8_t mNumberOfCandidateFloors = 3;
+ uint8_t mNumberOfCandidateFloors;
/**
生成する部屋の数の候補
部屋の初期生成数であり、最終的に生成される部屋の数ではありません。
*/
- uint8_t mNumberOfCandidateRooms = 5;
+ uint8_t mNumberOfCandidateRooms;
/**
部屋の最小の幅
*/
- uint32_t mMinRoomWidth = 2;
+ uint32_t mMinRoomWidth;
/**
部屋の最大の幅
*/
- uint32_t mMaxRoomWidth = 3;
+ uint32_t mMaxRoomWidth;
/**
部屋の最小の奥行き
*/
- uint32_t mMinRoomDepth = 2;
+ uint32_t mMinRoomDepth;
/**
部屋の最大の奥行き
*/
- uint32_t mMaxRoomDepth = 3;
+ uint32_t mMaxRoomDepth;
/**
部屋の最小の高さ
*/
- uint32_t mMinRoomHeight = 1;
+ uint32_t mMinRoomHeight;
/**
部屋の最大の高さ
*/
- uint32_t mMaxRoomHeight = 2;
+ uint32_t mMaxRoomHeight;
/**
部屋と部屋の水平方向の余白
*/
- uint32_t mHorizontalRoomMargin = 0;
+ uint32_t mHorizontalRoomMargin;
/**
部屋と部屋の垂直方向の余白
*/
- uint32_t mVerticalRoomMargin = 0;
+ uint32_t mVerticalRoomMargin;
/**
乱数生成器
*/
- Random mRandom;
+ std::shared_ptr mRandom;
+
+ FIntVector mStartRoomSize = { 0, 0, 0 };
+ FIntVector mGoalRoomSize = { 0, 0, 0 };
};
}
diff --git a/Source/DungeonGenerator/Private/Core/GenerateParameter.inl b/Source/DungeonGenerator/Private/Core/GenerateParameter.inl
index 98f8eb8..7b50a6f 100644
--- a/Source/DungeonGenerator/Private/Core/GenerateParameter.inl
+++ b/Source/DungeonGenerator/Private/Core/GenerateParameter.inl
@@ -7,7 +7,99 @@ All Rights Reserved.
*/
#pragma once
+#include "Core/Math/Random.h"
+#include
+#include
namespace dungeon
{
+ inline GenerateParameter::GenerateParameter()
+ : mRandom(std::make_shared())
+ {
+ }
+
+ inline uint8_t GenerateParameter::GetNumberOfCandidateFloors() const noexcept
+ {
+ return mNumberOfCandidateFloors;
+ }
+
+ inline uint8_t GenerateParameter::GetNumberOfCandidateRooms() const noexcept
+ {
+ return mNumberOfCandidateRooms;
+ }
+
+ inline uint32_t GenerateParameter::GetMinRoomWidth() const noexcept
+ {
+ return mMinRoomWidth;
+ }
+
+ inline uint32_t GenerateParameter::GetMaxRoomWidth() const noexcept
+ {
+ return mMaxRoomWidth;
+ }
+
+ inline uint32_t GenerateParameter::GetMinRoomDepth() const noexcept
+ {
+ return mMinRoomDepth;
+ }
+
+ inline uint32_t GenerateParameter::GetMaxRoomDepth() const noexcept
+ {
+ return mMaxRoomDepth;
+ }
+
+ inline uint32_t GenerateParameter::GetMinRoomHeight() const noexcept
+ {
+ return mMinRoomHeight;
+ }
+
+ inline uint32_t GenerateParameter::GetMaxRoomHeight() const noexcept
+ {
+ return mMaxRoomHeight;
+ }
+
+ inline uint32_t GenerateParameter::GetHorizontalRoomMargin() const noexcept
+ {
+ return mHorizontalRoomMargin;
+ };
+
+ inline uint32_t GenerateParameter::GetVerticalRoomMargin() const noexcept
+ {
+ return mVerticalRoomMargin;
+ };
+
+ inline std::shared_ptr GenerateParameter::GetRandom() noexcept
+ {
+ return mRandom;
+ }
+
+ inline std::shared_ptr GenerateParameter::GetRandom() const noexcept
+ {
+ return const_cast(this)->mRandom;
+ }
+
+ inline uint32_t GenerateParameter::GetWidth() const noexcept
+ {
+ return mWidth;
+ }
+
+ inline uint32_t GenerateParameter::GetDepth() const noexcept
+ {
+ return mDepth;
+ }
+
+ inline uint32_t GenerateParameter::GetHeight() const noexcept
+ {
+ return mHeight;
+ }
+
+ inline bool GenerateParameter::IsGenerateStartRoomReserved() const noexcept
+ {
+ return mStartRoomSize.IsZero() == false;
+ }
+
+ inline bool GenerateParameter::IsGenerateGoalRoomReserved() const noexcept
+ {
+ return mGoalRoomSize.IsZero() == false;
+ }
}
diff --git a/Source/DungeonGenerator/Private/Core/Generator.cpp b/Source/DungeonGenerator/Private/Core/Generator.cpp
index 4c897f5..1789689 100644
--- a/Source/DungeonGenerator/Private/Core/Generator.cpp
+++ b/Source/DungeonGenerator/Private/Core/Generator.cpp
@@ -15,6 +15,7 @@ All Rights Reserved.
#include "Debug/BuildInfomation.h"
#include "Debug/Debug.h"
#include "Debug/Stopwatch.h"
+#include "Helper/Crc.h"
#include "Math/Math.h"
#include "Math/PerlinNoise.h"
#include "Math/Plane.h"
@@ -22,7 +23,7 @@ All Rights Reserved.
#include "MissionGraph/MissionGraph.h"
-#if WITH_EDITOR && JENKINS_FOR_DEVELOP
+#if WITH_EDITOR & JENKINS_FOR_DEVELOP
#include
// 定義するとデバッグに便利なログを出力します
@@ -51,14 +52,6 @@ namespace dungeon
}
#endif
- Generator::Generator() noexcept
- {
- }
-
- Generator::~Generator() noexcept
- {
- }
-
void Generator::Reset()
{
mVoxel.reset();
@@ -73,6 +66,8 @@ namespace dungeon
void Generator::Generate(const GenerateParameter& parameter) noexcept
{
+ Identifier::ResetCounter();
+
mLastError = Error::Success;
mGenerateParameter = parameter;
@@ -133,56 +128,61 @@ namespace dungeon
// 部屋の生成
stopwatch.Start();
- if (!GenerateRooms(parameter))
+ const bool resultGenerateRooms = GenerateRooms(parameter);
+ DUNGEON_GENERATOR_LOG(TEXT("GenerateRooms: %lf seconds"), stopwatch.Lap());
+ if (!resultGenerateRooms)
return false;
- DUNGEON_GENERATOR_LOG(TEXT("GenerateRooms: %lf sec"), stopwatch.Lap());
// 部屋の分離
stopwatch.Start();
- if (!SeparateRooms(parameter))
+ const bool resultSeparateRooms = SeparateRooms(parameter);
+ DUNGEON_GENERATOR_LOG(TEXT("SeparateRooms: %lf seconds"), stopwatch.Lap());
+ if (!resultSeparateRooms)
return false;
- DUNGEON_GENERATOR_LOG(TEXT("SeparateRooms: %lf sec"), stopwatch.Lap());
// 全ての部屋が収まるように空間を拡張します
stopwatch.Start();
- if (!ExpandSpace(parameter))
+ const bool resultExpandSpace = ExpandSpace(parameter);
+ DUNGEON_GENERATOR_LOG(TEXT("ExpandSpace: %lf seconds"), stopwatch.Lap());
+ if (!resultExpandSpace)
return false;
- DUNGEON_GENERATOR_LOG(TEXT("ExpandSpace: %lf sec"), stopwatch.Lap());
- // 重複した部屋や範囲外の部屋を除去
+ // 通路の生成
stopwatch.Start();
- if (!RemoveInvalidRooms(parameter))
+ const bool resultExtractionAisles = ExtractionAisles(parameter);
+ DUNGEON_GENERATOR_LOG(TEXT("ExtractionAisles: %lf seconds"), stopwatch.Lap());
+ if (!resultExtractionAisles)
return false;
- DUNGEON_GENERATOR_LOG(TEXT("RemoveInvalidRooms: %lf sec"), stopwatch.Lap());
- // 通路の生成
- stopwatch.Start();
- if (!ExtractionAisles(parameter))
+ // 開始部屋と終了部屋のサブレベルを配置する隙間を調整
+ if (!AdjustedStartAndGoalSublevel(parameter))
return false;
- DUNGEON_GENERATOR_LOG(TEXT("ExtractionAisles: %lf sec"), stopwatch.Lap());
// ブランチIDの生成
stopwatch.Start();
- if (!Branch())
+ const bool resultBranch = Branch();
+ DUNGEON_GENERATOR_LOG(TEXT("Branch: %lf seconds"), stopwatch.Lap());
+ if (!resultBranch)
return false;
- DUNGEON_GENERATOR_LOG(TEXT("Branch: %lf sec"), stopwatch.Lap());
// 階層情報の生成
stopwatch.Start();
- if (!DetectFloorHeight())
+ const bool resultDetectFloorHeight = DetectFloorHeight();
+ DUNGEON_GENERATOR_LOG(TEXT("DetectFloorHeight: %lf seconds"), stopwatch.Lap());
+ if (!resultDetectFloorHeight)
return false;
- DUNGEON_GENERATOR_LOG(TEXT("DetectFloorHeight: %lf sec"), stopwatch.Lap());
// 部屋と通路に意味付けする
stopwatch.Start();
MissionGraph missionGraph(shared_from_this(), mGoalPoint);
- DUNGEON_GENERATOR_LOG(TEXT("MissionGraph: %lf sec"), stopwatch.Lap());
+ DUNGEON_GENERATOR_LOG(TEXT("MissionGraph: %lf seconds"), stopwatch.Lap());
// ボクセル情報を生成します
stopwatch.Start();
- if (!GenerateVoxel(parameter))
+ const bool resultGenerateVoxel = GenerateVoxel(parameter);
+ DUNGEON_GENERATOR_LOG(TEXT("GenerateVoxel: %lf seconds"), stopwatch.Lap());
+ if (!resultGenerateVoxel)
return false;
- DUNGEON_GENERATOR_LOG(TEXT("GenerateVoxel: %lf sec"), stopwatch.Lap());
return true;
}
@@ -204,13 +204,34 @@ namespace dungeon
maxRoomWidth += parameter.GetHorizontalRoomMargin();
range *= maxRoomWidth;
+ // Register Start Room
+ if (!parameter.mStartRoomSize.IsZero())
+ {
+ int32_t height = static_cast(parameter.GetNumberOfCandidateFloors()) - 1;
+ height -= parameter.mStartRoomSize.Z;
+ if (height < 0)
+ height = 0;
+ mStartRoom = mRooms.emplace_back(
+ std::make_shared(FIntVector(0, range, height), parameter.mStartRoomSize, true)
+ );
+ }
+
+ // Register Goal Room
+ if (!parameter.mGoalRoomSize.IsZero())
+ {
+ mGoalRoom = mRooms.emplace_back(
+ std::make_shared(FIntVector(0, -range, 0), parameter.mGoalRoomSize, true)
+ );
+ }
+
+ // Register Rooms
for (size_t i = 0; i < parameter.GetNumberOfCandidateRooms(); ++i)
{
- const float radian = parameter.GetRandom().Get() * (3.14159265359f * 2.f);
+ const float radian = parameter.GetRandom()->Get() * (3.14159265359f * 2.f);
const float width = std::sin(radian);
const float depth = std::cos(radian);
const float height = std::max(0.f, static_cast(parameter.GetNumberOfCandidateFloors()) - 1);
- const float distance = parameter.GetRandom().Get(range);
+ const float distance = parameter.GetRandom()->Get(range);
float noise = perlinNoise.Noise(width, depth);
noise = noise * 0.5f + 0.5f;
noise *= noiseBoostRatio;
@@ -231,7 +252,7 @@ namespace dungeon
location.Z = 0;
}
- auto room = std::make_shared(parameter, location);
+ std::shared_ptr room = std::make_shared(parameter, location);
#if defined(DEBUG_SHOW_DEVELOP_LOG)
DUNGEON_GENERATOR_LOG(TEXT("Room: X=%d,Y=%d,Z=%d W=%d,D=%d,H=%d center(%f, %f, %f)")
, room->GetX(), room->GetY(), room->GetZ()
@@ -242,11 +263,6 @@ namespace dungeon
mRooms.emplace_back(std::move(room));
}
-#if defined(DEBUG_SHOW_DEVELOP_LOG)
- // サブレベル配置テスト用の部屋
- //mRooms.emplace_back(std::make_shared(16, 15, 5, 3, 3, 1));
-#endif
-
GenerateRoomImageForDebug("generator_1.bmp");
#if defined(DEBUG_GENERATE_BITMAP_FILE)
@@ -347,7 +363,7 @@ namespace dungeon
// 中心が一致してしまったので適当な方向に押し出す
if (direction.SizeSquared() == 0.)
{
- const double ratio = parameter.GetRandom().Get();
+ const double ratio = parameter.GetRandom()->Get();
const double radian = ratio * (3.14159265359 * 2.);
direction.X = std::cos(radian);
direction.Y = std::sin(radian);
@@ -517,68 +533,6 @@ namespace dungeon
return true;
}
- /**
- 重複した部屋や範囲外の部屋を除去をします
- */
- bool Generator::RemoveInvalidRooms(const GenerateParameter& parameter) noexcept
- {
-#if defined(DEBUG_SHOW_DEVELOP_LOG)
- DUNGEON_GENERATOR_LOG(TEXT("Remove duplicate rooms and out-of-range rooms"));
-#endif
-
- auto result = std::remove_if(mRooms.begin(), mRooms.end(), [¶meter, this](const std::shared_ptr& room) -> bool
- {
- // 範囲外の部屋なら削除
- if (
- room->GetLeft() < 0 || static_cast(parameter.GetWidth()) <= room->GetRight() ||
- room->GetTop() < 0 || static_cast(parameter.GetDepth()) <= room->GetBottom() ||
- room->GetBackground() < 0 || static_cast(parameter.GetHeight()) <= room->GetForeground())
- {
-#if defined(DEBUG_SHOW_DEVELOP_LOG)
- DUNGEON_GENERATOR_LOG(TEXT("Room: X=%d,Y=%d W=%d,H=%d center(%f, %f) 範囲外")
- , room->GetX(), room->GetY(), room->GetWidth(), room->GetDepth()
- , room->GetCenter().X, room->GetCenter().Y
- );
-#endif
- return true;
- }
-
- // 他の部屋に含まれている?
- for (const auto& otherRoom : mRooms)
- {
- // 無効な部屋はスキップ
- if (otherRoom == nullptr)
- continue;
- // 自分自身はスキップ
- if (otherRoom == room)
- continue;
- // 内包?
- if (room->Intersect(*otherRoom, parameter.GetHorizontalRoomMargin(), parameter.GetVerticalRoomMargin()) == true)
- return true;
- }
-
- return false;
- }
- );
- mRooms.erase(result, mRooms.end());
-
-#if defined(DEBUG_GENERATE_BITMAP_FILE)
- bmp::Canvas canvas(Scale(parameter.GetWidth()), Scale(parameter.GetDepth()));
- for (const auto& room : mRooms)
- {
- canvas.Rectangle(Scale(room->GetLeft()), Scale(room->GetTop()), Scale(room->GetRight()), Scale(room->GetBottom()), baseDarkColor);
- }
- for (const auto& room : mRooms)
- {
- canvas.Frame(Scale(room->GetLeft()), Scale(room->GetTop()), Scale(room->GetRight()), Scale(room->GetBottom()), frameColor);
- }
- const auto filename = TCHAR_TO_ANSI(*(FPaths::ProjectSavedDir() + "/DungeonGenerator/generator_3.bmp"));
- canvas.Write(filename);
-#endif
-
- return true;
- }
-
bool Generator::DetectFloorHeight() noexcept
{
mFloorHeight.clear();
@@ -699,10 +653,14 @@ namespace dungeon
if (room->Contain(*mStartPoint))
{
room->SetParts(Room::Parts::Start);
+ if (mOnStartParts)
+ mOnStartParts(room);
}
else if (room->Contain(*mGoalPoint))
{
room->SetParts(Room::Parts::Goal);
+ if (mOnGoalParts)
+ mOnGoalParts(room);
}
else
{
@@ -721,13 +679,74 @@ namespace dungeon
}
}
- if (mQueryParts)
+ if (mOnQueryParts)
+ mOnQueryParts(room);
+ }
+
+ return mLastError == Error::Success;
+ }
+
+ bool Generator::AdjustedStartAndGoalSublevel(GenerateParameter& parameter) noexcept
+ {
+ Stopwatch stopwatch;
+
+ const bool isGenerateStartRoomReserved = (parameter.IsGenerateStartRoomReserved() && mStartPoint && mStartPoint->GetOwnerRoom());
+ const bool isGenerateGoalRoomReserved = (parameter.IsGenerateGoalRoomReserved() && mGoalPoint && mGoalPoint->GetOwnerRoom());
+ if (isGenerateStartRoomReserved || isGenerateGoalRoomReserved)
+ {
+ if (isGenerateStartRoomReserved)
{
- mQueryParts(room);
+ const std::shared_ptr& room = mStartPoint->GetOwnerRoom();
+ room->SetWidth(parameter.mStartRoomSize.X);
+ room->SetDepth(parameter.mStartRoomSize.Y);
+ room->SetHeight(parameter.mStartRoomSize.Z);
+ }
+ if (isGenerateGoalRoomReserved)
+ {
+ const std::shared_ptr& room = mGoalPoint->GetOwnerRoom();
+ room->SetWidth(parameter.mGoalRoomSize.X);
+ room->SetDepth(parameter.mGoalRoomSize.Y);
+ room->SetHeight(parameter.mGoalRoomSize.Z);
+ }
+
+ {
+ // 部屋の分離
+ stopwatch.Start();
+ const bool resultSeparateRooms2 = SeparateRooms(parameter);
+ DUNGEON_GENERATOR_LOG(TEXT("SeparateRooms: %lf seconds"), stopwatch.Lap());
+ if (!resultSeparateRooms2)
+ return false;
+
+ // 全ての部屋が収まるように空間を拡張します
+ stopwatch.Start();
+ const bool resultExpandSpace2 = ExpandSpace(parameter);
+ DUNGEON_GENERATOR_LOG(TEXT("ExpandSpace: %lf seconds"), stopwatch.Lap());
+ if (!resultExpandSpace2)
+ return false;
+ }
+
+ if (isGenerateStartRoomReserved)
+ {
+ std::const_pointer_cast(mStartPoint)->ResetByRoomGroundCenter();
+ }
+ if (isGenerateGoalRoomReserved)
+ {
+ std::const_pointer_cast(mGoalPoint)->ResetByRoomGroundCenter();
+ }
+
+ for (Aisle& aisle : mAisles)
+ {
+ for (uint_fast8_t i = 0; i < 2; ++i)
+ {
+ if (const std::shared_ptr& point = std::const_pointer_cast(aisle.GetPoint(i)))
+ {
+ std::const_pointer_cast(point)->ResetByRoomGroundCenter();
+ }
+ }
}
}
- return mLastError == Error::Success;
+ return true;
}
float Generator::GetDistanceCenterToContact(const float width, const float depth, const FVector& direction, const float margin) const noexcept
@@ -789,8 +808,16 @@ namespace dungeon
DUNGEON_GENERATOR_LOG(TEXT("%d minimum spanning tree edges detected"), minimumSpanningTree.Size());
#endif
- mStartPoint = minimumSpanningTree.GetStartPoint();
- mGoalPoint = minimumSpanningTree.GetGoalPoint();
+ if (mStartRoom)
+ mStartPoint = std::make_shared(mStartRoom);
+ else
+ mStartPoint = minimumSpanningTree.GetStartPoint();
+
+ if (mGoalRoom)
+ mGoalPoint = std::make_shared(mGoalRoom);
+ else
+ mGoalPoint = minimumSpanningTree.GetGoalPoint();
+
minimumSpanningTree.EachLeafPoint([this](const std::shared_ptr& point)
{
mLeafPoints.emplace_back(point);
@@ -804,7 +831,7 @@ namespace dungeon
{
mVoxel = std::make_shared(parameter);
- // 部屋を生成
+ // Generate room
for (const auto& room : mRooms)
{
{
@@ -822,44 +849,43 @@ namespace dungeon
}
}
- // 通路の距離が短い順に並べ替える
+ // Sort by shortest aisle distance
std::sort(mAisles.begin(), mAisles.end(), [](const Aisle& l, const Aisle& r)
{
return l.GetLength() < r.GetLength();
}
);
- // 通路を生成
+ // Generate pathways
for (const Aisle& aisle : mAisles)
{
- std::shared_ptr s = aisle.GetPoint(0);
- std::shared_ptr e = aisle.GetPoint(1);
+ std::shared_ptr startPoint = aisle.GetPoint(0);
+ std::shared_ptr goalPoint = aisle.GetPoint(1);
- check(s->GetOwnerRoom()->GetRect().Contains(ToIntPoint(*s)));
- check(e->GetOwnerRoom()->GetRect().Contains(ToIntPoint(*e)));
-
- // Use the back room as a starting point.
- if (s->GetOwnerRoom()->GetDepthFromStart() < e->GetOwnerRoom()->GetDepthFromStart())
+ // Use the back room as a starting point
+ if (startPoint->GetOwnerRoom()->GetDepthFromStart() < goalPoint->GetOwnerRoom()->GetDepthFromStart())
{
- const std::shared_ptr t = e;
- e = s;
- s = t;
+ const std::shared_ptr t = goalPoint;
+ goalPoint = startPoint;
+ startPoint = t;
}
- check(s->GetOwnerRoom()->GetRect().Contains(ToIntPoint(*s)));
- check(e->GetOwnerRoom()->GetRect().Contains(ToIntPoint(*e)));
+ // Check if the start and end points are included in the room
+ check(startPoint->GetOwnerRoom()->GetRect().Contains(ToIntPoint(*startPoint)));
+ check(goalPoint->GetOwnerRoom()->GetRect().Contains(ToIntPoint(*goalPoint)));
+
+ // Change to voxel coordinates
+ FIntVector start = ToIntVector(*startPoint);
+ FIntVector goal = ToIntVector(*goalPoint);
- const std::shared_ptr& startRoom = s->GetOwnerRoom();
- const std::shared_ptr& goalRoom = e->GetOwnerRoom();
- check(startRoom);
+ // Conditions for reaching the passage. The endpoint can be anywhere in the goal room.
+ const std::shared_ptr& goalRoom = goalPoint->GetOwnerRoom();
check(goalRoom);
+ const PathGoalCondition pathGoalCondition(goalRoom->GetRect());
- FIntVector start = ToIntVector(*s);
- FIntVector goal = ToIntVector(*e);
-
- // start周囲に侵入可能なグリッドを探す
+ // Find a voxel that can generate gates around the start
FIntVector result;
- if (mVoxel->SearchGateLocation(result, start, goal, PathGoalCondition(goalRoom->GetRect()), aisle.GetIdentifier()))
+ if (mVoxel->SearchGateLocation(result, start, goal, pathGoalCondition, aisle.GetIdentifier()))
{
start = result;
}
@@ -871,8 +897,9 @@ namespace dungeon
}
// Aisle generation by A*.
- if (mVoxel->Aisle(start, goal, PathGoalCondition(goalRoom->GetRect()), aisle.GetIdentifier()))
+ if (mVoxel->Aisle(start, goal, pathGoalCondition, aisle.GetIdentifier()))
{
+ // Put a lock on the gate of the back room if necessary.
Grid grid = mVoxel->Get(start.X, start.Y, start.Z);
check(grid.GetProps() == Grid::Props::None);
if (grid.GetProps() == Grid::Props::None)
@@ -971,27 +998,23 @@ namespace dungeon
std::shared_ptr Generator::Find(const Point& point) const noexcept
{
- for (const auto& room : mRooms)
- {
- // cppcheck-suppress [useStlAlgorithm]
- if (room->Contain(point))
- return room;
- }
- return nullptr;
+ const auto i = std::find_if(mRooms.begin(), mRooms.end(), [&point](const std::shared_ptr& room)
+ {
+ return room->Contain(point);
+ }
+ );
+ return i != mRooms.end() ? *i : nullptr;
}
std::vector> Generator::FindAll(const Point& point) const noexcept
{
std::vector> result;
result.reserve(mRooms.size());
- for (const auto& room : mRooms)
- {
- if (room->Contain(point))
+ std::copy_if(mRooms.begin(), mRooms.end(), result.begin(), [&point](const std::shared_ptr& room)
{
- // cppcheck-suppress [useStlAlgorithm]
- result.emplace_back(room);
+ return room->Contain(point);
}
- }
+ );
return result;
}
@@ -1233,4 +1256,9 @@ namespace dungeon
return false;
}
+
+ uint32_t Generator::CalculateCRC32() const noexcept
+ {
+ return mVoxel ? mVoxel->CalculateCRC32() : 0;
+ }
}
diff --git a/Source/DungeonGenerator/Private/Core/Generator.h b/Source/DungeonGenerator/Private/Core/Generator.h
index 182dfb8..3f2b77d 100644
--- a/Source/DungeonGenerator/Private/Core/Generator.h
+++ b/Source/DungeonGenerator/Private/Core/Generator.h
@@ -50,14 +50,14 @@ namespace dungeon
/**
コンストラクタ
*/
- Generator() noexcept;
+ Generator() = default;
Generator(const Generator&) = delete;
Generator& operator=(const Generator&) = delete;
/**
デストラクタ
*/
- virtual ~Generator() noexcept;
+ virtual ~Generator() = default;
/**
生成
@@ -89,24 +89,12 @@ namespace dungeon
/**
生成された部屋を更新します
*/
- void ForEach(std::function&)> func) noexcept
- {
- for (const auto& room : mRooms)
- {
- func(room);
- }
- }
+ void ForEach(std::function&)> func) noexcept;
/**
生成された部屋を参照します
*/
- void ForEach(std::function&)> func) const noexcept
- {
- for (const auto& room : mRooms)
- {
- func(room);
- }
- }
+ void ForEach(std::function&)> func) const noexcept;
// 深度による検索
std::vector> FindByDepth(const uint8_t depth) const noexcept;
@@ -133,48 +121,16 @@ namespace dungeon
public:
////////////////////////////////////////////////////////////////////////////////////////////
// Aisle
- void EachAisle(std::function func) const noexcept
- {
- for (const auto& aisle : mAisles)
- {
- func(aisle);
- }
- }
+ void EachAisle(std::function func) const noexcept;
// 部屋に接続している通路を検索
- void FindAisle(const std::shared_ptr& room, std::function func) noexcept
- {
- for (auto& aisle : mAisles)
- {
- const auto& room0 = aisle.GetPoint(0)->GetOwnerRoom();
- const auto& room1 = aisle.GetPoint(1)->GetOwnerRoom();
- if (room == room0 || room == room1)
- {
- if (func(aisle))
- break;
- }
- }
- }
-
- void FindAisle(const std::shared_ptr& room, std::function func) const noexcept
- {
- for (const auto& aisle : mAisles)
- {
- const auto& room0 = aisle.GetPoint(0)->GetOwnerRoom();
- const auto& room1 = aisle.GetPoint(1)->GetOwnerRoom();
- if (room == room0 || room == room1)
- {
- if (func(aisle))
- break;
- }
- }
- }
-
- void OnQueryParts(std::function&)> func) noexcept
- {
- mQueryParts = func;
- }
+ void FindAisle(const std::shared_ptr& room, std::function func) noexcept;
+ void FindAisle(const std::shared_ptr& room, std::function func) const noexcept;
+
+ void OnQueryParts(std::function&)> func) noexcept;
+ void OnStartParts(std::function&)> func) noexcept;
+ void OnGoalParts(std::function&)> func) noexcept;
////////////////////////////////////////////////////////////////////////////////////////////
// Point
@@ -198,50 +154,44 @@ namespace dungeon
開始地点にふさわしい点を取得します
\return 開始地点にふさわしい点
*/
- const std::shared_ptr& GetStartPoint() const noexcept
- {
- return mStartPoint;
- }
+ const std::shared_ptr& GetStartPoint() const noexcept;
/**
ゴール地点にふさわしい点を取得します
\return ゴール地点にふさわしい点
*/
- const std::shared_ptr& GetGoalPoint() const noexcept
- {
- return mGoalPoint;
- }
+ const std::shared_ptr& GetGoalPoint() const noexcept;
/**
行き止まりの点を更新します
\param[in] func 点を元に更新する関数
*/
- void EachLeafPoint(std::function& point)> func) const noexcept
- {
- for (auto& point : mLeafPoints)
- {
- func(point);
- }
- }
+ void EachLeafPoint(std::function& point)> func) const noexcept;
+ ////////////////////////////////////////////////////////////////////////////////////////////
void DumpRoomDiagram(const std::string& path) const noexcept;
void DumpRoomDiagram(std::ofstream& stream, std::unordered_set& generatedEdges, const std::shared_ptr& room) const noexcept;
void DumpAisle(const std::string& path) const noexcept;
+ ////////////////////////////////////////////////////////////////////////////////////////////
bool Branch() noexcept;
bool Branch(std::unordered_set& generatedEdges, const std::shared_ptr& room, uint8_t& branchId) noexcept;
- uint8_t GetDeepestDepthFromStart() const noexcept
- {
- return mDistance;
- }
+ uint8_t GetDeepestDepthFromStart() const noexcept;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ /**
+ Calculate CRC32
+ \return CRC32
+ */
+ uint32_t CalculateCRC32() const noexcept;
private:
/**
@@ -264,11 +214,6 @@ namespace dungeon
*/
bool ExpandSpace(GenerateParameter& parameter) noexcept;
- /**
- 重複した部屋や範囲外の部屋を除去をします
- */
- bool RemoveInvalidRooms(const GenerateParameter& parameter) noexcept;
-
/*
階層の高さを検出
*/
@@ -279,6 +224,11 @@ namespace dungeon
*/
bool ExtractionAisles(const GenerateParameter& parameter) noexcept;
+ /**
+ 開始部屋と終了部屋のサブレベルを配置する隙間を調整
+ */
+ bool AdjustedStartAndGoalSublevel(GenerateParameter& parameter) noexcept;
+
/**
ボクセル情報を生成
*/
@@ -312,7 +262,10 @@ namespace dungeon
GenerateParameter mGenerateParameter;
std::shared_ptr mVoxel;
+
std::list> mRooms;
+ std::shared_ptr mStartRoom;
+ std::shared_ptr mGoalRoom;
std::vector mFloorHeight;
@@ -322,7 +275,9 @@ namespace dungeon
std::vector mAisles;
- std::function&)> mQueryParts;
+ std::function&)> mOnQueryParts;
+ std::function&)> mOnStartParts;
+ std::function&)> mOnGoalParts;
uint8_t mDistance = 0;
diff --git a/Source/DungeonGenerator/Private/Core/Generator.inl b/Source/DungeonGenerator/Private/Core/Generator.inl
index 78595ce..c219309 100644
--- a/Source/DungeonGenerator/Private/Core/Generator.inl
+++ b/Source/DungeonGenerator/Private/Core/Generator.inl
@@ -14,4 +14,99 @@ namespace dungeon
{
return mLastError;
}
+
+ inline void Generator::ForEach(std::function&)> func) noexcept
+ {
+ for (const auto& room : mRooms)
+ {
+ func(room);
+ }
+ }
+
+ /**
+ 生成された部屋を参照します
+ */
+ inline void Generator::ForEach(std::function&)> func) const noexcept
+ {
+ for (const auto& room : mRooms)
+ {
+ func(room);
+ }
+ }
+
+
+ inline void Generator::EachAisle(std::function func) const noexcept
+ {
+ for (const auto& aisle : mAisles)
+ {
+ func(aisle);
+ }
+ }
+
+ inline void Generator::FindAisle(const std::shared_ptr& room, std::function func) noexcept
+ {
+ for (auto& aisle : mAisles)
+ {
+ const auto& room0 = aisle.GetPoint(0)->GetOwnerRoom();
+ const auto& room1 = aisle.GetPoint(1)->GetOwnerRoom();
+ if (room == room0 || room == room1)
+ {
+ if (func(aisle))
+ break;
+ }
+ }
+ }
+
+ inline void Generator::FindAisle(const std::shared_ptr& room, std::function func) const noexcept
+ {
+ for (const auto& aisle : mAisles)
+ {
+ const auto& room0 = aisle.GetPoint(0)->GetOwnerRoom();
+ const auto& room1 = aisle.GetPoint(1)->GetOwnerRoom();
+ if (room == room0 || room == room1)
+ {
+ if (func(aisle))
+ break;
+ }
+ }
+ }
+
+ inline void Generator::OnQueryParts(std::function&)> func) noexcept
+ {
+ mOnQueryParts = func;
+ }
+
+ inline void Generator::OnStartParts(std::function&)> func) noexcept
+ {
+ mOnStartParts = func;
+ }
+
+ inline void Generator::OnGoalParts(std::function&)> func) noexcept
+ {
+ mOnGoalParts = func;
+ }
+
+
+ inline const std::shared_ptr& Generator::GetStartPoint() const noexcept
+ {
+ return mStartPoint;
+ }
+
+ inline const std::shared_ptr& Generator::GetGoalPoint() const noexcept
+ {
+ return mGoalPoint;
+ }
+
+ inline void Generator::EachLeafPoint(std::function& point)> func) const noexcept
+ {
+ for (auto& point : mLeafPoints)
+ {
+ func(point);
+ }
+ }
+
+ inline uint8_t Generator::GetDeepestDepthFromStart() const noexcept
+ {
+ return mDistance;
+ }
}
diff --git a/Source/DungeonGenerator/Private/Core/Grid.cpp b/Source/DungeonGenerator/Private/Core/Grid.cpp
index 551dace..c0b7d10 100644
--- a/Source/DungeonGenerator/Private/Core/Grid.cpp
+++ b/Source/DungeonGenerator/Private/Core/Grid.cpp
@@ -160,7 +160,7 @@ namespace dungeon
/*
自身からtoGridを見た時に壁が生成されるか判定します
*/
- bool Grid::CanBuildWall(const Grid& toGrid, const Direction::Index direction, const bool mergeRooms) const noexcept
+ bool Grid::CanBuildWall(const Grid& toGrid, const Grid& underGrid, const Direction::Index direction, const bool mergeRooms) const noexcept
{
// 部屋と部屋の間に壁を生成する?
if (!mergeRooms)
@@ -171,7 +171,7 @@ namespace dungeon
*/
if (IsKindOfRoomTypeWithoutGate() && toGrid.IsKindOfRoomTypeWithoutGate())
{
- return mIdentifier != toGrid.mIdentifier;
+ return GetIdentifier() != toGrid.GetIdentifier();
}
}
@@ -204,9 +204,7 @@ namespace dungeon
return toGrid.GetIdentifier() != GetIdentifier();
}
- return
- toGrid.IsKindOfRoomTypeWithoutGate() ||
- toGrid.IsKindOfSpatialType();
+ return toGrid.IsKindOfSpatialType() || toGrid.IsKindOfRoomTypeWithoutGate();
}
else if (mType == Type::Slope)
{
@@ -216,10 +214,10 @@ namespace dungeon
// グリッドの識別番号が不一致なら壁がある
return
(toGrid.GetDirection().IsNorthSouth() != Direction::IsNorthSouth(direction)) ||
- (toGrid.mIdentifier != mIdentifier);
+ (toGrid.GetIdentifier() != GetIdentifier());
}
- return toGrid.IsKindOfSpatialType();
+ return toGrid.IsKindOfSpatialType() || toGrid.IsKindOfRoomTypeWithoutGate();
}
else if (mType == Type::Atrium)
{
@@ -227,11 +225,20 @@ namespace dungeon
{
// 方向が交差していたら壁
// グリッドの識別番号が不一致なら壁がある
- return toGrid.GetDirection().IsNorthSouth() != Direction::IsNorthSouth(direction) ||
- (toGrid.mIdentifier != mIdentifier);
+ return
+ (toGrid.GetDirection().IsNorthSouth() != Direction::IsNorthSouth(direction)) ||
+ (toGrid.GetIdentifier() != GetIdentifier());
}
- return toGrid.IsKindOfSpatialType();
+ if (toGrid.IsKindOfSpatialType())
+ {
+ if (GetDirection().IsNorthSouth() != Direction::IsNorthSouth(direction))
+ return true;
+
+ return underGrid.mType == Type::Slope;
+ }
+
+ return toGrid.IsKindOfRoomTypeWithoutGate();
}
return false;
@@ -322,17 +329,38 @@ namespace dungeon
*/
bool Grid::CanBuildPillar(const Grid& toGrid) const noexcept
{
- /*
- 判定が怪しいので見直してください
- */
+#if 0
+ // 部屋と部屋の間に壁を生成する?
+ //if (!mergeRooms)
+ {
+ /*
+ 部屋と部屋が隣接している場合、
+ グリッドの識別番号(=部屋の識別番号)が不一致なら壁がある
+ */
+ if (IsKindOfRoomTypeWithoutGate() && toGrid.IsKindOfRoomTypeWithoutGate())
+ {
+ return GetIdentifier() != toGrid.GetIdentifier();
+ }
+ }
+
+ if (!toGrid.IsHorizontallyPassable())
+ return false;
+ if (toGrid.GetType() == dungeon::Grid::Type::Empty)
+ return false;
+ if (toGrid.GetType() == dungeon::Grid::Type::Atrium || toGrid.GetType() == dungeon::Grid::Type::Slope)
+ {
+ // 通路の識別子が違うなら壁
+ return toGrid.GetIdentifier() != GetIdentifier();
+ }
+#else
+ // 判定が怪しいので見直してください
return
- toGrid.IsHorizontallyPassable() &&
+ toGrid.IsHorizontallyPassable() /* &&
(
- toGrid.GetType() != dungeon::Grid::Type::Empty &&
- /*result.GetType() != dungeon::Grid::Type::Gate &&*/
toGrid.GetType() != dungeon::Grid::Type::Atrium &&
toGrid.GetType() != dungeon::Grid::Type::Slope
- );
+ )*/;
+#endif
}
/*
@@ -416,4 +444,22 @@ namespace dungeon
const size_t index = static_cast(mProps);
return names[index];
}
+
+ FString Grid::GetNoMeshGenerationName() const noexcept
+ {
+ FString noMeshGenerationName(TEXT("NoMeshGeneration: "));
+
+ if (mNoMeshGeneration & NoMeshGenerationRoofMask)
+ {
+ noMeshGenerationName += TEXT("Roof");
+ }
+ if (mNoMeshGeneration & NoMeshGenerationFloorMask)
+ {
+ if (!noMeshGenerationName.IsEmpty())
+ noMeshGenerationName += TEXT(",");
+ noMeshGenerationName += TEXT("Floor");
+ }
+
+ return noMeshGenerationName;
+ }
}
diff --git a/Source/DungeonGenerator/Private/Core/Grid.h b/Source/DungeonGenerator/Private/Core/Grid.h
index f9241cc..7d4a5d7 100644
--- a/Source/DungeonGenerator/Private/Core/Grid.h
+++ b/Source/DungeonGenerator/Private/Core/Grid.h
@@ -7,12 +7,14 @@ All Rights Reserved.
*/
#pragma once
-#include "Core/Math/Random.h"
#include "Direction.h"
-#include
namespace dungeon
{
+ /**
+ @addtogroup PathGeneration
+ @{
+ */
/**
グリッドクラス
*/
@@ -185,12 +187,12 @@ namespace dungeon
/**
床(部屋)グリッドを生成します
*/
- static Grid CreateFloor(Random& random, const uint16_t identifier) noexcept;
+ static Grid CreateFloor(const std::shared_ptr& random, const uint16_t identifier) noexcept;
/**
デッキ(部屋の周辺)グリッドを生成します
*/
- static Grid CreateDeck(Random& random, const uint16_t identifier) noexcept;
+ static Grid CreateDeck(const std::shared_ptr& random, const uint16_t identifier) noexcept;
// 判定補助関数
/**
@@ -222,7 +224,7 @@ namespace dungeon
\param[in] mergeRooms 部屋と部屋を結合する
\return trueならば壁の生成が可能
*/
- bool CanBuildWall(const Grid& toGrid, const Direction::Index direction, const bool mergeRooms) const noexcept;
+ bool CanBuildWall(const Grid& toGrid, const Grid& underGrid, const Direction::Index direction, const bool mergeRooms) const noexcept;
/**
自身からtoGridを見た時に壁が生成されるか判定します
@@ -278,22 +280,28 @@ namespace dungeon
const FString& GetTypeName() const noexcept;
const FString& GetPropsName() const noexcept;
+ FString GetNoMeshGenerationName() const noexcept;
private:
- static constexpr uint16_t InvalidIdentifier = static_cast(~0);
-
Type mType;
Props mProps;
Direction mDirection;
- uint16_t mIdentifier = InvalidIdentifier;
enum class NoMeshGeneration : uint8_t
{
Floor,
Roof
};
- std::bitset<2> mNoMeshGeneration = 0;
+ static constexpr uint8_t NoMeshGenerationRoofMask = 1 << static_cast(NoMeshGeneration::Roof);
+ static constexpr uint8_t NoMeshGenerationFloorMask = 1 << static_cast(NoMeshGeneration::Floor);
+ uint8_t mNoMeshGeneration = 0;
+
+ static constexpr uint16_t InvalidIdentifier = static_cast(~0);
+ uint16_t mIdentifier = InvalidIdentifier;
};
+ /**
+ @}
+ */
}
#include "Grid.inl"
diff --git a/Source/DungeonGenerator/Private/Core/Grid.inl b/Source/DungeonGenerator/Private/Core/Grid.inl
index 066a669..e379993 100644
--- a/Source/DungeonGenerator/Private/Core/Grid.inl
+++ b/Source/DungeonGenerator/Private/Core/Grid.inl
@@ -41,12 +41,12 @@ namespace dungeon
{
}
- inline Grid Grid::CreateFloor(Random& random, const uint16_t identifier) noexcept
+ inline Grid Grid::CreateFloor(const std::shared_ptr& random, const uint16_t identifier) noexcept
{
return Grid(Type::Floor, Direction::CreateFromRandom(random), identifier);
}
- inline Grid Grid::CreateDeck(Random& random, const uint16_t identifier) noexcept
+ inline Grid Grid::CreateDeck(const std::shared_ptr& random, const uint16_t identifier) noexcept
{
return Grid(Type::Deck, Direction::CreateFromRandom(random), identifier);
}
@@ -98,17 +98,24 @@ namespace dungeon
inline void Grid::SetNoMeshGeneration(const bool noRoofMeshGeneration, const bool noFloorMeshGeneration)
{
- mNoMeshGeneration.set(static_cast(NoMeshGeneration::Roof), noRoofMeshGeneration);
- mNoMeshGeneration.set(static_cast(NoMeshGeneration::Floor), noFloorMeshGeneration);
+ if(noRoofMeshGeneration)
+ mNoMeshGeneration |= NoMeshGenerationRoofMask;
+ else
+ mNoMeshGeneration &= ~NoMeshGenerationRoofMask;
+
+ if (noFloorMeshGeneration)
+ mNoMeshGeneration |= NoMeshGenerationFloorMask;
+ else
+ mNoMeshGeneration &= ~NoMeshGenerationFloorMask;
}
inline bool Grid::IsNoFloorMeshGeneration() const noexcept
{
- return mNoMeshGeneration.test(static_cast(NoMeshGeneration::Floor));
+ return (mNoMeshGeneration & NoMeshGenerationFloorMask) != 0;
}
inline bool Grid::IsNoRoofMeshGeneration() const noexcept
{
- return mNoMeshGeneration.test(static_cast(NoMeshGeneration::Roof));
+ return (mNoMeshGeneration & NoMeshGenerationRoofMask) != 0;
}
}
diff --git a/Source/DungeonGenerator/Private/Core/Helper/Crc.h b/Source/DungeonGenerator/Private/Core/Helper/Crc.h
new file mode 100644
index 0000000..cf4a269
--- /dev/null
+++ b/Source/DungeonGenerator/Private/Core/Helper/Crc.h
@@ -0,0 +1,58 @@
+#pragma once
+
+namespace dungeon
+{
+ namespace detail
+ {
+ // CRC-32 (zlib): 0xEDB88320, Reverse
+ static constexpr uint32_t Crc32Table[256] = {
+ 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U, 0x706af48fU, 0xe963a535U, 0x9e6495a3U,
+ 0x0edb8832U, 0x79dcb8a4U, 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U, 0x90bf1d91U,
+ 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU, 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U,
+ 0x136c9856U, 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U, 0xfa0f3d63U, 0x8d080df5U,
+ 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U, 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
+ 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U, 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U,
+ 0x26d930acU, 0x51de003aU, 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U, 0xb8bda50fU,
+ 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U, 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU,
+ 0x76dc4190U, 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU, 0x9fbfe4a5U, 0xe8b8d433U,
+ 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU, 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
+ 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU, 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U,
+ 0x65b0d9c6U, 0x12b7e950U, 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, 0xfbd44c65U,
+ 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U, 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU,
+ 0x4369e96aU, 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U, 0xaa0a4c5fU, 0xdd0d7cc9U,
+ 0x5005713cU, 0x270241aaU, 0xbe0b1010U, 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
+ 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U, 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU,
+ 0xedb88320U, 0x9abfb3b6U, 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U, 0x73dc1683U,
+ 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U, 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U,
+ 0xf00f9344U, 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU, 0x196c3671U, 0x6e6b06e7U,
+ 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU, 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
+ 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U, 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU,
+ 0xd80d2bdaU, 0xaf0a1b4cU, 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU, 0x4669be79U,
+ 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U, 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU,
+ 0xc5ba3bbeU, 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U, 0x2cd99e8bU, 0x5bdeae1dU,
+ 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU, 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
+ 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU, 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U,
+ 0x86d3d2d4U, 0xf1d4e242U, 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U, 0x18b74777U,
+ 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU, 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U,
+ 0xa00ae278U, 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U, 0x4969474dU, 0x3e6e77dbU,
+ 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U, 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
+ 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U, 0xcdd70693U, 0x54de5729U, 0x23d967bfU,
+ 0xb3667a2eU, 0xc4614ab8U, 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, 0x2d02ef8dU
+ };
+ }
+
+ static constexpr uint32_t GenerateCrc32(const char* text, const size_t size, uint32_t hash = 0xffffffffU) noexcept
+ {
+ for (size_t i = 0; i < size; ++i)
+ {
+ const uint8_t index = static_cast((hash & 0xff) ^ text[i]);
+ hash = detail::Crc32Table[index] ^ (hash >> 8);
+ }
+ return hash ^ 0xffffffffU;
+ }
+
+ static constexpr uint32_t GenerateCrc32(const void* data, const size_t size, uint32_t hash = 0xffffffffU) noexcept
+ {
+ return GenerateCrc32(static_cast(data), size, hash);
+ }
+}
diff --git a/Source/DungeonGenerator/Private/Core/Identifier.h b/Source/DungeonGenerator/Private/Core/Identifier.h
index bb393c0..f07ecdf 100644
--- a/Source/DungeonGenerator/Private/Core/Identifier.h
+++ b/Source/DungeonGenerator/Private/Core/Identifier.h
@@ -10,6 +10,10 @@ All Rights Reserved.
namespace dungeon
{
+ /**
+ @addtogroup PathGeneration
+ @{
+ */
/**
識別子クラス
*/
@@ -47,6 +51,11 @@ namespace dungeon
Type GetType() const noexcept;
bool IsType(const Type type) const noexcept;
+ /*
+ Reset counter to identify
+ */
+ static void ResetCounter();
+
// TODO:移行が完了したら削除して下さい
uint16_t Get() const noexcept { return mIdentifier; }
@@ -58,6 +67,9 @@ namespace dungeon
static constexpr IdentifierType maskCounter = static_cast(~0) >> bitCount;
static IdentifierType mCounter;
};
+ /**
+ @}
+ */
}
#include "Identifier.inl"
diff --git a/Source/DungeonGenerator/Private/Core/Identifier.inl b/Source/DungeonGenerator/Private/Core/Identifier.inl
index c43e1e7..9d8b0fc 100644
--- a/Source/DungeonGenerator/Private/Core/Identifier.inl
+++ b/Source/DungeonGenerator/Private/Core/Identifier.inl
@@ -57,4 +57,9 @@ namespace dungeon
{
return type == GetType();
}
+
+ inline void Identifier::ResetCounter()
+ {
+ mCounter = 0;
+ }
}
diff --git a/Source/DungeonGenerator/Private/Core/Math/Math.h b/Source/DungeonGenerator/Private/Core/Math/Math.h
index a2be03f..1e88740 100644
--- a/Source/DungeonGenerator/Private/Core/Math/Math.h
+++ b/Source/DungeonGenerator/Private/Core/Math/Math.h
@@ -6,21 +6,89 @@ All Rights Reserved.
#pragma once
#include
+#include
namespace dungeon
{
+ //! commonly used calculations Implementation
namespace math
{
template
- inline T Square(const T value) noexcept
+ static constexpr T Pi() noexcept
+ {
+ return static_cast(3.14159265358979323846264338327950288);
+ }
+
+ template
+ static constexpr T PiHalf() noexcept
+ {
+ return Pi() * static_cast(0.5);
+ }
+
+ template
+ static constexpr T Pi2() noexcept
+ {
+ return Pi() * static_cast(2.);
+ }
+
+ template
+ static constexpr T Negative(const T t) noexcept
+ {
+ return -t;
+ }
+
+ template
+ static constexpr T Inverse(const T t) noexcept
+ {
+ return static_cast(1.) / t;
+ }
+
+ template
+ static constexpr T Sign(const T t) noexcept
+ {
+ return t >= static_cast(0.) ? static_cast(1.) : static_cast(-1.);
+ }
+
+ template
+ static constexpr T Square(const T value) noexcept
{
return value * value;
}
template
- T Clamp(const T value, const T min, const T max) noexcept
+ static constexpr T Clamp(const T value, const T min, const T max) noexcept
{
return std::max(min, std::min(value, max));
}
+
+ template
+ static constexpr bool Equal(const T a, const T b, const T eps = std::numeric_limits::epsilon()) noexcept
+ {
+ return IsZero(a - b, eps);
+ }
+
+ template
+ static constexpr bool IsZero(const T x, const T eps = std::numeric_limits::epsilon()) noexcept
+ {
+ return (-eps <= x && x <= eps);
+ }
+
+ template
+ static constexpr float Lerp(const T a, const T b, const T ratio)
+ {
+ return a + (b - a) * ratio;
+ }
+
+ template
+ static constexpr T ToRadian(const T degree)
+ {
+ return degree * (Pi() / static_cast(180.));
+ }
+
+ template
+ static constexpr T ToDegree(const T radian)
+ {
+ return radian * (static_cast(180.0) / Pi());
+ }
}
}
diff --git a/Source/DungeonGenerator/Private/Core/Math/PerlinNoise.cpp b/Source/DungeonGenerator/Private/Core/Math/PerlinNoise.cpp
index 6262b24..dc62fbd 100644
--- a/Source/DungeonGenerator/Private/Core/Math/PerlinNoise.cpp
+++ b/Source/DungeonGenerator/Private/Core/Math/PerlinNoise.cpp
@@ -8,15 +8,16 @@ All Rights Reserved.
#include "PerlinNoise.h"
#include "Random.h"
+#include
namespace dungeon
{
- PerlinNoise::PerlinNoise(Random& random)
+ PerlinNoise::PerlinNoise(const std::shared_ptr& random)
{
SetSeed(random);
}
- void PerlinNoise::SetSeed(Random& random)
+ void PerlinNoise::SetSeed(const std::shared_ptr& random)
{
for (std::size_t i = 0; i < 256; ++i)
{
@@ -24,7 +25,7 @@ namespace dungeon
}
for (std::size_t i = 256 - 2; i >= 1; --i)
{
- const std::size_t j = random.Get(256);
+ const std::size_t j = random->Get(256);
const uint8_t t = mHash[i];
mHash[i] = mHash[j];
mHash[j] = t;
diff --git a/Source/DungeonGenerator/Private/Core/Math/PerlinNoise.h b/Source/DungeonGenerator/Private/Core/Math/PerlinNoise.h
index 507b484..4d35b73 100644
--- a/Source/DungeonGenerator/Private/Core/Math/PerlinNoise.h
+++ b/Source/DungeonGenerator/Private/Core/Math/PerlinNoise.h
@@ -9,6 +9,7 @@ All Rights Reserved.
#pragma once
#include
#include
+#include
namespace dungeon
{
@@ -20,11 +21,11 @@ namespace dungeon
class PerlinNoise final
{
public:
- explicit PerlinNoise(Random& random);
+ explicit PerlinNoise(const std::shared_ptr& random);
~PerlinNoise() = default;
// SEED値を設定する
- void SetSeed(Random& random);
+ void SetSeed(const std::shared_ptr& random);
// オクターブ無しノイズを取得する
float Noise(float x, float y) const noexcept;
diff --git a/Source/DungeonGenerator/Private/Core/Math/Point.cpp b/Source/DungeonGenerator/Private/Core/Math/Point.cpp
index 5c4d412..52df557 100644
--- a/Source/DungeonGenerator/Private/Core/Math/Point.cpp
+++ b/Source/DungeonGenerator/Private/Core/Math/Point.cpp
@@ -66,6 +66,17 @@ namespace dungeon
return super::operator==(other);
}
+ void Point::ResetByRoomGroundCenter() noexcept
+ {
+ if (mRoom)
+ {
+ const Point& groundCenter = mRoom->GetGroundCenter();
+ X = groundCenter.X;
+ Y = groundCenter.Y;
+ Z = groundCenter.Z;
+ }
+ }
+
double Point::Dist(const Point& v0, const Point& v1) noexcept
{
return std::sqrt(Point::DistSquared(v0, v1));
diff --git a/Source/DungeonGenerator/Private/Core/Math/Point.h b/Source/DungeonGenerator/Private/Core/Math/Point.h
index 2b2716c..e7d66ad 100644
--- a/Source/DungeonGenerator/Private/Core/Math/Point.h
+++ b/Source/DungeonGenerator/Private/Core/Math/Point.h
@@ -87,6 +87,11 @@ namespace dungeon
*/
bool operator==(const Point& other) const noexcept;
+ /**
+ オーナーの部屋の中心にリセットします
+ */
+ void ResetByRoomGroundCenter() noexcept;
+
/**
2点間の距離を求めます
\param[in] v0 点0
diff --git a/Source/DungeonGenerator/Private/Core/Math/Random.h b/Source/DungeonGenerator/Private/Core/Math/Random.h
index 915a784..928c312 100644
--- a/Source/DungeonGenerator/Private/Core/Math/Random.h
+++ b/Source/DungeonGenerator/Private/Core/Math/Random.h
@@ -8,91 +8,83 @@ All Rights Reserved.
namespace dungeon
{
- /**
- 乱数クラス
- */
+ //! Generates random numbers by xorshift32
class Random
{
public:
- //! コンストラクタ
+ //! Default constructor
Random();
/**
- コンストラクタ
+ Constructor
\param[in] seed 乱数の種
*/
explicit Random(const uint32_t seed);
/**
- コピーコンストラクタ
+ copy constructor
*/
explicit Random(const Random& other);
/**
- ムーブコンストラクタ
+ move constructor
*/
explicit Random(Random&& other) noexcept;
/**
- コピー代入
+ copy assignment
*/
Random& operator = (const Random& other);
/**
- ムーブ代入
+ move assignment
*/
Random& operator = (Random&& other) noexcept;
/**
- 乱数の種を設定します
- \param[in] seed 乱数の種
+ Sets the random number seed
+ \param[in] seed Random number seeds
*/
void SetSeed(const uint32_t seed);
/**
- 符号の乱数を取得します
- \return -1または1
+ \return -1 or 1
+ T must be a signed type.
*/
template
T GetSign();
/**
- 乱数を取得します
- \return 整数では[type_min,type_max]、実数では[0,1]の範囲を等確率で返す
+ Get a random number
+ \return Returns the range [type_min,type_max) if T is an integer,
+ or [0,1] with equal probability if T is a real number.
*/
template
T Get();
/**
- 乱数を取得します
- \param[in] to 範囲
- \return 整数では[0,to)、実数では[0,to]の範囲を等確率で返す
+ Get a random number
+ \param[in] to Upper value
+ \return Returns the range [0,to) if T is an integer,
+ or [0,to] with equal probability if T is a real number.
*/
template
T Get(const T to);
/**
- 乱数を取得します
- \param[in] from 開始範囲
- \param[in] to 終了範囲
- \return 整数では[from,to)、実数では[from,to]の範囲を等確率で返す
+ Get a random number
+ \param[in] from Lower value
+ \param[in] to Upper value
+ \return Returns the range [from,to) if T is an integer,
+ or [from,to] with equal probability if T is a real number.
*/
template
T Get(const T from, const T to);
- /**
- インスタンスを取得します
- */
- static Random& Instance()
- {
- static Random instance;
- return instance;
- }
-
private:
/**
- uint32_t型の乱数を取得します
- \return [0,std::numeric_limits::max]の範囲を返す
+ Get a random number of type uint32_t
+ \return Returns a range of [0,std::numeric_limits::max
*/
uint32_t GetU32();
diff --git a/Source/DungeonGenerator/Private/Core/Math/Random.inl b/Source/DungeonGenerator/Private/Core/Math/Random.inl
index adbaaec..f5121a2 100644
--- a/Source/DungeonGenerator/Private/Core/Math/Random.inl
+++ b/Source/DungeonGenerator/Private/Core/Math/Random.inl
@@ -1,5 +1,4 @@
/**
-乱数クラス
\author Shun Moriya
\copyright 2023- Shun Moriya
All Rights Reserved.
@@ -14,7 +13,7 @@ All Rights Reserved.
namespace dungeon
{
/*
- constexpr if内のブロックの評価を遅延させるためのテンプレート
+ constexpr Template for delaying evaluation of blocks in if
*/
template
constexpr bool RandamFalse_v = false;
@@ -70,7 +69,7 @@ namespace dungeon
mZ = 521288629;
mW = 88675123;
- // 全て0にならないようにする
+ // Make sure it doesn't all go to zero.
do
{
mX ^= seed; mX ^= mX >> 21; mX ^= mX >> 4; mX *= 1332534557;
@@ -92,8 +91,11 @@ namespace dungeon
{
if constexpr (std::is_same())
{
- // 線形合同法と異なり、XorShiftは最下位ビットの短周期の規則性はない。
- // 0または1を直接得ることができるため、最下位ビットを取る実装としている。
+ /*
+ Unlike linear congruence, XorShift has no short - period regularity
+ in the least significant bit. Implementation that takes the least
+ significant bit because it is possible to obtain 0 or 1 directly.
+ */
return static_cast(GetU32() & 0x1);
}
else if constexpr (std::is_same())
@@ -108,15 +110,15 @@ namespace dungeon
}
else if constexpr (std::is_same())
{
- const uint64_t hight = static_cast(GetU32()) << 32ULL;
+ const uint64_t high = static_cast(GetU32()) << 32ULL;
const uint64_t low = static_cast(GetU32());
- return hight | low;
+ return high | low;
}
else if constexpr (std::is_same())
{
- const uint64_t hight = static_cast(GetU32()) << 32ULL;
+ const uint64_t high = static_cast(GetU32()) << 32ULL;
const uint64_t low = static_cast(GetU32());
- return static_cast(hight | low);
+ return static_cast(high | low);
}
else if constexpr (std::is_integral::value)
{
@@ -133,14 +135,14 @@ namespace dungeon
{
if constexpr (std::is_floating_point::value)
{
- const auto value = Get();
+ const T value = Get();
return value * to;
}
else
{
if (to != 0)
{
- const size_t value = Get();
+ const std::make_unsigned_t value = Get();
return value % to;
}
else
@@ -156,14 +158,14 @@ namespace dungeon
check(from <= to);
if constexpr (std::is_floating_point::value)
{
- const auto value = Get();
+ const T value = Get();
return from + value * (to - from);
}
else
{
if (from != to)
{
- const size_t value = Get();
+ const std::make_unsigned_t value = Get();
return from + value % (to - from);
}
else
diff --git a/Source/DungeonGenerator/Private/Core/Math/Tetrahedron.h b/Source/DungeonGenerator/Private/Core/Math/Tetrahedron.h
index 4b9c741..2c59428 100644
--- a/Source/DungeonGenerator/Private/Core/Math/Tetrahedron.h
+++ b/Source/DungeonGenerator/Private/Core/Math/Tetrahedron.h
@@ -10,6 +10,7 @@ All Rights Reserved.
#pragma once
#include "Circle.h"
#include
+#include
namespace dungeon
{
diff --git a/Source/DungeonGenerator/Private/Core/MinimumSpanningTree.cpp b/Source/DungeonGenerator/Private/Core/MinimumSpanningTree.cpp
index 38d85ee..fd6fa8c 100644
--- a/Source/DungeonGenerator/Private/Core/MinimumSpanningTree.cpp
+++ b/Source/DungeonGenerator/Private/Core/MinimumSpanningTree.cpp
@@ -230,7 +230,7 @@ namespace dungeon
mStartPoint = FindStartPoint();
size_t startPointIndex = verteces.Find(mStartPoint);
- // cppcheck-suppress [knownConditionTrueFalse, unmatchedSuppression]
+ // cppcheck-suppress [knownConditionTrueFalse]
if (startPointIndex != static_cast(~0))
{
// スタートから各部屋の深さ(部屋の数)を設定
diff --git a/Source/DungeonGenerator/Private/Core/MinimumSpanningTree.h b/Source/DungeonGenerator/Private/Core/MinimumSpanningTree.h
index 2ee8f40..a534cc4 100644
--- a/Source/DungeonGenerator/Private/Core/MinimumSpanningTree.h
+++ b/Source/DungeonGenerator/Private/Core/MinimumSpanningTree.h
@@ -14,7 +14,11 @@ All Rights Reserved.
namespace dungeon
{
/**
- 最小スパニングツリークラス
+ @addtogroup PathSelection
+ @{
+ */
+ /**
+ Minimum Spanning Tree Class
*/
class MinimumSpanningTree final
{
@@ -221,6 +225,9 @@ namespace dungeon
uint8_t mDistance = 0;
};
+ /**
+ @}
+ */
}
#include "MinimumSpanningTree.inl"
diff --git a/Source/DungeonGenerator/Private/Core/MissionGraph/MissionGraph.cpp b/Source/DungeonGenerator/Private/Core/MissionGraph/MissionGraph.cpp
index f10a590..e566f67 100644
--- a/Source/DungeonGenerator/Private/Core/MissionGraph/MissionGraph.cpp
+++ b/Source/DungeonGenerator/Private/Core/MissionGraph/MissionGraph.cpp
@@ -53,9 +53,10 @@ namespace dungeon
keyRooms = mGenerator->FindByRoute(connectingRoom);
if (keyRooms.size() > 0)
{
- // TODO:DrawLots内で乱数を使っています
+ const std::shared_ptr& random = mGenerator->GetGenerateParameter().GetRandom();
+
const uint8_t roomBranch = room->GetBranchId();
- const auto keyRoom = DrawLots(keyRooms.begin(), keyRooms.end(), [roomBranch](const std::shared_ptr& room)
+ const auto keyRoom = DrawLots(random, keyRooms.begin(), keyRooms.end(), [roomBranch](const std::shared_ptr& room)
{
uint32_t weight = room->GetDepthFromStart();
if (room->GetBranchId() - roomBranch)
@@ -86,9 +87,6 @@ namespace dungeon
}
}
- /*
- TODO:乱数を共通化して下さい
- */
void MissionGraph::Generate(const std::shared_ptr& room) noexcept
{
#if 0
@@ -111,52 +109,18 @@ namespace dungeon
keyRooms = mGenerator->FindByRoute(room == room0 ? room1 : room0);
if (keyRooms.size() > 0)
{
-#if 0
- // TODO:DrawLots内で乱数を使っています
- const uint8_t roomBranch = room->GetBranchId();
- const auto keyRoom = DrawLots(keyRooms.begin(), keyRooms.end(), [roomBranch](const std::shared_ptr& room)
- {
- const uint32_t deltaBranch = std::abs(roomBranch - room->GetBranchId());
- const uint32_t depthFromStart = room->GetDepthFromStart();
- uint32_t weight = deltaBranch + depthFromStart;
- //if (room->GetParts() == Room::Parts::Hanare)
- // weight *= 2;
- return weight;
- }
- );
- if (keyRoom != keyRooms.end())
- {
- // That's the room where I'm supposed to put the key.
- check((*keyRoom)->GetItem() == Room::Item::Empty);
- (*keyRoom)->SetItem(Room::Item::Key);
-#if 0
- Generate(*keyRoom);
-#else
- //const auto lockRoom = keyRooms[std::rand() % keyRooms.size()];
- const auto lockRoom = DrawLots(keyRooms.begin(), keyRooms.end(), [](const std::shared_ptr& room)
- {
- return room->GetDepthFromStart();
- }
- );
- Generate(*lockRoom);
-#endif
- }
- else
- {
- // It did not decide on a room to put the key, so it will be unlocked
- aisle->SetLock(false);
- }
-#else
+ const std::shared_ptr& random = mGenerator->GetGenerateParameter().GetRandom();
+
// That's the room where I'm supposed to put the key.
{
- // TODO:共通の乱数を使用してください
- const auto keyRoom = keyRooms[std::rand() % keyRooms.size()];
+ const size_t index = random->Get(keyRooms.size());
+ const auto keyRoom = keyRooms[index];
check(keyRoom->GetItem() == Room::Item::Empty);
keyRoom->SetItem(Room::Item::Key);
}
// TODO:DrawLots内で乱数を使っています
- const auto lockRoom = DrawLots(keyRooms.begin(), keyRooms.end(), [](const std::shared_ptr& room)
+ const auto lockRoom = DrawLots(random, keyRooms.begin(), keyRooms.end(), [](const std::shared_ptr& room)
{
const uint32_t depthFromStart = room->GetDepthFromStart();
return depthFromStart * 10;
@@ -166,7 +130,6 @@ namespace dungeon
{
Generate(*lockRoom);
}
-#endif
}
else
{
diff --git a/Source/DungeonGenerator/Private/Core/PathFinder.cpp b/Source/DungeonGenerator/Private/Core/PathFinder.cpp
index 0398b17..f80aa42 100644
--- a/Source/DungeonGenerator/Private/Core/PathFinder.cpp
+++ b/Source/DungeonGenerator/Private/Core/PathFinder.cpp
@@ -13,7 +13,7 @@ All Rights Reserved.
// 定義するとマンハッタン距離で計算する。未定義ならユークリッド距離で計算する
#define CALCULATE_IN_MANHATTAN_DISTANCE
-#if WITH_EDITOR && JENKINS_FOR_DEVELOP
+#if WITH_EDITOR & JENKINS_FOR_DEVELOP
// 定義すると経路を調べるため、中間データを開放しない
//#define CHECK_ROUTE
#endif
@@ -103,13 +103,13 @@ namespace dungeon
// コスト計算
const uint32_t newCost = TotalCost(cost, location, goal);
- // Openリスト内を検索
+ // オープンリスト内を検索
const auto openNode = mOpen.find(key);
- // Closeリスト内を検索
+ // クローズリスト内を検索
const auto closeNode = mClose.find(key);
- // OpenとClose両方に存在する事はありえない
+ // オープンとクローズ両方に存在する事はありえない
check((openNode != mOpen.end() && closeNode != mClose.end()) == false);
// オープンリストに追加するノードがある。かつ、新しいノードの方がトータルコストが低い
@@ -117,7 +117,7 @@ namespace dungeon
{
if (openNode->second.mCost > newCost)
{
- // Openリストを更新
+ // Replace node with open list
openNode->second.mNodeType = nodeType;
openNode->second.mDirection = direction;
openNode->second.mParentKey = parentKey;
@@ -130,18 +130,18 @@ namespace dungeon
{
if (closeNode->second.mCost > newCost)
{
- // Closeリストから消す
+ // Delete from close list
mClose.erase(closeNode);
- // Openリストに再登録
+ // Re-register on open list
mOpen.emplace(key, OpenNode(parentKey, nodeType, location, direction, searchDirection, newCost));
RevertOpenNode(key);
}
}
- // オープンとクローズリストに追加するノードがない
+ // No nodes on open and closed list
else
{
- // Openリストに登録
+ // Register open List
mOpen.emplace(key, OpenNode(parentKey, nodeType, location, direction, searchDirection, newCost));
}
@@ -158,7 +158,7 @@ namespace dungeon
if (mOpen.empty())
return false;
- // 最もコストの低いノードを検索
+ // Find the node with the lowest cost
std::unordered_map::iterator result = mOpen.begin();
uint32_t minimumCost = std::numeric_limits::max();
for (std::unordered_map::iterator i = mOpen.begin(); i != mOpen.end(); ++i)
@@ -168,7 +168,7 @@ namespace dungeon
minimumCost = (*i).second.mCost;
result = i;
}
- // タイブレーク(コストが同じならば上下移動を優先)
+ // Tiebreaker (if costs are the same, up/down movement is preferred)
else if (minimumCost == (*i).second.mCost)
{
if ((*i).second.mNodeType == NodeType::Downstairs || (*i).second.mNodeType == NodeType::Upstairs)
diff --git a/Source/DungeonGenerator/Private/Core/PathFinder.h b/Source/DungeonGenerator/Private/Core/PathFinder.h
index 58411b2..8da2cbc 100644
--- a/Source/DungeonGenerator/Private/Core/PathFinder.h
+++ b/Source/DungeonGenerator/Private/Core/PathFinder.h
@@ -16,6 +16,11 @@ All Rights Reserved.
namespace dungeon
{
+ /**
+ @addtogroup PathGeneration
+ @{
+ */
+
/**
A*によるパス検索クラス
*/
@@ -307,6 +312,9 @@ namespace dungeon
std::unordered_map mClose;
std::vector mRoute;
};
+ /**
+ @}
+ */
}
#include "PathFinder.inl"
diff --git a/Source/DungeonGenerator/Private/Core/PathGoalCondition.h b/Source/DungeonGenerator/Private/Core/PathGoalCondition.h
index 287d85f..db85009 100644
--- a/Source/DungeonGenerator/Private/Core/PathGoalCondition.h
+++ b/Source/DungeonGenerator/Private/Core/PathGoalCondition.h
@@ -12,6 +12,10 @@ All Rights Reserved.
namespace dungeon
{
+ /**
+ @addtogroup PathGeneration
+ @{
+ */
/**
ゴール条件クラス
*/
@@ -73,6 +77,9 @@ namespace dungeon
private:
FIntRect mRect;
};
+ /**
+ @}
+ */
inline PathGoalCondition::PathGoalCondition(const FIntRect& rect) noexcept
: mRect(rect)
diff --git a/Source/DungeonGenerator/Private/Core/PathNodeSwitcher.h b/Source/DungeonGenerator/Private/Core/PathNodeSwitcher.h
index df25f7a..f2f99c6 100644
--- a/Source/DungeonGenerator/Private/Core/PathNodeSwitcher.h
+++ b/Source/DungeonGenerator/Private/Core/PathNodeSwitcher.h
@@ -14,6 +14,10 @@ All Rights Reserved.
namespace dungeon
{
+ /**
+ @addtogroup PathGeneration
+ @{
+ */
/*
パス検索ノードの予約・使用中切り替えクラス
*/
@@ -49,6 +53,9 @@ namespace dungeon
std::unordered_map> mReserved;
std::unordered_map> mUsed;
};
+ /**
+ @}
+ */
}
#include "PathNodeSwitcher.inl"
diff --git a/Source/DungeonGenerator/Private/Core/PathNodeSwitcher.inl b/Source/DungeonGenerator/Private/Core/PathNodeSwitcher.inl
index 9d96d81..a2e9b5e 100644
--- a/Source/DungeonGenerator/Private/Core/PathNodeSwitcher.inl
+++ b/Source/DungeonGenerator/Private/Core/PathNodeSwitcher.inl
@@ -9,6 +9,7 @@ All Rights Reserved.
#pragma once
#include "PathFinder.h"
#include "PathNodeSwitcher.h"
+#include
namespace dungeon
{
@@ -51,12 +52,11 @@ namespace dungeon
inline bool PathNodeSwitcher::IsUsing(const uint64_t key) const
{
- for (const auto& node : mUsed)
- {
- if (node.second->Contain(key))
- return true;
- }
- return false;
+ return std::any_of(mUsed.begin(), mUsed.end(), [key](const std::pair>& node)
+ {
+ return node.second->Contain(key);
+ }
+ );
}
inline void PathNodeSwitcher::Clear()
diff --git a/Source/DungeonGenerator/Private/Core/Room.cpp b/Source/DungeonGenerator/Private/Core/Room.cpp
index 227821d..7a0d07f 100644
--- a/Source/DungeonGenerator/Private/Core/Room.cpp
+++ b/Source/DungeonGenerator/Private/Core/Room.cpp
@@ -22,24 +22,35 @@ namespace
\param[in] maximum 最大値
\return 乱数で決めたサイズ
*/
- static uint32_t randSize(dungeon::Random& random, const uint32_t minimum, const uint32_t maximum)
+ static uint32_t randSize(const std::shared_ptr& random, const uint32_t minimum, const uint32_t maximum)
{
- return random.Get(minimum, maximum);
+ return random->Get(minimum, maximum + 1);
}
}
namespace dungeon
{
Room::Room(const GenerateParameter& parameter, const FIntVector& location) noexcept
+ : mX(location.X)
+ , mY(location.Y)
+ , mZ(location.Z)
{
- mX = location.X;
- mY = location.Y;
- mZ = location.Z;
mWidth = randSize(parameter.GetRandom(), parameter.GetMinRoomWidth(), parameter.GetMaxRoomWidth());
mDepth = randSize(parameter.GetRandom(), parameter.GetMinRoomDepth(), parameter.GetMaxRoomDepth());
mHeight = randSize(parameter.GetRandom(), parameter.GetMinRoomHeight(), parameter.GetMaxRoomHeight());
}
+ Room::Room(const FIntVector& location, const FIntVector& size, const bool undeletable) noexcept
+ : mX(location.X)
+ , mY(location.Y)
+ , mZ(location.Z)
+ , mWidth(size.X)
+ , mDepth(size.Y)
+ , mHeight(size.Z)
+ , mUndeletable(undeletable)
+ {
+ }
+
Room::Room(const Room& other) noexcept
: mX(other.mX)
, mY(other.mY)
@@ -282,10 +293,10 @@ namespace dungeon
{
static const std::array names = {
"unidentified",
- "start",
- "goal",
"hall",
"hanare",
+ "start",
+ "goal",
};
return names[static_cast(mParts)];
}
diff --git a/Source/DungeonGenerator/Private/Core/Room.h b/Source/DungeonGenerator/Private/Core/Room.h
index 75331df..4d8c952 100644
--- a/Source/DungeonGenerator/Private/Core/Room.h
+++ b/Source/DungeonGenerator/Private/Core/Room.h
@@ -32,12 +32,12 @@ namespace dungeon
enum class Parts : uint8_t
{
Unidentified, //!< 未識別
- Start, //!< スタート地点
- Goal, //!< ゴール地点
Hall, //!< 広間(通路が複数つながっている)
Hanare, //!< 離れ(通路が一つだけつながっている)
+ Start, //!< スタート地点
+ Goal, //!< ゴール地点
};
- static constexpr uint8_t PartsSize = static_cast(Parts::Hanare) + 1;
+ static constexpr uint8_t PartsSize = static_cast(Parts::Goal) + 1;
/**
変更した場合はGetItemNameもあわせて修正して下さい
@@ -56,6 +56,11 @@ namespace dungeon
*/
Room(const GenerateParameter& parameter, const FIntVector& location) noexcept;
+ /**
+ コンストラクタ
+ */
+ Room(const FIntVector& location, const FIntVector& size, const bool undeletable) noexcept;
+
/**
コピーコンストラクタ
*/
@@ -311,6 +316,10 @@ namespace dungeon
*/
void GetDataBounds(FIntVector& min, FIntVector& max) const noexcept;
+ bool IsUndeletable() const noexcept;
+
+ void SetUndeletables(const bool undeletable) noexcept;
+
/**
Sets mesh generation prohibition
\param[in] noRoofMeshGeneration No roof mesh generation
@@ -349,6 +358,8 @@ namespace dungeon
uint8_t mDepthFromStart = std::numeric_limits::max();
uint8_t mBranchId = std::numeric_limits::max();
+ bool mUndeletable = false;
+
enum class NoMeshGeneration : uint8_t
{
Floor,
diff --git a/Source/DungeonGenerator/Private/Core/Room.inl b/Source/DungeonGenerator/Private/Core/Room.inl
index a19d671..81ad5e2 100644
--- a/Source/DungeonGenerator/Private/Core/Room.inl
+++ b/Source/DungeonGenerator/Private/Core/Room.inl
@@ -10,6 +10,16 @@ All Rights Reserved.
namespace dungeon
{
+ inline bool Room::IsUndeletable() const noexcept
+ {
+ return mUndeletable;
+ }
+
+ inline void Room::SetUndeletables(const bool undeletable) noexcept
+ {
+ mUndeletable = undeletable;
+ }
+
inline void Room::SetNoMeshGeneration(const bool noRoofMeshGeneration, const bool noFloorMeshGeneration)
{
mNoMeshGeneration.set(static_cast(NoMeshGeneration::Roof), noRoofMeshGeneration);
diff --git a/Source/DungeonGenerator/Private/Core/Voxel.cpp b/Source/DungeonGenerator/Private/Core/Voxel.cpp
index 64b352c..123f44b 100644
--- a/Source/DungeonGenerator/Private/Core/Voxel.cpp
+++ b/Source/DungeonGenerator/Private/Core/Voxel.cpp
@@ -13,10 +13,11 @@ All Rights Reserved.
#include "PathGoalCondition.h"
#include "Debug/BuildInfomation.h"
#include "Debug/Debug.h"
+#include "Helper/Crc.h"
#include "Math/Math.h"
#include
-#if WITH_EDITOR && JENKINS_FOR_DEVELOP
+#if WITH_EDITOR & JENKINS_FOR_DEVELOP
// 定義するとデバッグに便利なログを出力します
//#define DEBUG_SHOW_DEVELOP_LOG
#endif
@@ -130,7 +131,6 @@ namespace dungeon
gateFinder.Entry(openLocation, goal);
}
}
-
}
}
@@ -146,11 +146,11 @@ namespace dungeon
return false;
}
- // パス検索開始
+ // Start of path search
PathFinder pathFinder;
pathFinder.Start(start, idealGoal, PathFinder::SearchDirection::Any);
- // 最も有望な位置を取得します
+ // Get the most promising positions
uint64_t nextKey;
PathFinder::NodeType nextNodeType;
uint32_t nextCost;
@@ -159,7 +159,7 @@ namespace dungeon
PathFinder::SearchDirection nextSearchDirection;
while (pathFinder.Pop(nextKey, nextNodeType, nextCost, nextLocation, nextDirection, nextSearchDirection))
{
- // ゴールに到達?
+ // Reaching the goal?
if (IsReachedGoal(nextLocation, idealGoal.Z, goalCondition))
{
if (nextNodeType == PathFinder::NodeType::Aisle && nextSearchDirection == PathFinder::SearchDirection::Any)
@@ -168,7 +168,7 @@ namespace dungeon
continue;
}
- // 水平方向へ探索
+ // Search horizontally
for (auto i = Direction::Begin(); i != Direction::End(); ++i)
{
if (
@@ -187,10 +187,10 @@ namespace dungeon
}
}
- // 垂直方向へ探索
+ // Vertical search
if (nextNodeType == PathFinder::NodeType::Aisle)
{
- // 上
+ // up
const FIntVector upstairsOpenLocationU = nextLocation + FIntVector(0, 0, 1);
const FIntVector upstairsOpenLocationF = nextLocation + nextDirection.GetVector();
const FIntVector upstairsOpenLocationUF = upstairsOpenLocationF + FIntVector(0, 0, 1);
@@ -208,7 +208,7 @@ namespace dungeon
pathFinder.ReserveOpenNode(upstairsOpenLocationUF, useNode);
}
- // 下
+ // down
const FIntVector downstairsOpenLocationD = nextLocation + FIntVector(0, 0, -1);
const FIntVector downstairsOpenLocationF = nextLocation + nextDirection.GetVector();
const FIntVector downstairsOpenLocationDF = downstairsOpenLocationF + FIntVector(0, 0, -1);
@@ -335,6 +335,17 @@ namespace dungeon
return mGrids.get()[index];
}
+ const Grid& Voxel::Get(const FIntVector& location) const noexcept
+ {
+ return Get(location.X, location.Y, location.Z);
+ }
+
+ const Grid& Voxel::Get(const size_t index) const noexcept
+ {
+ check(index < static_cast