This commit is contained in:
2026-07-04 03:57:58 +07:00
parent ddaf07ef2f
commit a3359cf7e1
38 changed files with 1201 additions and 263 deletions

View File

@@ -12,19 +12,17 @@
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="d308d1cb-09fc-4331-ba20-00f7b43d1576" name="Changes" comment=""> <list default="true" id="d308d1cb-09fc-4331-ba20-00f7b43d1576" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/.idea.BABA_YAGA/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.BABA_YAGA/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/.idea.BABA_YAGA/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.BABA_YAGA/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Prefabs/Environment/Hall/HallDoubleRoom Extend.prefab" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Prefabs/Environment/Hall/HallDoubleRoom Extend.prefab" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Materials/Red.mat" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Materials/Red.mat" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Prefabs/Environment/Hall/MazeRework.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Prefabs/Environment/Hall/MazeRework.asset" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Materials/Separator.mat" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Prefabs/Environment/Hall/Turn.prefab" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Prefabs/Environment/Hall/Turn.prefab" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Materials/Separator.mat.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Materials/Transparency.mat" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Materials/Transparency.mat.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Prefabs/Environment/Hall/MazeRework.asset" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Prefabs/Environment/Hall/MazeRework.asset.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkConfig.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkGenerator.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkGenerator.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkManager.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkManager.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkSpawner.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkSpawner.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkSpawner.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkSpawner.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/Network/BasicSpawner.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/Network/BasicSpawner.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Third Parties/Opsive/UltimateCharacterController/Demo.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Third Parties/Opsive/UltimateCharacterController/Editor.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Third Parties/Opsive/UltimateCharacterController/Materials.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Third Parties/Opsive/UltimateCharacterController/Scripts.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Third Parties/Opsive/UltimateCharacterController/Shaders.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Third Parties/UltimateCharacterController_Documentation.pdf" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Third Parties/UltimateCharacterController_Documentation.pdf.meta" beforeDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -48,6 +46,10 @@
<setting file="file://$PROJECT_DIR$/Library/PackageCache/com.wooshii.foldericons@201a18f355d3/FolderIcons/Editor/FolderIcons.cs" root0="SKIP_HIGHLIGHTING" /> <setting file="file://$PROJECT_DIR$/Library/PackageCache/com.wooshii.foldericons@201a18f355d3/FolderIcons/Editor/FolderIcons.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Library/PackageCache/com.wooshii.foldericons@201a18f355d3/FolderIcons/Editor/FolderIconsEditor.asmdef" root0="SKIP_HIGHLIGHTING" /> <setting file="file://$PROJECT_DIR$/Library/PackageCache/com.wooshii.foldericons@201a18f355d3/FolderIcons/Editor/FolderIconsEditor.asmdef" root0="SKIP_HIGHLIGHTING" />
</component> </component>
<component name="KubernetesApiPersistence"><![CDATA[{}]]></component>
<component name="KubernetesApiProvider"><![CDATA[{
"isMigrated": true
}]]></component>
<component name="McpProjectServerCommands"> <component name="McpProjectServerCommands">
<commands /> <commands />
<urls /> <urls />

View File

@@ -7,22 +7,27 @@ Material:
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_Name: Transparency m_Name: Red 1
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0} m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0 m_ModifiedSerializedProperties: 0
m_ValidKeywords: m_ValidKeywords:
- _ALPHAPREMULTIPLY_ON
- _EMISSION
- _ENVIRONMENTREFLECTIONS_OFF - _ENVIRONMENTREFLECTIONS_OFF
- _SURFACE_TYPE_TRANSPARENT
m_InvalidKeywords: m_InvalidKeywords:
- _GLOSSYREFLECTIONS_OFF - _GLOSSYREFLECTIONS_OFF
m_LightmapFlags: 4 m_LightmapFlags: 1
m_EnableInstancingVariants: 1 m_EnableInstancingVariants: 1
m_DoubleSidedGI: 0 m_DoubleSidedGI: 0
m_CustomRenderQueue: 2000 m_CustomRenderQueue: 3000
stringTagMap: stringTagMap:
RenderType: Opaque RenderType: Transparent
disabledShaderPasses: disabledShaderPasses:
- MOTIONVECTORS - MOTIONVECTORS
- DepthOnly
- SHADOWCASTER
m_LockedProperties: m_LockedProperties:
m_SavedProperties: m_SavedProperties:
serializedVersion: 3 serializedVersion: 3
@@ -97,36 +102,36 @@ Material:
- _Cutoff: 0.5 - _Cutoff: 0.5
- _DetailAlbedoMapScale: 1 - _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1 - _DetailNormalMapScale: 1
- _DstBlend: 0 - _DstBlend: 10
- _DstBlendAlpha: 0 - _DstBlendAlpha: 10
- _EnvironmentReflections: 0 - _EnvironmentReflections: 0
- _GlossMapScale: 0 - _GlossMapScale: 0
- _Glossiness: 0 - _Glossiness: 0
- _GlossyReflections: 0 - _GlossyReflections: 0
- _Metallic: 0 - _Metallic: 1
- _Mode: 0 - _Mode: 0
- _OcclusionStrength: 1 - _OcclusionStrength: 1
- _Parallax: 0.005 - _Parallax: 0.005
- _QueueOffset: 0 - _QueueOffset: 0
- _ReceiveShadows: 1 - _ReceiveShadows: 1
- _Smoothness: 0 - _Smoothness: 0.485
- _SmoothnessTextureChannel: 0 - _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1 - _SpecularHighlights: 1
- _SrcBlend: 1 - _SrcBlend: 1
- _SrcBlendAlpha: 1 - _SrcBlendAlpha: 1
- _Surface: 0 - _Surface: 1
- _UVSec: 0 - _UVSec: 0
- _WorkflowMode: 1 - _WorkflowMode: 1
- _XRMotionVectorsPass: 1 - _XRMotionVectorsPass: 1
- _ZWrite: 1 - _ZWrite: 0
m_Colors: m_Colors:
- _BaseColor: {r: 0.6462264, g: 1, b: 0.90943396, a: 1} - _BaseColor: {r: 1, g: 0, b: 0, a: 0.54509807}
- _Color: {r: 0.6462264, g: 1, b: 0.90943396, a: 1} - _Color: {r: 1, g: 0, b: 0, a: 0.54509807}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1} - _EmissionColor: {r: 0.4433962, g: 0, b: 0.035386458, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: [] m_BuildTextureStacks: []
m_AllowLocking: 1 m_AllowLocking: 1
--- !u!114 &7323331776208790253 --- !u!114 &4579113440628220621
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 11 m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: b0a84576fc378a24cbb3bfc7be45a02e guid: 4e2761c702df38044a3b33cb36bdabf4
NativeFormatImporter: NativeFormatImporter:
externalObjects: {} externalObjects: {}
mainObjectFileID: 2100000 mainObjectFileID: 2100000

View File

@@ -7,21 +7,26 @@ Material:
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_Name: Separator m_Name: Red 2
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0} m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0 m_ModifiedSerializedProperties: 0
m_ValidKeywords: [] m_ValidKeywords:
- _ALPHAPREMULTIPLY_ON
- _EMISSION
- _ENVIRONMENTREFLECTIONS_OFF
- _SURFACE_TYPE_TRANSPARENT
m_InvalidKeywords: m_InvalidKeywords:
- _GLOSSYREFLECTIONS_OFF - _GLOSSYREFLECTIONS_OFF
m_LightmapFlags: 4 m_LightmapFlags: 1
m_EnableInstancingVariants: 1 m_EnableInstancingVariants: 1
m_DoubleSidedGI: 0 m_DoubleSidedGI: 0
m_CustomRenderQueue: 2000 m_CustomRenderQueue: 3000
stringTagMap: stringTagMap:
RenderType: Opaque RenderType: Transparent
disabledShaderPasses: disabledShaderPasses:
- MOTIONVECTORS - MOTIONVECTORS
- DepthOnly
- SHADOWCASTER - SHADOWCASTER
m_LockedProperties: m_LockedProperties:
m_SavedProperties: m_SavedProperties:
@@ -97,36 +102,36 @@ Material:
- _Cutoff: 0.5 - _Cutoff: 0.5
- _DetailAlbedoMapScale: 1 - _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1 - _DetailNormalMapScale: 1
- _DstBlend: 0 - _DstBlend: 10
- _DstBlendAlpha: 0 - _DstBlendAlpha: 10
- _EnvironmentReflections: 0 - _EnvironmentReflections: 0
- _GlossMapScale: 0 - _GlossMapScale: 0
- _Glossiness: 0 - _Glossiness: 0
- _GlossyReflections: 0 - _GlossyReflections: 0
- _Metallic: 0 - _Metallic: 1
- _Mode: 0 - _Mode: 0
- _OcclusionStrength: 1 - _OcclusionStrength: 1
- _Parallax: 0.005 - _Parallax: 0.005
- _QueueOffset: 0 - _QueueOffset: 0
- _ReceiveShadows: 1 - _ReceiveShadows: 1
- _Smoothness: 0 - _Smoothness: 0.485
- _SmoothnessTextureChannel: 0 - _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1 - _SpecularHighlights: 1
- _SrcBlend: 1 - _SrcBlend: 1
- _SrcBlendAlpha: 1 - _SrcBlendAlpha: 1
- _Surface: 0 - _Surface: 1
- _UVSec: 0 - _UVSec: 0
- _WorkflowMode: 1 - _WorkflowMode: 1
- _XRMotionVectorsPass: 1 - _XRMotionVectorsPass: 1
- _ZWrite: 1 - _ZWrite: 0
m_Colors: m_Colors:
- _BaseColor: {r: 1, g: 0, b: 0, a: 0.5686275} - _BaseColor: {r: 1, g: 0, b: 0, a: 0.54509807}
- _Color: {r: 1, g: 0, b: 0, a: 0.5686275} - _Color: {r: 1, g: 0, b: 0, a: 0.54509807}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1} - _EmissionColor: {r: 0.4433962, g: 0, b: 0.035386458, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: [] m_BuildTextureStacks: []
m_AllowLocking: 1 m_AllowLocking: 1
--- !u!114 &9152226916650191239 --- !u!114 &4579113440628220621
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 11 m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: d7e691e02b41b9a47b417cc138d6f1bc guid: c2de57284d214404394d08e4b5f50372
NativeFormatImporter: NativeFormatImporter:
externalObjects: {} externalObjects: {}
mainObjectFileID: 2100000 mainObjectFileID: 2100000

View File

@@ -11,17 +11,23 @@ Material:
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0} m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0 m_ModifiedSerializedProperties: 0
m_ValidKeywords: [] m_ValidKeywords:
- _ALPHAPREMULTIPLY_ON
- _EMISSION
- _ENVIRONMENTREFLECTIONS_OFF
- _SURFACE_TYPE_TRANSPARENT
m_InvalidKeywords: m_InvalidKeywords:
- _GLOSSYREFLECTIONS_OFF - _GLOSSYREFLECTIONS_OFF
m_LightmapFlags: 4 m_LightmapFlags: 1
m_EnableInstancingVariants: 1 m_EnableInstancingVariants: 1
m_DoubleSidedGI: 0 m_DoubleSidedGI: 0
m_CustomRenderQueue: -1 m_CustomRenderQueue: 3000
stringTagMap: stringTagMap:
RenderType: Opaque RenderType: Transparent
disabledShaderPasses: disabledShaderPasses:
- MOTIONVECTORS - MOTIONVECTORS
- DepthOnly
- SHADOWCASTER
m_LockedProperties: m_LockedProperties:
m_SavedProperties: m_SavedProperties:
serializedVersion: 3 serializedVersion: 3
@@ -96,32 +102,32 @@ Material:
- _Cutoff: 0.5 - _Cutoff: 0.5
- _DetailAlbedoMapScale: 1 - _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1 - _DetailNormalMapScale: 1
- _DstBlend: 0 - _DstBlend: 10
- _DstBlendAlpha: 0 - _DstBlendAlpha: 10
- _EnvironmentReflections: 0 - _EnvironmentReflections: 0
- _GlossMapScale: 0 - _GlossMapScale: 0
- _Glossiness: 0 - _Glossiness: 0
- _GlossyReflections: 0 - _GlossyReflections: 0
- _Metallic: 0 - _Metallic: 1
- _Mode: 0 - _Mode: 0
- _OcclusionStrength: 1 - _OcclusionStrength: 1
- _Parallax: 0.005 - _Parallax: 0.005
- _QueueOffset: 0 - _QueueOffset: 0
- _ReceiveShadows: 1 - _ReceiveShadows: 1
- _Smoothness: 0 - _Smoothness: 0.485
- _SmoothnessTextureChannel: 0 - _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1 - _SpecularHighlights: 1
- _SrcBlend: 1 - _SrcBlend: 1
- _SrcBlendAlpha: 1 - _SrcBlendAlpha: 1
- _Surface: 0 - _Surface: 1
- _UVSec: 0 - _UVSec: 0
- _WorkflowMode: 1 - _WorkflowMode: 1
- _XRMotionVectorsPass: 1 - _XRMotionVectorsPass: 1
- _ZWrite: 1 - _ZWrite: 0
m_Colors: m_Colors:
- _BaseColor: {r: 1, g: 0, b: 0, a: 1} - _BaseColor: {r: 1, g: 0, b: 0, a: 0.54509807}
- _Color: {r: 1, g: 0, b: 0, a: 1} - _Color: {r: 1, g: 0, b: 0, a: 0.54509807}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1} - _EmissionColor: {r: 0.4433962, g: 0, b: 0.035386458, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: [] m_BuildTextureStacks: []
m_AllowLocking: 1 m_AllowLocking: 1

View File

@@ -0,0 +1,63 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &8524974212353532561
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 3172752473709046689, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3172752473709046689, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3172752473709046689, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3172752473709046689, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3172752473709046689, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3172752473709046689, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3172752473709046689, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3172752473709046689, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3172752473709046689, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3172752473709046689, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3276807805808399797, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}
propertyPath: 'm_Materials.Array.data[0]'
value:
objectReference: {fileID: 2100000, guid: c2de57284d214404394d08e4b5f50372, type: 2}
- target: {fileID: 7410088413158269499, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}
propertyPath: m_Name
value: MazeVisualize 1 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 17f01b6b44475394da68b1ca1d8d7eb4, type: 3}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c39adeeb3a17d824392cc018d65aedc4
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,63 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &4042319629769208918
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1449831261723959287, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1449831261723959287, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1449831261723959287, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1449831261723959287, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1449831261723959287, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1449831261723959287, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1449831261723959287, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1449831261723959287, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1449831261723959287, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1449831261723959287, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1540436817844937187, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}
propertyPath: 'm_Materials.Array.data[0]'
value:
objectReference: {fileID: 2100000, guid: 4e2761c702df38044a3b33cb36bdabf4, type: 2}
- target: {fileID: 6831072708289238637, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}
propertyPath: m_Name
value: MazeVisualize 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 085ffdfee17437a4f8e0d3c365edcc24, type: 3}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 17f01b6b44475394da68b1ca1d8d7eb4
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,114 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &6831072708289238637
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1449831261723959287}
- component: {fileID: 7162882105187371053}
- component: {fileID: 1540436817844937187}
- component: {fileID: 1186626314013191963}
m_Layer: 0
m_Name: MazeVisualize
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1449831261723959287
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6831072708289238637}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 111.06352, y: 0.99998, z: 75.67667}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &7162882105187371053
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6831072708289238637}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &1540436817844937187
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6831072708289238637}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 9193f4635bbf98d46be9a6357461aa10, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!65 &1186626314013191963
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6831072708289238637}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 0
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 085ffdfee17437a4f8e0d3c365edcc24
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -12,13 +12,14 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 30892b1102feb6841a9288ddb11ef50d, type: 3} m_Script: {fileID: 11500000, guid: 30892b1102feb6841a9288ddb11ef50d, type: 3}
m_Name: MazeRework m_Name: MazeRework
m_EditorClassIdentifier: Assembly-CSharp::Baba_yaga.GameSetup.MazeRework.MazeReworkConfig m_EditorClassIdentifier: Assembly-CSharp::Baba_yaga.GameSetup.MazeRework.MazeReworkConfig
width: 15 algorithm: 3
depth: 15 width: 21
depth: 21
useRandomSeed: 1 useRandomSeed: 1
seed: 1337 seed: 1337
startLocation: {x: 1, y: 1} startLocation: {x: 1, y: 1}
generateRooms: 0 generateRooms: 0
roomCount: 207 roomCount: 378
minRoomSize: {x: 3, y: 3} minRoomSize: {x: 3, y: 3}
maxRoomSize: {x: 5, y: 5} maxRoomSize: {x: 5, y: 5}
extraRoomDoorChance: 0.3 extraRoomDoorChance: 0.3

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1207eeec52bcfcf4a9a97e054680d844
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
using System.Collections.Generic;
using UnityEngine;
namespace Baba_yaga.GameSetup.MazeRework.Algorithms
{
public class DFSIterative : IMazeReworkAlgorithm
{
public void Carve(
MazeReworkCellType[,] grid,
bool[,] visited,
int startX, int startZ,
int width, int depth,
System.Random rng,
System.Action<int, int, MazeReworkCellType, Animation.MazeCellHighlight> onCellChanged = null)
{
Stack<Vector2Int> stack = new Stack<Vector2Int>();
stack.Push(new Vector2Int(startX, startZ));
onCellChanged?.Invoke(startX, startZ, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
int[] dx = { 2, -2, 0, 0 };
int[] dz = { 0, 0, 2, -2 };
while (stack.Count > 0)
{
Vector2Int current = stack.Peek();
List<int> candidates = new List<int>(4);
for (int i = 0; i < 4; i++)
{
int nx = current.x + dx[i];
int nz = current.y + dz[i];
if (nx > 0 && nx < width - 1 && nz > 0 && nz < depth - 1 && !visited[nx, nz])
candidates.Add(i);
}
if (candidates.Count > 0)
{
int pick = candidates[rng.Next(candidates.Count)];
int nx2 = current.x + dx[pick];
int nz2 = current.y + dz[pick];
int wx = current.x + dx[pick] / 2;
int wz = current.y + dz[pick] / 2;
grid[wx, wz] = MazeReworkCellType.Corridor;
grid[nx2, nz2] = MazeReworkCellType.Corridor;
visited[wx, wz] = true;
visited[nx2, nz2] = true;
// Move head off current cell
onCellChanged?.Invoke(current.x, current.y, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
// Show breaking intermediate wall with head
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
// Move head to new cell
onCellChanged?.Invoke(nx2, nz2, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
stack.Push(new Vector2Int(nx2, nz2));
}
else
{
stack.Pop();
// Clear head from popped cell
onCellChanged?.Invoke(current.x, current.y, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
// Restore head to new top of stack
if (stack.Count > 0)
{
var nextCurrent = stack.Peek();
onCellChanged?.Invoke(nextCurrent.x, nextCurrent.y, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
}
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: cdda5d3deb881154481ad5f60c4bdc0a

View File

@@ -0,0 +1,64 @@
namespace Baba_yaga.GameSetup.MazeRework.Algorithms
{
public class DFSRecursive : IMazeReworkAlgorithm
{
public void Carve(
MazeReworkCellType[,] grid,
bool[,] visited,
int startX, int startZ,
int width, int depth,
System.Random rng,
System.Action<int, int, MazeReworkCellType, Animation.MazeCellHighlight> onCellChanged = null)
{
CarveFrom(startX, startZ, grid, visited, rng, width, depth, onCellChanged);
// Clear final head position when completely done
onCellChanged?.Invoke(startX, startZ, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
}
private void CarveFrom(int cx, int cz, MazeReworkCellType[,] grid, bool[,] visited,
System.Random rng, int width, int depth,
System.Action<int, int, MazeReworkCellType, Animation.MazeCellHighlight> onCellChanged)
{
onCellChanged?.Invoke(cx, cz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
int[] dx = { 2, -2, 0, 0 };
int[] dz = { 0, 0, 2, -2 };
int[] order = { 0, 1, 2, 3 };
for (int i = 3; i > 0; i--)
{
int j = rng.Next(i + 1);
int tmp = order[i]; order[i] = order[j]; order[j] = tmp;
}
for (int i = 0; i < 4; i++)
{
int nx = cx + dx[order[i]];
int nz = cz + dz[order[i]];
int wx = cx + dx[order[i]] / 2;
int wz = cz + dz[order[i]] / 2;
if (nx > 0 && nx < width - 1 && nz > 0 && nz < depth - 1 && !visited[nx, nz])
{
grid[wx, wz] = MazeReworkCellType.Corridor;
grid[nx, nz] = MazeReworkCellType.Corridor;
visited[wx, wz] = true;
visited[nx, nz] = true;
// Move head off current cell
onCellChanged?.Invoke(cx, cz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
// Show intermediate wall breaking with head
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
CarveFrom(nx, nz, grid, visited, rng, width, depth, onCellChanged);
// Clear head from the child cell and restore it here
onCellChanged?.Invoke(nx, nz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
onCellChanged?.Invoke(cx, cz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f20ddc35c8bf6604b84a0102bdad1821

View File

@@ -0,0 +1,36 @@
namespace Baba_yaga.GameSetup.MazeRework.Algorithms
{
/// <summary>
/// Contract that all maze carving algorithms must fulfill.
/// The algorithm is only responsible for carving corridors.
/// Rooms, loops, Start/End placement, and connectivity repair are handled externally.
/// </summary>
public interface IMazeReworkAlgorithm
{
/// <summary>
/// Carves corridors into the grid starting from (startX, startZ).
/// All cells begin as Wall. The algorithm sets reachable cells to Corridor.
/// </summary>
/// <param name="grid">The 2D cell array to carve into.</param>
/// <param name="visited">Shared visited map. Pre-marked cells (e.g. rooms) are already true.</param>
/// <param name="startX">X coordinate of the first cell to carve (must be odd).</param>
/// <param name="startZ">Z coordinate of the first cell to carve (must be odd).</param>
/// <param name="width">Grid width.</param>
/// <param name="depth">Grid depth.</param>
/// <param name="rng">Seeded random number generator.</param>
/// <param name="onCellChanged">
/// Optional callback fired every time a cell is carved or evaluated.
/// Signature: (x, z, newType, highlight). Pass null in non-animated mode.
/// </param>
void Carve(
MazeReworkCellType[,] grid,
bool[,] visited,
int startX,
int startZ,
int width,
int depth,
System.Random rng,
System.Action<int, int, MazeReworkCellType, Animation.MazeCellHighlight> onCellChanged = null
);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f8ba54b75b8f8344aa7ccb03b8779c03

View File

@@ -0,0 +1,82 @@
using System.Collections.Generic;
using UnityEngine;
namespace Baba_yaga.GameSetup.MazeRework.Algorithms
{
public class Kruskals : IMazeReworkAlgorithm
{
public void Carve(
MazeReworkCellType[,] grid,
bool[,] visited,
int startX, int startZ,
int width, int depth,
System.Random rng,
System.Action<int, int, MazeReworkCellType, Animation.MazeCellHighlight> onCellChanged = null)
{
// Assign unique ID to every odd-coordinate (node) cell
int[,] cellId = new int[width, depth];
int idCounter = 0;
for (int z = 1; z < depth - 1; z += 2)
for (int x = 1; x < width - 1; x += 2)
cellId[x, z] = idCounter++;
UnionFind uf = new UnionFind(idCounter);
// Collect all internal walls
List<Vector2Int> walls = new List<Vector2Int>();
for (int z = 1; z < depth - 1; z++)
for (int x = 1; x < width - 1; x++)
if ((x % 2 == 0 && z % 2 == 1) || (x % 2 == 1 && z % 2 == 0))
walls.Add(new Vector2Int(x, z));
// Shuffle walls
for (int i = walls.Count - 1; i > 0; i--)
{
int j = rng.Next(i + 1);
var tmp = walls[i]; walls[i] = walls[j]; walls[j] = tmp;
}
foreach (var wall in walls)
{
int wx = wall.x, wz = wall.y;
int ax, az, bx, bz;
if (wx % 2 == 0) { ax = wx - 1; az = wz; bx = wx + 1; bz = wz; }
else { ax = wx; az = wz - 1; bx = wx; bz = wz + 1; }
if (ax < 1 || ax >= width - 1 || az < 1 || az >= depth - 1) continue;
if (bx < 1 || bx >= width - 1 || bz < 1 || bz >= depth - 1) continue;
// Show evaluating highlight
onCellChanged?.Invoke(wx, wz, grid[wx, wz], Animation.MazeCellHighlight.Evaluating);
if (uf.Find(cellId[ax, az]) != uf.Find(cellId[bx, bz]))
{
grid[wx, wz] = MazeReworkCellType.Corridor;
grid[ax, az] = MazeReworkCellType.Corridor;
grid[bx, bz] = MazeReworkCellType.Corridor;
visited[wx, wz] = visited[ax, az] = visited[bx, bz] = true;
onCellChanged?.Invoke(ax, az, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
onCellChanged?.Invoke(bx, bz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
uf.Union(cellId[ax, az], cellId[bx, bz]);
}
else
{
// Clear evaluate highlight
onCellChanged?.Invoke(wx, wz, grid[wx, wz], Animation.MazeCellHighlight.None);
}
}
}
private class UnionFind
{
private readonly int[] _parent, _rank;
public UnionFind(int count) { _parent = new int[count]; _rank = new int[count]; for (int i = 0; i < count; i++) _parent[i] = i; }
public int Find(int x) { if (_parent[x] != x) _parent[x] = Find(_parent[x]); return _parent[x]; }
public void Union(int a, int b) { int ra = Find(a), rb = Find(b); if (ra == rb) return; if (_rank[ra] < _rank[rb]) _parent[ra] = rb; else if (_rank[ra] > _rank[rb]) _parent[rb] = ra; else { _parent[rb] = ra; _rank[ra]++; } }
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7574ba4325993ac46a12a7861b70031f

View File

@@ -0,0 +1,73 @@
using System.Collections.Generic;
using UnityEngine;
namespace Baba_yaga.GameSetup.MazeRework.Algorithms
{
public class Prims : IMazeReworkAlgorithm
{
public void Carve(
MazeReworkCellType[,] grid,
bool[,] visited,
int startX, int startZ,
int width, int depth,
System.Random rng,
System.Action<int, int, MazeReworkCellType, Animation.MazeCellHighlight> onCellChanged = null)
{
grid[startX, startZ] = MazeReworkCellType.Corridor;
visited[startX, startZ] = true;
onCellChanged?.Invoke(startX, startZ, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
List<(int nx, int nz, int wx, int wz)> frontier = new List<(int, int, int, int)>();
AddFrontier(startX, startZ, frontier, visited, width, depth, grid, onCellChanged);
while (frontier.Count > 0)
{
int pick = rng.Next(frontier.Count);
var (nx, nz, wx, wz) = frontier[pick];
// Swap-remove O(1)
frontier[pick] = frontier[frontier.Count - 1];
frontier.RemoveAt(frontier.Count - 1);
if (visited[nx, nz])
{
// Clear the frontier highlight if this cell was already visited by another path
onCellChanged?.Invoke(nx, nz, grid[nx, nz], Animation.MazeCellHighlight.None);
continue;
}
grid[wx, wz] = MazeReworkCellType.Corridor;
grid[nx, nz] = MazeReworkCellType.Corridor;
visited[wx, wz] = true;
visited[nx, nz] = true;
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
onCellChanged?.Invoke(nx, nz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
onCellChanged?.Invoke(nx, nz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
AddFrontier(nx, nz, frontier, visited, width, depth, grid, onCellChanged);
}
}
private void AddFrontier(int cx, int cz,
List<(int nx, int nz, int wx, int wz)> frontier,
bool[,] visited, int width, int depth, MazeReworkCellType[,] grid,
System.Action<int, int, MazeReworkCellType, Animation.MazeCellHighlight> onCellChanged)
{
int[] dx = { 2, -2, 0, 0 };
int[] dz = { 0, 0, 2, -2 };
for (int i = 0; i < 4; i++)
{
int nx = cx + dx[i], nz = cz + dz[i];
int wx = cx + dx[i] / 2, wz = cz + dz[i] / 2;
if (nx > 0 && nx < width - 1 && nz > 0 && nz < depth - 1 && !visited[nx, nz])
{
frontier.Add((nx, nz, wx, wz));
onCellChanged?.Invoke(nx, nz, grid[nx, nz], Animation.MazeCellHighlight.Frontier);
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 321151d3d7c655047b73b6bd981800e6

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 92ea88f252068ee47ad6145db600314b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
namespace Baba_yaga.GameSetup.MazeRework.Animation
{
/// <summary>
/// Labels each recorded cell change with which generation phase produced it.
/// Used to color-code or group changes during animated playback.
/// </summary>
public enum MazeAnimationPhase
{
RoomPlacement, // Rooms being stamped onto the grid
Carving, // Algorithm carving corridors
Connecting, // Hunt-and-Kill fixing isolated pockets
Loops, // Extra walls removed to create shortcuts
StartEnd // Start and End cells placed
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 45bda90d4b2d42245a8d9f06543053ee

View File

@@ -0,0 +1,123 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Baba_yaga.GameSetup.MazeRework.Animation
{
public class MazeAnimator : MonoBehaviour
{
[Header("Animation Settings")]
[Tooltip("How many cell changes to process in a single frame. Higher = faster generation.")]
[Min(1)]
public int cellsPerFrame = 5;
[Tooltip("Extra delay (in seconds) between major generation phases (like switching from Rooms to Carving).")]
public float delayBetweenPhases = 0.5f;
private Coroutine _animationRoutine;
public void AnimateGeneration(
List<MazeCellChange> history,
MazeReworkCellType[,] grid,
MazeReworkSpawner spawner,
float yOffset,
Transform container,
System.Action onComplete = null)
{
if (_animationRoutine != null)
StopCoroutine(_animationRoutine);
_animationRoutine = StartCoroutine(AnimateRoutine(history, grid, spawner, yOffset, container, onComplete));
}
public void StopAnimation()
{
if (_animationRoutine != null)
{
StopCoroutine(_animationRoutine);
_animationRoutine = null;
}
}
private IEnumerator AnimateRoutine(
List<MazeCellChange> history,
MazeReworkCellType[,] finalGrid,
MazeReworkSpawner spawner,
float yOffset,
Transform container,
System.Action onComplete)
{
int width = finalGrid.GetLength(0);
int depth = finalGrid.GetLength(1);
// Create a working grid starting fully as walls (like the generator does)
MazeReworkCellType[,] workingGrid = new MazeReworkCellType[width, depth];
MazeCellHighlight[,] workingHighlights = new MazeCellHighlight[width, depth];
for (int z = 0; z < depth; z++)
{
for (int x = 0; x < width; x++)
{
workingGrid[x, z] = MazeReworkCellType.Wall;
workingHighlights[x, z] = MazeCellHighlight.None;
}
}
spawner.Clear();
MazeAnimationPhase currentPhase = MazeAnimationPhase.RoomPlacement;
int processedThisFrame = 0;
foreach (var change in history)
{
if (change.Phase != currentPhase)
{
currentPhase = change.Phase;
if (delayBetweenPhases > 0f)
{
yield return new WaitForSeconds(delayBetweenPhases);
processedThisFrame = 0;
}
}
workingGrid[change.X, change.Z] = change.Type;
workingHighlights[change.X, change.Z] = change.Highlight;
// Refresh the cell and its neighbors in the spawner
spawner.RefreshCell(workingGrid, workingHighlights, change.X, change.Z, yOffset, container);
processedThisFrame++;
if (processedThisFrame >= cellsPerFrame)
{
yield return null; // Wait for next frame
processedThisFrame = 0;
}
}
// Wait a moment at the end before finalizing
if (delayBetweenPhases > 0f)
{
yield return new WaitForSeconds(delayBetweenPhases);
}
// One final sync with finalGrid just to be absolutely safe
for (int z = 0; z < depth; z++)
{
for (int x = 0; x < width; x++)
{
bool gridChanged = workingGrid[x, z] != finalGrid[x, z];
bool highlightChanged = workingHighlights[x, z] != MazeCellHighlight.None;
if (gridChanged || highlightChanged)
{
workingGrid[x, z] = finalGrid[x, z];
workingHighlights[x, z] = MazeCellHighlight.None;
spawner.RefreshCell(workingGrid, workingHighlights, x, z, yOffset, container);
}
}
}
_animationRoutine = null;
onComplete?.Invoke();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 209db07e0fcae2e4e9e8b9e2fb822e31

View File

@@ -0,0 +1,24 @@
namespace Baba_yaga.GameSetup.MazeRework.Animation
{
/// <summary>
/// A single recorded cell change captured during maze generation.
/// The animator drains this list to replay generation visually.
/// </summary>
public readonly struct MazeCellChange
{
public readonly int X;
public readonly int Z;
public readonly MazeReworkCellType Type;
public readonly MazeCellHighlight Highlight;
public readonly MazeAnimationPhase Phase;
public MazeCellChange(int x, int z, MazeReworkCellType type, MazeCellHighlight highlight, MazeAnimationPhase phase)
{
X = x;
Z = z;
Type = type;
Highlight = highlight;
Phase = phase;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6f6a93f9b414a3f4a83c74ee28fb441b

View File

@@ -0,0 +1,10 @@
namespace Baba_yaga.GameSetup.MazeRework.Animation
{
public enum MazeCellHighlight
{
None,
SearchHead, // Current cell being evaluated (DFS, Prim's)
Frontier, // Known candidate cells (Prim's)
Evaluating // Walls currently being considered (Kruskal's)
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6bff934558bb70343ad947b2c9e4da45

View File

@@ -1,13 +1,29 @@
using UnityEngine; using UnityEngine;
using Baba_yaga.GameSetup.MazeRework.Algorithms;
namespace Baba_yaga.GameSetup.MazeRework namespace Baba_yaga.GameSetup.MazeRework
{ {
/// <summary>
/// Defines which carving algorithm the generator will use.
/// </summary>
public enum MazeAlgorithmType
{
DFSRecursive, // Long winding corridors. May stack overflow on huge grids.
DFSIterative, // Same result as recursive but safe for large grids.
Kruskals, // Short branchy corridors, open feel, no directional bias.
Prims, // Organic cave-like layout, radiates outward from start.
}
/// <summary> /// <summary>
/// Configuration asset containing parameters for the reworked maze generation. /// Configuration asset containing parameters for the reworked maze generation.
/// </summary> /// </summary>
[CreateAssetMenu(fileName = "MazeReworkConfig", menuName = "BABA_YAGA/GameSetup/MazeRework")] [CreateAssetMenu(fileName = "MazeReworkConfig", menuName = "BABA_YAGA/MazeRework/Config")]
public class MazeReworkConfig : ScriptableObject public class MazeReworkConfig : ScriptableObject
{ {
[Header("Algorithm")]
[Tooltip("Which carving algorithm to use for generating the maze corridors.")]
public MazeAlgorithmType algorithm = MazeAlgorithmType.DFSRecursive;
[Header("Grid Dimensions")] [Header("Grid Dimensions")]
[Tooltip("Width of the maze grid. Best if odd to align with wall-corridor-wall patterning.")] [Tooltip("Width of the maze grid. Best if odd to align with wall-corridor-wall patterning.")]
[Min(5)] [Min(5)]

View File

@@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using Baba_yaga.GameSetup.MazeRework.Algorithms;
using Baba_yaga.GameSetup.MazeRework.Animation;
namespace Baba_yaga.GameSetup.MazeRework namespace Baba_yaga.GameSetup.MazeRework
{ {
@@ -97,10 +99,11 @@ namespace Baba_yaga.GameSetup.MazeRework
int startZ = _config.startLocation.y; int startZ = _config.startLocation.y;
EnsureValidOddCoordinates(width, depth, ref startX, ref startZ); EnsureValidOddCoordinates(width, depth, ref startX, ref startZ);
// 5. Carve Corridors recursively using Step-by-2 Recursive Backtracking // 5. Carve Corridors using the selected algorithm
visited[startX, startZ] = true; visited[startX, startZ] = true;
grid[startX, startZ] = MazeReworkCellType.Corridor; grid[startX, startZ] = MazeReworkCellType.Corridor;
CarveFrom(startX, startZ, grid, visited, rooms, rng, width, depth); IMazeReworkAlgorithm algorithm = GetAlgorithm();
algorithm.Carve(grid, visited, startX, startZ, width, depth, rng);
// 6. Hunt & Kill scan to connect isolated rooms/corridors // 6. Hunt & Kill scan to connect isolated rooms/corridors
EnsureAllConnected(grid, visited, rooms, rng, width, depth); EnsureAllConnected(grid, visited, rooms, rng, width, depth);
@@ -114,9 +117,86 @@ namespace Baba_yaga.GameSetup.MazeRework
return grid; return grid;
} }
#region Animated Generation
/// <summary>
/// Generates the maze and records every cell change with its phase label.
/// Returns the final grid AND the ordered history list for the animator to replay.
/// </summary>
public (MazeReworkCellType[,] grid, List<MazeCellChange> history) GenerateAnimated()
{
if (_config == null) return (null, null);
int seed = _config.useRandomSeed
? System.DateTime.Now.Millisecond + System.Threading.Thread.CurrentThread.ManagedThreadId
: _config.seed;
return GenerateAnimated(seed);
}
public (MazeReworkCellType[,] grid, List<MazeCellChange> history) GenerateAnimated(int seed)
{
if (_config == null) return (null, null);
int width = _config.width;
int depth = _config.depth;
var grid = new MazeReworkCellType[width, depth];
var history = new List<MazeCellChange>(width * depth * 2);
// Helper: record a cell change tagged with a phase
var currentPhase = MazeAnimationPhase.RoomPlacement;
Action<int, int, MazeReworkCellType, MazeCellHighlight> record =
(x, z, t, h) => history.Add(new MazeCellChange(x, z, t, h, currentPhase));
Action<int, int, MazeReworkCellType> recordNoHighlight =
(x, z, t) => record(x, z, t, MazeCellHighlight.None);
// 1. Initialize all cells as Wall (no recording — start state is all-Wall)
for (int z = 0; z < depth; z++)
for (int x = 0; x < width; x++)
grid[x, z] = MazeReworkCellType.Wall;
System.Random rng = new System.Random(seed);
// 2. Generate Rooms — record each Room cell
currentPhase = MazeAnimationPhase.RoomPlacement;
List<Room> rooms = GenerateRooms(grid, width, depth, rng, recordNoHighlight);
// 3. Setup visited map
bool[,] visited = new bool[width, depth];
InitializeVisitedMap(grid, visited, rooms, width, depth);
// 4. Starting coordinates
int startX = _config.startLocation.x;
int startZ = _config.startLocation.y;
EnsureValidOddCoordinates(width, depth, ref startX, ref startZ);
// 5. Carve Corridors — algorithm fires back through the record callback
currentPhase = MazeAnimationPhase.Carving;
visited[startX, startZ] = true;
grid[startX, startZ] = MazeReworkCellType.Corridor;
record(startX, startZ, MazeReworkCellType.Corridor, MazeCellHighlight.None); // DFS will highlight itself
GetAlgorithm().Carve(grid, visited, startX, startZ, width, depth, rng, record);
// 6. Hunt & Kill connecting pass
currentPhase = MazeAnimationPhase.Connecting;
EnsureAllConnected(grid, visited, rooms, rng, width, depth, recordNoHighlight);
// 7. Loop carving
currentPhase = MazeAnimationPhase.Loops;
CarveLoops(grid, rng, width, depth, recordNoHighlight);
// 8. Start & End placement
currentPhase = MazeAnimationPhase.StartEnd;
PlaceStartAndEnd(grid, rooms, width, depth, recordNoHighlight);
return (grid, history);
}
#endregion
#region Internal Generation Logic #region Internal Generation Logic
private List<Room> GenerateRooms(MazeReworkCellType[,] grid, int width, int depth, System.Random rng) private List<Room> GenerateRooms(MazeReworkCellType[,] grid, int width, int depth, System.Random rng,
Action<int, int, MazeReworkCellType> onCellChanged = null)
{ {
List<Room> rooms = new List<Room>(); List<Room> rooms = new List<Room>();
if (!_config.generateRooms) return rooms; if (!_config.generateRooms) return rooms;
@@ -144,22 +224,18 @@ namespace Baba_yaga.GameSetup.MazeRework
bool overlaps = false; bool overlaps = false;
foreach (var r in rooms) foreach (var r in rooms)
{ {
if (newRoom.Overlaps(r, 1)) if (newRoom.Overlaps(r, 1)) { overlaps = true; break; }
{
overlaps = true;
break;
}
} }
if (!overlaps) if (!overlaps)
{ {
rooms.Add(newRoom); rooms.Add(newRoom);
// Carve room cells
for (int z = rz; z < rz + rh; z++) for (int z = rz; z < rz + rh; z++)
{ {
for (int x = rx; x < rx + rw; x++) for (int x = rx; x < rx + rw; x++)
{ {
grid[x, z] = MazeReworkCellType.Room; grid[x, z] = MazeReworkCellType.Room;
onCellChanged?.Invoke(x, z, MazeReworkCellType.Room);
} }
} }
} }
@@ -182,7 +258,26 @@ namespace Baba_yaga.GameSetup.MazeRework
} }
} }
private void CarveFrom(int cx, int cz, MazeReworkCellType[,] grid, bool[,] visited, List<Room> rooms, System.Random rng, int width, int depth) /// <summary>
/// Factory that returns the correct algorithm based on config selection.
/// </summary>
private IMazeReworkAlgorithm GetAlgorithm()
{
return _config.algorithm switch
{
MazeAlgorithmType.DFSRecursive => new DFSRecursive(),
MazeAlgorithmType.DFSIterative => new DFSIterative(),
MazeAlgorithmType.Kruskals => new Kruskals(),
MazeAlgorithmType.Prims => new Prims(),
_ => new DFSIterative()
};
}
/// <summary>
/// After corridor carving, connects room cells to the corridor network
/// by carving doorway walls between corridors and rooms.
/// </summary>
private void ConnectRoomsFrom(int cx, int cz, MazeReworkCellType[,] grid, bool[,] visited, List<Room> rooms, System.Random rng, int width, int depth)
{ {
Vector2Int[] dirs = new Vector2Int[4] Vector2Int[] dirs = new Vector2Int[4]
{ {
@@ -215,7 +310,7 @@ namespace Baba_yaga.GameSetup.MazeRework
grid[nx, nz] = MazeReworkCellType.Corridor; grid[nx, nz] = MazeReworkCellType.Corridor;
visited[wx, wz] = true; visited[wx, wz] = true;
visited[nx, nz] = true; visited[nx, nz] = true;
CarveFrom(nx, nz, grid, visited, rooms, rng, width, depth); ConnectRoomsFrom(nx, nz, grid, visited, rooms, rng, width, depth);
} }
else if (grid[nx, nz] == MazeReworkCellType.Room) else if (grid[nx, nz] == MazeReworkCellType.Room)
{ {
@@ -244,7 +339,9 @@ namespace Baba_yaga.GameSetup.MazeRework
} }
} }
private void EnsureAllConnected(MazeReworkCellType[,] grid, bool[,] visited, List<Room> rooms, System.Random rng, int width, int depth) private void EnsureAllConnected(MazeReworkCellType[,] grid, bool[,] visited, List<Room> rooms,
System.Random rng, int width, int depth,
Action<int, int, MazeReworkCellType> onCellChanged = null)
{ {
for (int z = 1; z < depth - 1; z += 2) for (int z = 1; z < depth - 1; z += 2)
{ {
@@ -254,50 +351,30 @@ namespace Baba_yaga.GameSetup.MazeRework
{ {
Vector2Int[] dirs = new Vector2Int[4] Vector2Int[] dirs = new Vector2Int[4]
{ {
new Vector2Int(2, 0), new Vector2Int(2, 0), new Vector2Int(-2, 0),
new Vector2Int(-2, 0), new Vector2Int(0, 2), new Vector2Int(0, -2)
new Vector2Int(0, 2),
new Vector2Int(0, -2)
}; };
for (int i = 3; i > 0; i--) { int j = rng.Next(i + 1); var t = dirs[i]; dirs[i] = dirs[j]; dirs[j] = t; }
for (int i = 3; i > 0; i--)
{
int j = rng.Next(i + 1);
var temp = dirs[i];
dirs[i] = dirs[j];
dirs[j] = temp;
}
bool connected = false; bool connected = false;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
int nx = x + dirs[i].x; int nx = x + dirs[i].x, nz = z + dirs[i].y;
int nz = z + dirs[i].y; int wx = x + dirs[i].x / 2, wz = z + dirs[i].y / 2;
int wx = x + dirs[i].x / 2; if (nx > 0 && nx < width - 1 && nz > 0 && nz < depth - 1 && visited[nx, nz])
int wz = z + dirs[i].y / 2;
if (nx > 0 && nx < width - 1 && nz > 0 && nz < depth - 1)
{ {
if (visited[nx, nz]) grid[wx, wz] = MazeReworkCellType.Corridor;
{ grid[x, z] = MazeReworkCellType.Corridor;
grid[wx, wz] = MazeReworkCellType.Corridor; visited[wx, wz] = visited[x, z] = true;
grid[x, z] = MazeReworkCellType.Corridor; onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Corridor);
visited[wx, wz] = true; onCellChanged?.Invoke(x, z, MazeReworkCellType.Corridor);
visited[x, z] = true; connected = true;
connected = true; break;
break;
}
} }
} }
if (connected) ConnectRoomsFrom(x, z, grid, visited, rooms, rng, width, depth);
{ _ = connected; // suppress unused warning
CarveFrom(x, z, grid, visited, rooms, rng, width, depth);
}
else
{
CarveFrom(x, z, grid, visited, rooms, rng, width, depth);
}
} }
} }
} }
@@ -307,74 +384,31 @@ namespace Baba_yaga.GameSetup.MazeRework
var room = rooms[i]; var room = rooms[i];
if (!room.isConnected) if (!room.isConnected)
{ {
ForceConnectRoom(grid, room, visited, rng, width, depth); ForceConnectRoom(grid, room, visited, rng, width, depth, onCellChanged);
room.isConnected = true; room.isConnected = true;
rooms[i] = room; rooms[i] = room;
} }
} }
} }
private void ForceConnectRoom(MazeReworkCellType[,] grid, Room room, bool[,] visited, System.Random rng, int width, int depth) private void ForceConnectRoom(MazeReworkCellType[,] grid, Room room, bool[,] visited,
System.Random rng, int width, int depth,
Action<int, int, MazeReworkCellType> onCellChanged = null)
{ {
int[] sides = new int[] { 0, 1, 2, 3 }; int[] sides = new int[] { 0, 1, 2, 3 };
for (int i = 3; i > 0; i--) for (int i = 3; i > 0; i--) { int j = rng.Next(i + 1); int t = sides[i]; sides[i] = sides[j]; sides[j] = t; }
{
int j = rng.Next(i + 1);
int temp = sides[i];
sides[i] = sides[j];
sides[j] = temp;
}
foreach (int side in sides) foreach (int side in sides)
{ {
if (side == 0) if (side == 0) { int z = room.z + room.depth - 1; if (z + 2 < depth - 1) { int x = room.x + 2 * rng.Next(0, room.width / 2); grid[x, z + 1] = MazeReworkCellType.Corridor; visited[x, z + 1] = true; onCellChanged?.Invoke(x, z + 1, MazeReworkCellType.Corridor); return; } }
{ else if (side == 1) { int z = room.z; if (z - 2 > 0) { int x = room.x + 2 * rng.Next(0, room.width / 2); grid[x, z - 1] = MazeReworkCellType.Corridor; visited[x, z - 1] = true; onCellChanged?.Invoke(x, z - 1, MazeReworkCellType.Corridor); return; } }
int z = room.z + room.depth - 1; else if (side == 2) { int x = room.x; if (x - 2 > 0) { int z = room.z + 2 * rng.Next(0, room.depth / 2); grid[x - 1, z] = MazeReworkCellType.Corridor; visited[x - 1, z] = true; onCellChanged?.Invoke(x - 1, z, MazeReworkCellType.Corridor); return; } }
if (z + 2 < depth - 1) else if (side == 3) { int x = room.x + room.width - 1; if (x + 2 < width - 1) { int z = room.z + 2 * rng.Next(0, room.depth / 2); grid[x + 1, z] = MazeReworkCellType.Corridor; visited[x + 1, z] = true; onCellChanged?.Invoke(x + 1, z, MazeReworkCellType.Corridor); return; } }
{
int x = room.x + 2 * rng.Next(0, room.width / 2);
grid[x, z + 1] = MazeReworkCellType.Corridor;
visited[x, z + 1] = true;
return;
}
}
else if (side == 1)
{
int z = room.z;
if (z - 2 > 0)
{
int x = room.x + 2 * rng.Next(0, room.width / 2);
grid[x, z - 1] = MazeReworkCellType.Corridor;
visited[x, z - 1] = true;
return;
}
}
else if (side == 2)
{
int x = room.x;
if (x - 2 > 0)
{
int z = room.z + 2 * rng.Next(0, room.depth / 2);
grid[x - 1, z] = MazeReworkCellType.Corridor;
visited[x - 1, z] = true;
return;
}
}
else if (side == 3)
{
int x = room.x + room.width - 1;
if (x + 2 < width - 1)
{
int z = room.z + 2 * rng.Next(0, room.depth / 2);
grid[x + 1, z] = MazeReworkCellType.Corridor;
visited[x + 1, z] = true;
return;
}
}
} }
} }
private void CarveLoops(MazeReworkCellType[,] grid, System.Random rng, int width, int depth) private void CarveLoops(MazeReworkCellType[,] grid, System.Random rng, int width, int depth,
Action<int, int, MazeReworkCellType> onCellChanged = null)
{ {
if (_config.loopChance <= 0f) return; if (_config.loopChance <= 0f) return;
@@ -383,90 +417,66 @@ namespace Baba_yaga.GameSetup.MazeRework
for (int x = 1; x < width - 1; x++) for (int x = 1; x < width - 1; x++)
{ {
bool isHorizontalWall = (x % 2 == 0 && z % 2 != 0); bool isHorizontalWall = (x % 2 == 0 && z % 2 != 0);
bool isVerticalWall = (x % 2 != 0 && z % 2 == 0); bool isVerticalWall = (x % 2 != 0 && z % 2 == 0);
if (!isHorizontalWall && !isVerticalWall) continue; if (!isHorizontalWall && !isVerticalWall) continue;
if (grid[x, z] == MazeReworkCellType.Wall) if (grid[x, z] == MazeReworkCellType.Wall)
{ {
if (isHorizontalWall) bool carve = isHorizontalWall
? IsPathCell(grid[x - 1, z]) && IsPathCell(grid[x + 1, z])
: IsPathCell(grid[x, z - 1]) && IsPathCell(grid[x, z + 1]);
if (carve && rng.NextDouble() < _config.loopChance)
{ {
if (IsPathCell(grid[x - 1, z]) && IsPathCell(grid[x + 1, z])) grid[x, z] = MazeReworkCellType.Corridor;
{ onCellChanged?.Invoke(x, z, MazeReworkCellType.Corridor);
if (rng.NextDouble() < _config.loopChance)
{
grid[x, z] = MazeReworkCellType.Corridor;
}
}
}
else
{
if (IsPathCell(grid[x, z - 1]) && IsPathCell(grid[x, z + 1]))
{
if (rng.NextDouble() < _config.loopChance)
{
grid[x, z] = MazeReworkCellType.Corridor;
}
}
} }
} }
} }
} }
} }
private void PlaceStartAndEnd(MazeReworkCellType[,] grid, List<Room> rooms, int width, int depth) private void PlaceStartAndEnd(MazeReworkCellType[,] grid, List<Room> rooms, int width, int depth,
Action<int, int, MazeReworkCellType> onCellChanged = null)
{ {
if (rooms != null && rooms.Count > 0) if (rooms != null && rooms.Count > 0)
{ {
var startRoom = rooms[0]; var startRoom = rooms[0];
var startPt = startRoom.GetCenter(); var startPt = startRoom.GetCenter();
grid[startPt.x, startPt.y] = MazeReworkCellType.Start; grid[startPt.x, startPt.y] = MazeReworkCellType.Start;
onCellChanged?.Invoke(startPt.x, startPt.y, MazeReworkCellType.Start);
var endRoom = rooms[rooms.Count - 1]; var endRoom = rooms[rooms.Count - 1];
var endPt = endRoom.GetCenter(); var endPt = endRoom.GetCenter();
if (endPt == startPt && rooms.Count > 1) if (endPt == startPt && rooms.Count > 1) { endRoom = rooms[1]; endPt = endRoom.GetCenter(); }
{
endRoom = rooms[1];
endPt = endRoom.GetCenter();
}
grid[endPt.x, endPt.y] = MazeReworkCellType.End; grid[endPt.x, endPt.y] = MazeReworkCellType.End;
onCellChanged?.Invoke(endPt.x, endPt.y, MazeReworkCellType.End);
} }
else else
{ {
int sx = _config.startLocation.x; int sx = _config.startLocation.x, sz = _config.startLocation.y;
int sz = _config.startLocation.y;
EnsureValidOddCoordinates(width, depth, ref sx, ref sz); EnsureValidOddCoordinates(width, depth, ref sx, ref sz);
grid[sx, sz] = MazeReworkCellType.Start; grid[sx, sz] = MazeReworkCellType.Start;
onCellChanged?.Invoke(sx, sz, MazeReworkCellType.Start);
int ex = width - 2; int ex = width - 2, ez = depth - 2;
int ez = depth - 2;
EnsureValidOddCoordinates(width, depth, ref ex, ref ez); EnsureValidOddCoordinates(width, depth, ref ex, ref ez);
if (grid[ex, ez] == MazeReworkCellType.Wall) if (grid[ex, ez] == MazeReworkCellType.Wall)
{ {
bool found = false; bool found = false;
for (int r = 1; r < Mathf.Max(width, depth) && !found; r++) for (int r = 1; r < Mathf.Max(width, depth) && !found; r++)
{ for (int ddx = -r; ddx <= r && !found; ddx++)
for (int dx = -r; dx <= r && !found; dx++) for (int ddz = -r; ddz <= r && !found; ddz++)
{
for (int dz = -r; dz <= r && !found; dz++)
{ {
int tx = ex + dx; int tx = ex + ddx, tz = ez + ddz;
int tz = ez + dz;
if (tx >= 0 && tx < width && tz >= 0 && tz < depth && IsPathCell(grid[tx, tz])) if (tx >= 0 && tx < width && tz >= 0 && tz < depth && IsPathCell(grid[tx, tz]))
{ { ex = tx; ez = tz; found = true; }
ex = tx;
ez = tz;
found = true;
}
} }
}
}
} }
if (ex != sx || ez != sz) if (ex != sx || ez != sz)
{ {
grid[ex, ez] = MazeReworkCellType.End; grid[ex, ez] = MazeReworkCellType.End;
onCellChanged?.Invoke(ex, ez, MazeReworkCellType.End);
} }
} }
} }

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using Sirenix.OdinInspector; using Sirenix.OdinInspector;
using Baba_yaga.GameSetup.MazeRework.Animation;
namespace Baba_yaga.GameSetup.MazeRework namespace Baba_yaga.GameSetup.MazeRework
{ {
@@ -16,6 +17,11 @@ namespace Baba_yaga.GameSetup.MazeRework
[Header("References")] [Header("References")]
[SerializeField] private MazeReworkSpawner spawner; [SerializeField] private MazeReworkSpawner spawner;
[SerializeField] private Transform mazeContainer; [SerializeField] private Transform mazeContainer;
[SerializeField] private MazeAnimator animator;
[Header("Animation")]
[Tooltip("If true, visually animates the generation process step-by-step. (Best used with 1 floor)")]
[SerializeField] private bool animateGeneration = false;
[Header("Multi-floor Settings")] [Header("Multi-floor Settings")]
[Tooltip("Number of floors to generate.")] [Tooltip("Number of floors to generate.")]
@@ -102,33 +108,51 @@ namespace Baba_yaga.GameSetup.MazeRework
// Clear any previously spawned maze objects // Clear any previously spawned maze objects
ClearMaze(); ClearMaze();
if (animator != null) animator.StopAnimation();
var generator = new MazeReworkGenerator(config); var generator = new MazeReworkGenerator(config);
// Generate each floor using the configuration if (animateGeneration && animator != null)
for (int i = 0; i < floorCount; i++)
{ {
int seed = config.useRandomSeed ? Random.Range(0, 1000000) : config.seed + i * 1000; // Animated mode: generates floor 0 and replays the creation step-by-step
var grid = generator.Generate(seed); int seed = config.useRandomSeed ? Random.Range(0, 1000000) : config.seed;
var (grid, history) = generator.GenerateAnimated(seed);
_grids.Add(grid); _grids.Add(grid);
}
// Connect floors with staircases if multiple floors are present BeginningWorldPosition = FindBeginningWorldPosition(grid);
if (floorCount > 1)
animator.AnimateGeneration(history, grid, spawner, 0f, mazeContainer, () =>
{
Debug.Log($"[MazeReworkManager] Animation complete. Beginning world position: {BeginningWorldPosition}");
});
}
else
{ {
GenerateConnections(); // Standard instantaneous generation
} for (int i = 0; i < floorCount; i++)
{
int seed = config.useRandomSeed ? Random.Range(0, 1000000) : config.seed + i * 1000;
var grid = generator.Generate(seed);
_grids.Add(grid);
}
// Spawn prefabs for all floors // Connect floors with staircases if multiple floors are present
for (int i = 0; i < floorCount; i++) if (floorCount > 1)
{ {
float yOffset = i * floorHeight; GenerateConnections();
spawner.Spawn(_grids[i], yOffset, mazeContainer); }
}
// Compute and cache the world-space Beginning position from floor 0 // Spawn prefabs for all floors
BeginningWorldPosition = FindBeginningWorldPosition(_grids[0]); for (int i = 0; i < floorCount; i++)
Debug.Log($"[MazeReworkManager] Beginning world position set to: {BeginningWorldPosition}"); {
float yOffset = i * floorHeight;
spawner.Spawn(_grids[i], yOffset, mazeContainer);
}
// Compute and cache the world-space Beginning position from floor 0
BeginningWorldPosition = FindBeginningWorldPosition(_grids[0]);
Debug.Log($"[MazeReworkManager] Beginning world position set to: {BeginningWorldPosition}");
}
} }
private void GenerateConnections() private void GenerateConnections()

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using Baba_yaga.GameSetup.MazeRework.Animation;
namespace Baba_yaga.GameSetup.MazeRework namespace Baba_yaga.GameSetup.MazeRework
{ {
@@ -27,6 +28,11 @@ namespace Baba_yaga.GameSetup.MazeRework
[Tooltip("Prefab for the End cell (player exit point). Auto-rotates based on neighbors.")] [Tooltip("Prefab for the End cell (player exit point). Auto-rotates based on neighbors.")]
public GameObject endPrefab; public GameObject endPrefab;
[Header("Highlight Prefabs (Animation Only)")]
public GameObject searchHeadPrefab;
public GameObject frontierPrefab;
public GameObject evaluatingPrefab;
[Header("Rotation Offsets (Degrees)")] [Header("Rotation Offsets (Degrees)")]
[Tooltip("Rotation offset added to Hall 'I' prefab.")] [Tooltip("Rotation offset added to Hall 'I' prefab.")]
public float hallRotationOffset = 0f; public float hallRotationOffset = 0f;
@@ -47,7 +53,8 @@ namespace Baba_yaga.GameSetup.MazeRework
[Tooltip("Physical distance between each grid cell center.")] [Tooltip("Physical distance between each grid cell center.")]
public float spacing = 3.0f; public float spacing = 3.0f;
private readonly List<GameObject> _spawnedObjects = new List<GameObject>(); private readonly Dictionary<Vector2Int, GameObject> _spawnedObjects = new Dictionary<Vector2Int, GameObject>();
private readonly Dictionary<Vector2Int, GameObject> _spawnedHighlights = new Dictionary<Vector2Int, GameObject>();
private void Start() private void Start()
{ {
@@ -73,20 +80,21 @@ namespace Baba_yaga.GameSetup.MazeRework
/// </summary> /// </summary>
public void Clear() public void Clear()
{ {
foreach (var obj in _spawnedObjects) foreach (var obj in _spawnedObjects.Values)
{ {
if (obj == null) continue; if (obj == null) continue;
if (Application.isPlaying) if (Application.isPlaying) Destroy(obj); else DestroyImmediate(obj);
Destroy(obj);
else
DestroyImmediate(obj);
} }
_spawnedObjects.Clear(); _spawnedObjects.Clear();
foreach (var obj in _spawnedHighlights.Values)
{
if (obj == null) continue;
if (Application.isPlaying) Destroy(obj); else DestroyImmediate(obj);
}
_spawnedHighlights.Clear();
} }
/// <summary>
/// Spawns the modular prefabs based on the generated 2D grid array.
/// </summary>
public void Spawn(MazeReworkCellType[,] grid, float yOffset, Transform container) public void Spawn(MazeReworkCellType[,] grid, float yOffset, Transform container)
{ {
if (grid == null) return; if (grid == null) return;
@@ -99,40 +107,96 @@ namespace Baba_yaga.GameSetup.MazeRework
{ {
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
MazeReworkCellType type = grid[x, z]; RefreshSingleCell(grid, null, x, z, width, depth, yOffset, container);
// Wall cells spawn nothing
if (type == MazeReworkCellType.Wall)
{
continue;
}
// For Start and End cells, use their dedicated prefab if assigned,
// then apply connectivity-based rotation so they face the correct open direction.
if (type == MazeReworkCellType.Start && beginningPrefab != null)
{
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
SpawnPrefab(beginningPrefab, x, yOffset, z, baseRot + beginningRotationOffset, container, "Beginning");
continue;
}
if (type == MazeReworkCellType.End && endPrefab != null)
{
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
SpawnPrefab(endPrefab, x, yOffset, z, baseRot + endRotationOffset, container, "End");
continue;
}
// All other path cells: evaluate connectivity to select and rotate the modular hallway prefab
(GameObject modularPrefab, float yRotation) = GetModularPrefabAndRotation(grid, x, z, width, depth);
if (modularPrefab != null)
{
SpawnPrefab(modularPrefab, x, yOffset, z, yRotation, container, $"{type}");
}
} }
} }
} }
/// <summary>
/// Refreshes a specific cell and its neighbors based on the current grid state.
/// </summary>
public void RefreshCell(MazeReworkCellType[,] grid, MazeCellHighlight[,] highlights, int x, int z, float yOffset, Transform container)
{
if (grid == null) return;
int width = grid.GetLength(0);
int depth = grid.GetLength(1);
// Refresh the target cell
RefreshSingleCell(grid, highlights, x, z, width, depth, yOffset, container);
// Refresh neighbors because their connectivity might have changed
RefreshSingleCell(grid, highlights, x + 1, z, width, depth, yOffset, container);
RefreshSingleCell(grid, highlights, x - 1, z, width, depth, yOffset, container);
RefreshSingleCell(grid, highlights, x, z + 1, width, depth, yOffset, container);
RefreshSingleCell(grid, highlights, x, z - 1, width, depth, yOffset, container);
}
private void RefreshSingleCell(MazeReworkCellType[,] grid, MazeCellHighlight[,] highlights, int x, int z, int width, int depth, float yOffset, Transform container)
{
if (x < 0 || x >= width || z < 0 || z >= depth) return;
Vector2Int pos = new Vector2Int(x, z);
MazeReworkCellType type = grid[x, z];
MazeCellHighlight hType = highlights != null ? highlights[x, z] : MazeCellHighlight.None;
// 1. Process Highlights
if (_spawnedHighlights.TryGetValue(pos, out GameObject existingHighlight))
{
if (Application.isPlaying) Destroy(existingHighlight);
else DestroyImmediate(existingHighlight);
_spawnedHighlights.Remove(pos);
}
if (hType != MazeCellHighlight.None)
{
GameObject hPrefab = null;
if (hType == MazeCellHighlight.SearchHead) hPrefab = searchHeadPrefab;
else if (hType == MazeCellHighlight.Frontier) hPrefab = frontierPrefab;
else if (hType == MazeCellHighlight.Evaluating) hPrefab = evaluatingPrefab;
if (hPrefab != null)
{
Vector3 localPos = new Vector3(x * spacing, yOffset, z * spacing);
GameObject spawnedH = Instantiate(hPrefab, container != null ? container : transform);
spawnedH.transform.localPosition = localPos;
spawnedH.name = $"Highlight_{hType}_{x}_{z}";
_spawnedHighlights[pos] = spawnedH;
}
}
// 2. Process Grid Cells
if (type == MazeReworkCellType.Wall)
{
if (_spawnedObjects.TryGetValue(pos, out GameObject existing))
{
if (Application.isPlaying) Destroy(existing);
else DestroyImmediate(existing);
_spawnedObjects.Remove(pos);
}
return;
}
if (type == MazeReworkCellType.Start && beginningPrefab != null)
{
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
SpawnPrefab(beginningPrefab, x, yOffset, z, baseRot + beginningRotationOffset, container, "Beginning");
return;
}
if (type == MazeReworkCellType.End && endPrefab != null)
{
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
SpawnPrefab(endPrefab, x, yOffset, z, baseRot + endRotationOffset, container, "End");
return;
}
(GameObject modularPrefab, float yRotation) = GetModularPrefabAndRotation(grid, x, z, width, depth);
if (modularPrefab != null)
{
SpawnPrefab(modularPrefab, x, yOffset, z, yRotation, container, $"{type}");
}
}
private void SpawnPrefab(GameObject prefab, int x, float y, int z, float yRotation, Transform container, string namePrefix) private void SpawnPrefab(GameObject prefab, int x, float y, int z, float yRotation, Transform container, string namePrefix)
{ {
Vector3 localPosition = new Vector3(x * spacing, y, z * spacing); Vector3 localPosition = new Vector3(x * spacing, y, z * spacing);
@@ -140,7 +204,14 @@ namespace Baba_yaga.GameSetup.MazeRework
spawnedObj.transform.localPosition = localPosition; spawnedObj.transform.localPosition = localPosition;
spawnedObj.transform.localRotation = Quaternion.Euler(0f, yRotation, 0f); spawnedObj.transform.localRotation = Quaternion.Euler(0f, yRotation, 0f);
spawnedObj.name = $"{namePrefix}_{x}_{z}"; spawnedObj.name = $"{namePrefix}_{x}_{z}";
_spawnedObjects.Add(spawnedObj);
var pos = new Vector2Int(x, z);
if (_spawnedObjects.TryGetValue(pos, out GameObject existing))
{
if (Application.isPlaying) Destroy(existing);
else DestroyImmediate(existing);
}
_spawnedObjects[pos] = spawnedObj;
} }
private (GameObject, float) GetModularPrefabAndRotation(MazeReworkCellType[,] grid, int x, int z, int width, int depth) private (GameObject, float) GetModularPrefabAndRotation(MazeReworkCellType[,] grid, int x, int z, int width, int depth)