diff --git a/Assets/Editor/Inspector/BlockPuzzleGridEditor.cs b/Assets/Editor/Inspector/BlockShaprEditor.cs
similarity index 51%
rename from Assets/Editor/Inspector/BlockPuzzleGridEditor.cs
rename to Assets/Editor/Inspector/BlockShaprEditor.cs
index 2ad6302c4..021b9e91f 100644
--- a/Assets/Editor/Inspector/BlockPuzzleGridEditor.cs
+++ b/Assets/Editor/Inspector/BlockShaprEditor.cs
@@ -3,26 +3,23 @@ using UnityEngine;
namespace AibisDream.SystemEditor
{
- [CustomEditor(typeof(BlockPuzzleGrid))]
- public class BlockPuzzleGridEditor : Editor
+ [CustomEditor(typeof(BlockShape))]
+ public class BlockShapeEditor : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
- var example = (BlockPuzzleGrid)target;
- EditorGUILayout.Separator();
+ var example = (BlockShape)target;
EditorGUILayout.BeginHorizontal();
- // 保存按钮
+ // 增加绘制形状和保存形状按钮
+ if (GUILayout.Button("绘制"))
+ {
+ example.DrawShape();
+ }
if (GUILayout.Button("保存"))
{
- // example.SaveStyle();
- }
-
- // 加载按钮
- if (GUILayout.Button("加载"))
- {
- // example.LoadStyle();
+ example.SaveShape();
}
EditorGUILayout.EndHorizontal();
}
diff --git a/Assets/Editor/Inspector/BlockPuzzleGridEditor.cs.meta b/Assets/Editor/Inspector/BlockShaprEditor.cs.meta
similarity index 83%
rename from Assets/Editor/Inspector/BlockPuzzleGridEditor.cs.meta
rename to Assets/Editor/Inspector/BlockShaprEditor.cs.meta
index fb40dde14..6ab775eca 100644
--- a/Assets/Editor/Inspector/BlockPuzzleGridEditor.cs.meta
+++ b/Assets/Editor/Inspector/BlockShaprEditor.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 7eb275cadab046c44a9f46f3f475145e
+guid: 73fc356b22fa6a147be7a2eb9c78f123
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Assets/Language/UIText/UIText_zh-Hans.asset b/Assets/Language/UIText/UIText_zh-Hans.asset
index df174b5f0..270bd717d 100644
--- a/Assets/Language/UIText/UIText_zh-Hans.asset
+++ b/Assets/Language/UIText/UIText_zh-Hans.asset
@@ -24,7 +24,7 @@ MonoBehaviour:
m_Metadata:
m_Items: []
- m_Id: 22296654778368
- m_Localized: "\u7231&\u673A\u5668\u4EBA\\n\u7EF4\u4FEE\u6280\u672F"
+ m_Localized: "\u7231\u4E0E\u673A\u5668\u4EBA\\n\u7EF4\u4FEE\u6280\u672F"
m_Metadata:
m_Items:
- rid: 7917695939544875419
diff --git a/Assets/Scenes/网格测试.unity b/Assets/Scenes/网格测试.unity
index c8dffcca1..cee6a404e 100644
--- a/Assets/Scenes/网格测试.unity
+++ b/Assets/Scenes/网格测试.unity
@@ -123,6 +123,552 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
+--- !u!1 &199240525
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 199240526}
+ - component: {fileID: 199240527}
+ m_Layer: 0
+ m_Name: Cell_0_2
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &199240526
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 199240525}
+ serializedVersion: 2
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 2, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 1147676901}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!212 &199240527
+SpriteRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 199240525}
+ m_Enabled: 1
+ m_CastShadows: 0
+ m_ReceiveShadows: 0
+ m_DynamicOccludee: 1
+ m_StaticShadowCaster: 0
+ m_MotionVectors: 1
+ m_LightProbeUsage: 1
+ m_ReflectionProbeUsage: 1
+ m_RayTracingMode: 0
+ m_RayTraceProcedural: 0
+ m_RenderingLayerMask: 1
+ m_RendererPriority: 0
+ m_Materials:
+ - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, 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: 0
+ m_MinimumChartSize: 4
+ m_AutoUVMaxDistance: 0.5
+ m_AutoUVMaxAngle: 89
+ m_LightmapParameters: {fileID: 0}
+ m_SortingLayerID: 0
+ m_SortingLayer: 0
+ m_SortingOrder: 0
+ m_Sprite: {fileID: 431031536}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_FlipX: 0
+ m_FlipY: 0
+ m_DrawMode: 0
+ m_Size: {x: 1, y: 1}
+ m_AdaptiveModeThreshold: 0.5
+ m_SpriteTileMode: 0
+ m_WasSpriteAssigned: 1
+ m_MaskInteraction: 0
+ m_SpriteSortPoint: 0
+--- !u!1 &224755568
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 224755569}
+ - component: {fileID: 224755570}
+ m_Layer: 0
+ m_Name: Cell_1_1
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &224755569
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 224755568}
+ serializedVersion: 2
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 1, y: 1, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 1147676901}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!212 &224755570
+SpriteRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 224755568}
+ m_Enabled: 1
+ m_CastShadows: 0
+ m_ReceiveShadows: 0
+ m_DynamicOccludee: 1
+ m_StaticShadowCaster: 0
+ m_MotionVectors: 1
+ m_LightProbeUsage: 1
+ m_ReflectionProbeUsage: 1
+ m_RayTracingMode: 0
+ m_RayTraceProcedural: 0
+ m_RenderingLayerMask: 1
+ m_RendererPriority: 0
+ m_Materials:
+ - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, 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: 0
+ m_MinimumChartSize: 4
+ m_AutoUVMaxDistance: 0.5
+ m_AutoUVMaxAngle: 89
+ m_LightmapParameters: {fileID: 0}
+ m_SortingLayerID: 0
+ m_SortingLayer: 0
+ m_SortingOrder: 0
+ m_Sprite: {fileID: 431031536}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_FlipX: 0
+ m_FlipY: 0
+ m_DrawMode: 0
+ m_Size: {x: 1, y: 1}
+ m_AdaptiveModeThreshold: 0.5
+ m_SpriteTileMode: 0
+ m_WasSpriteAssigned: 1
+ m_MaskInteraction: 0
+ m_SpriteSortPoint: 0
+--- !u!1 &397665472
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 397665473}
+ - component: {fileID: 397665474}
+ m_Layer: 0
+ m_Name: Cell_0_1
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &397665473
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 397665472}
+ serializedVersion: 2
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0.01, y: 1, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 1147676901}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!212 &397665474
+SpriteRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 397665472}
+ m_Enabled: 1
+ m_CastShadows: 0
+ m_ReceiveShadows: 0
+ m_DynamicOccludee: 1
+ m_StaticShadowCaster: 0
+ m_MotionVectors: 1
+ m_LightProbeUsage: 1
+ m_ReflectionProbeUsage: 1
+ m_RayTracingMode: 0
+ m_RayTraceProcedural: 0
+ m_RenderingLayerMask: 1
+ m_RendererPriority: 0
+ m_Materials:
+ - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, 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: 0
+ m_MinimumChartSize: 4
+ m_AutoUVMaxDistance: 0.5
+ m_AutoUVMaxAngle: 89
+ m_LightmapParameters: {fileID: 0}
+ m_SortingLayerID: 0
+ m_SortingLayer: 0
+ m_SortingOrder: 0
+ m_Sprite: {fileID: 431031536}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_FlipX: 0
+ m_FlipY: 0
+ m_DrawMode: 0
+ m_Size: {x: 1, y: 1}
+ m_AdaptiveModeThreshold: 0.5
+ m_SpriteTileMode: 0
+ m_WasSpriteAssigned: 1
+ m_MaskInteraction: 0
+ m_SpriteSortPoint: 0
+--- !u!213 &431031536
+Sprite:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name:
+ m_Rect:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 1
+ height: 1
+ m_Offset: {x: 0, y: 0}
+ m_Border: {x: 0, y: 0, z: 0, w: 0}
+ m_PixelsToUnits: 1
+ m_Pivot: {x: 0.5, y: 0.5}
+ m_Extrude: 0
+ m_IsPolygon: 0
+ m_AtlasName:
+ m_PackingTag:
+ m_RenderDataKey:
+ 00000000000000000000000000000000: 0
+ m_AtlasTags: []
+ m_SpriteAtlas: {fileID: 0}
+ m_RD:
+ serializedVersion: 3
+ texture: {fileID: 952406368}
+ alphaTexture: {fileID: 0}
+ secondaryTextures: []
+ m_SubMeshes:
+ - serializedVersion: 2
+ firstByte: 0
+ indexCount: 6
+ topology: 0
+ baseVertex: 0
+ firstVertex: 0
+ vertexCount: 4
+ localAABB:
+ m_Center: {x: 0, y: 0, z: 0}
+ m_Extent: {x: 0, y: 0, z: 0}
+ m_IndexBuffer: 000001000200020001000300
+ m_VertexData:
+ serializedVersion: 3
+ m_VertexCount: 4
+ m_Channels:
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 3
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 1
+ offset: 0
+ format: 0
+ dimension: 2
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ m_DataSize: 80
+ _typelessdata: 000000bf0000003f000000000000003f0000003f00000000000000bf000000bf000000000000003f000000bf00000000000000000000803f0000803f0000803f00000000000000000000803f00000000
+ m_Bindpose: []
+ textureRect:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 1
+ height: 1
+ textureRectOffset: {x: 0, y: 0}
+ atlasRectOffset: {x: -1, y: -1}
+ settingsRaw: 64
+ uvTransform: {x: 1, y: 0.5, z: 1, w: 0.5}
+ downscaleMultiplier: 1
+ m_AtlasRD:
+ serializedVersion: 3
+ texture: {fileID: 952406368}
+ alphaTexture: {fileID: 0}
+ secondaryTextures: []
+ m_SubMeshes:
+ - serializedVersion: 2
+ firstByte: 0
+ indexCount: 6
+ topology: 0
+ baseVertex: 0
+ firstVertex: 0
+ vertexCount: 4
+ localAABB:
+ m_Center: {x: 0, y: 0, z: 0}
+ m_Extent: {x: 0, y: 0, z: 0}
+ m_IndexBuffer: 000001000200020001000300
+ m_VertexData:
+ serializedVersion: 3
+ m_VertexCount: 4
+ m_Channels:
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 3
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 1
+ offset: 0
+ format: 0
+ dimension: 2
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ - stream: 0
+ offset: 0
+ format: 0
+ dimension: 0
+ m_DataSize: 80
+ _typelessdata: 000000bf0000003f000000000000003f0000003f00000000000000bf000000bf000000000000003f000000bf00000000000000000000803f0000803f0000803f00000000000000000000803f00000000
+ m_Bindpose: []
+ textureRect:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 1
+ height: 1
+ textureRectOffset: {x: 0, y: 0}
+ atlasRectOffset: {x: -1, y: -1}
+ settingsRaw: 64
+ uvTransform: {x: 1, y: 0.5, z: 1, w: 0.5}
+ downscaleMultiplier: 1
+ m_PhysicsShape: []
+ m_Bones: []
+ m_SpriteID:
+--- !u!1 &451361381
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 451361382}
+ - component: {fileID: 451361383}
+ m_Layer: 0
+ m_Name: Cell_1_0
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &451361382
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 451361381}
+ serializedVersion: 2
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 1, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 1147676901}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!212 &451361383
+SpriteRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 451361381}
+ m_Enabled: 1
+ m_CastShadows: 0
+ m_ReceiveShadows: 0
+ m_DynamicOccludee: 1
+ m_StaticShadowCaster: 0
+ m_MotionVectors: 1
+ m_LightProbeUsage: 1
+ m_ReflectionProbeUsage: 1
+ m_RayTracingMode: 0
+ m_RayTraceProcedural: 0
+ m_RenderingLayerMask: 1
+ m_RendererPriority: 0
+ m_Materials:
+ - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, 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: 0
+ m_MinimumChartSize: 4
+ m_AutoUVMaxDistance: 0.5
+ m_AutoUVMaxAngle: 89
+ m_LightmapParameters: {fileID: 0}
+ m_SortingLayerID: 0
+ m_SortingLayer: 0
+ m_SortingOrder: 0
+ m_Sprite: {fileID: 431031536}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_FlipX: 0
+ m_FlipY: 0
+ m_DrawMode: 0
+ m_Size: {x: 1, y: 1}
+ m_AdaptiveModeThreshold: 0.5
+ m_SpriteTileMode: 0
+ m_WasSpriteAssigned: 1
+ m_MaskInteraction: 0
+ m_SpriteSortPoint: 0
--- !u!1 &791020753
GameObject:
m_ObjectHideFlags: 0
@@ -215,6 +761,370 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &822843321
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 822843322}
+ - component: {fileID: 822843323}
+ m_Layer: 0
+ m_Name: Cell_0_0
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &822843322
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 822843321}
+ serializedVersion: 2
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 1147676901}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!212 &822843323
+SpriteRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 822843321}
+ m_Enabled: 0
+ m_CastShadows: 0
+ m_ReceiveShadows: 0
+ m_DynamicOccludee: 1
+ m_StaticShadowCaster: 0
+ m_MotionVectors: 1
+ m_LightProbeUsage: 1
+ m_ReflectionProbeUsage: 1
+ m_RayTracingMode: 0
+ m_RayTraceProcedural: 0
+ m_RenderingLayerMask: 1
+ m_RendererPriority: 0
+ m_Materials:
+ - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, 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: 0
+ m_MinimumChartSize: 4
+ m_AutoUVMaxDistance: 0.5
+ m_AutoUVMaxAngle: 89
+ m_LightmapParameters: {fileID: 0}
+ m_SortingLayerID: 0
+ m_SortingLayer: 0
+ m_SortingOrder: 0
+ m_Sprite: {fileID: 431031536}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_FlipX: 0
+ m_FlipY: 0
+ m_DrawMode: 0
+ m_Size: {x: 1, y: 1}
+ m_AdaptiveModeThreshold: 0.5
+ m_SpriteTileMode: 0
+ m_WasSpriteAssigned: 1
+ m_MaskInteraction: 0
+ m_SpriteSortPoint: 0
+--- !u!28 &952406368
+Texture2D:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name:
+ m_ImageContentsHash:
+ serializedVersion: 2
+ Hash: 00000000000000000000000000000000
+ m_ForcedFallbackFormat: 4
+ m_DownscaleFallback: 0
+ m_IsAlphaChannelOptional: 0
+ serializedVersion: 2
+ m_Width: 1
+ m_Height: 1
+ m_CompleteImageSize: 4
+ m_MipsStripped: 0
+ m_TextureFormat: 4
+ m_MipCount: 1
+ m_IsReadable: 1
+ m_IsPreProcessed: 0
+ m_IgnoreMipmapLimit: 0
+ m_MipmapLimitGroupName:
+ m_StreamingMipmaps: 0
+ m_StreamingMipmapsPriority: 0
+ m_VTOnly: 0
+ m_AlphaIsTransparency: 0
+ m_ImageCount: 1
+ m_TextureDimension: 2
+ m_TextureSettings:
+ serializedVersion: 2
+ m_FilterMode: 1
+ m_Aniso: 1
+ m_MipBias: 0
+ m_WrapU: 0
+ m_WrapV: 0
+ m_WrapW: 0
+ m_LightmapFormat: 0
+ m_ColorSpace: 1
+ m_PlatformBlob:
+ image data: 4
+ _typelessdata: ff0000ff
+ m_StreamData:
+ serializedVersion: 2
+ offset: 0
+ size: 0
+ path:
+--- !u!1 &1147676900
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1147676901}
+ - component: {fileID: 1147676902}
+ - component: {fileID: 1147676903}
+ - component: {fileID: 1147676904}
+ - component: {fileID: 1147676905}
+ - component: {fileID: 1147676906}
+ m_Layer: 0
+ m_Name: Shape
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &1147676901
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1147676900}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 2.06, y: -0.14, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children:
+ - {fileID: 822843322}
+ - {fileID: 397665473}
+ - {fileID: 199240526}
+ - {fileID: 451361382}
+ - {fileID: 224755569}
+ - {fileID: 1662947689}
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1147676902
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1147676900}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 4be33b2e5baf96447a7df0d10cb22064, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ shapeId: 0
+ shapeName: "\u793A\u4F8B\u6A21\u5757"
+ currentRotation: 0
+ width: 2
+ height: 3
+ cellSize: 1
+ originalPatternStr: 0,1,1;1,1,0
+--- !u!212 &1147676903
+SpriteRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1147676900}
+ m_Enabled: 1
+ m_CastShadows: 0
+ m_ReceiveShadows: 0
+ m_DynamicOccludee: 1
+ m_StaticShadowCaster: 0
+ m_MotionVectors: 1
+ m_LightProbeUsage: 1
+ m_ReflectionProbeUsage: 1
+ m_RayTracingMode: 0
+ m_RayTraceProcedural: 0
+ m_RenderingLayerMask: 1
+ m_RendererPriority: 0
+ m_Materials:
+ - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, 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: 0
+ m_MinimumChartSize: 4
+ m_AutoUVMaxDistance: 0.5
+ m_AutoUVMaxAngle: 89
+ m_LightmapParameters: {fileID: 0}
+ m_SortingLayerID: 0
+ m_SortingLayer: 0
+ m_SortingOrder: 0
+ m_Sprite: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_FlipX: 0
+ m_FlipY: 0
+ m_DrawMode: 0
+ m_Size: {x: 1, y: 1}
+ m_AdaptiveModeThreshold: 0.5
+ m_SpriteTileMode: 0
+ m_WasSpriteAssigned: 0
+ m_MaskInteraction: 0
+ m_SpriteSortPoint: 0
+--- !u!60 &1147676904
+PolygonCollider2D:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1147676900}
+ m_Enabled: 1
+ m_Density: 1
+ m_Material: {fileID: 0}
+ m_IncludeLayers:
+ serializedVersion: 2
+ m_Bits: 0
+ m_ExcludeLayers:
+ serializedVersion: 2
+ m_Bits: 0
+ m_LayerOverridePriority: 0
+ m_ForceSendLayers:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_ForceReceiveLayers:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_ContactCaptureLayers:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_CallbackLayers:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_IsTrigger: 0
+ m_UsedByEffector: 0
+ m_UsedByComposite: 0
+ m_Offset: {x: 0, y: 0}
+ m_SpriteTilingProperty:
+ border: {x: 0, y: 0, z: 0, w: 0}
+ pivot: {x: 0, y: 0}
+ oldSize: {x: 0, y: 0}
+ newSize: {x: 0, y: 0}
+ adaptiveTilingThreshold: 0
+ drawMode: 0
+ adaptiveTiling: 0
+ m_AutoTiling: 0
+ m_Points:
+ m_Paths:
+ - - {x: -0.5, y: 0.5}
+ - {x: 0.5, y: 0.5}
+ - {x: 0.5, y: -0.5}
+ - {x: 1.5, y: -0.5}
+ - {x: 1.5, y: 0.5}
+ - {x: 1.5, y: 1.5}
+ - {x: 0.5, y: 1.5}
+ - {x: 0.5, y: 2.5}
+ - {x: -0.5, y: 2.5}
+ - {x: -0.5, y: 1.5}
+ m_UseDelaunayMesh: 0
+--- !u!114 &1147676905
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1147676900}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 6ad01079e32d2314eb3719ead5f50ddb, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ isDraggable: 1
+ snapDistance: 0.5
+ targetGridComponent: {fileID: 1928610078}
+ snapColor: {r: 0, g: 1, b: 0, a: 0.7}
+ invalidColor: {r: 1, g: 0, b: 0, a: 0.7}
+ normalColor: {r: 1, g: 1, b: 1, a: 1}
+ dragScale: 1.1
+--- !u!114 &1147676906
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1147676900}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 0c4fbab01ad40c2449c849cd2a8c620f, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Delegates:
+ - eventID: 0
+ callback:
+ m_PersistentCalls:
+ m_Calls: []
+ - eventID: 1
+ callback:
+ m_PersistentCalls:
+ m_Calls: []
+ - eventID: 2
+ callback:
+ m_PersistentCalls:
+ m_Calls: []
+ - eventID: 3
+ callback:
+ m_PersistentCalls:
+ m_Calls: []
+ - eventID: 4
+ callback:
+ m_PersistentCalls:
+ m_Calls: []
+ - eventID: 5
+ callback:
+ m_PersistentCalls:
+ m_Calls: []
+ - eventID: 14
+ callback:
+ m_PersistentCalls:
+ m_Calls: []
+ - eventID: 13
+ callback:
+ m_PersistentCalls:
+ m_Calls: []
--- !u!1 &1429030510
GameObject:
m_ObjectHideFlags: 0
@@ -224,7 +1134,6 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 1429030511}
- - component: {fileID: 1429030512}
m_Layer: 0
m_Name: Block Puzzle Game
m_TagString: Untagged
@@ -248,22 +1157,90 @@ Transform:
- {fileID: 1928610076}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
---- !u!114 &1429030512
-MonoBehaviour:
+--- !u!1 &1662947688
+GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 1429030510}
- m_Enabled: 1
- m_EditorHideFlags: 0
- m_Script: {fileID: 11500000, guid: cfe4f41ce15355345b390aa2701f3f46, type: 3}
- m_Name:
- m_EditorClassIdentifier:
- gridComponent: {fileID: 0}
- gridVisualizer: {fileID: 0}
- testPlaceKey: 32
- testClearKey: 99
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1662947689}
+ - component: {fileID: 1662947690}
+ m_Layer: 0
+ m_Name: Cell_1_2
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &1662947689
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1662947688}
+ serializedVersion: 2
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 1, y: 2, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 1147676901}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!212 &1662947690
+SpriteRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1662947688}
+ m_Enabled: 0
+ m_CastShadows: 0
+ m_ReceiveShadows: 0
+ m_DynamicOccludee: 1
+ m_StaticShadowCaster: 0
+ m_MotionVectors: 1
+ m_LightProbeUsage: 1
+ m_ReflectionProbeUsage: 1
+ m_RayTracingMode: 0
+ m_RayTraceProcedural: 0
+ m_RenderingLayerMask: 1
+ m_RendererPriority: 0
+ m_Materials:
+ - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, 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: 0
+ m_MinimumChartSize: 4
+ m_AutoUVMaxDistance: 0.5
+ m_AutoUVMaxAngle: 89
+ m_LightmapParameters: {fileID: 0}
+ m_SortingLayerID: 0
+ m_SortingLayer: 0
+ m_SortingOrder: 0
+ m_Sprite: {fileID: 431031536}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_FlipX: 0
+ m_FlipY: 0
+ m_DrawMode: 0
+ m_Size: {x: 1, y: 1}
+ m_AdaptiveModeThreshold: 0.5
+ m_SpriteTileMode: 0
+ m_WasSpriteAssigned: 1
+ m_MaskInteraction: 0
+ m_SpriteSortPoint: 0
--- !u!1 &1928610075
GameObject:
m_ObjectHideFlags: 0
@@ -291,7 +1268,7 @@ Transform:
m_GameObject: {fileID: 1928610075}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalPosition: {x: -6.5, y: -2.5, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
@@ -310,8 +1287,8 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
gridComponent: {fileID: 1928610078}
- gridWidth: 10
- gridHeight: 10
+ gridWidth: 5
+ gridHeight: 5
cellSize: 1
showGridLines: 1
showCellSprites: 1
@@ -333,13 +1310,19 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 990de8ef2a6774544b9bc9b64af0a8a5, type: 3}
m_Name:
m_EditorClassIdentifier:
- width: 10
- height: 10
+ width: 5
+ height: 5
cellSize: 1
initializeOnStart: 1
+ showGizmos: 1
+ gridLineColor: {r: 0.5, g: 0.5, b: 0.5, a: 0.8}
+ emptyCellColor: {r: 0.9, g: 0.9, b: 0.9, a: 0.2}
+ occupiedCellColor: {r: 0.2, g: 0.6, b: 1, a: 0.5}
+ showCellStates: 1
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 791020756}
- {fileID: 1429030511}
+ - {fileID: 1147676901}
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/Class.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Class.meta
new file mode 100644
index 000000000..822c6c2df
--- /dev/null
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Class.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0eb5cc55dcdc0f244a5cb635090c0bd3
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/BlockPuzzleGrid.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleGrid.cs
similarity index 54%
rename from Assets/Scripts/MiniGame/BlockPuzzle/BlockPuzzleGrid.cs
rename to Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleGrid.cs
index 4936c995c..6f61d4257 100644
--- a/Assets/Scripts/MiniGame/BlockPuzzle/BlockPuzzleGrid.cs
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleGrid.cs
@@ -14,6 +14,13 @@ namespace AibisDream
[SerializeField] private float cellSize = 1f;
[SerializeField] private bool initializeOnStart = true;
+ [Header("编辑器预览设置")]
+ [SerializeField] private bool showGizmos = true;
+ [SerializeField] private Color gridLineColor = new Color(0.5f, 0.5f, 0.5f, 0.8f);
+ [SerializeField] private Color emptyCellColor = new Color(0.9f, 0.9f, 0.9f, 0.2f);
+ [SerializeField] private Color occupiedCellColor = new Color(0.2f, 0.6f, 1f, 0.5f);
+ [SerializeField] private bool showCellStates = true;
+
private GridCellState[,] _grid;
private bool _isInitialized = false;
@@ -157,6 +164,24 @@ namespace AibisDream
return new Vector3(worldX, worldY, Origin.z);
}
+ public Vector3[] GridVerticesToWorld(int x, int y)
+ {
+ if (!_isInitialized)
+ {
+ return new Vector3[4];
+ }
+
+ // 先获取网格中心位置
+ Vector3 center = GridToWorld(x, y);
+ // 然后获取网格四个顶点位置
+ Vector3[] vertices = new Vector3[4];
+ vertices[0] = center + new Vector3(-CellSize / 2, -CellSize / 2, 0);
+ vertices[1] = center + new Vector3(CellSize / 2, -CellSize / 2, 0);
+ vertices[2] = center + new Vector3(CellSize / 2, CellSize / 2, 0);
+ vertices[3] = center + new Vector3(-CellSize / 2, CellSize / 2, 0);
+ return vertices;
+ }
+
public void Clear()
{
if (!_isInitialized || _grid == null) return;
@@ -209,6 +234,93 @@ namespace AibisDream
height = Mathf.Max(1, height);
cellSize = Mathf.Max(0.1f, cellSize);
}
+
+ ///
+ /// 在编辑器中绘制网格预览
+ ///
+ private void OnDrawGizmos()
+ {
+ if (!showGizmos) return;
+
+ // 使用当前Inspector中的参数或已初始化的参数
+ int drawWidth = _isInitialized ? Width : width;
+ int drawHeight = _isInitialized ? Height : height;
+ float drawCellSize = _isInitialized ? CellSize : cellSize;
+ Vector3 drawOrigin = _isInitialized ? Origin : transform.position;
+
+ if (drawWidth <= 0 || drawHeight <= 0 || drawCellSize <= 0) return;
+
+ // 绘制网格线
+ Gizmos.color = gridLineColor;
+ for (int x = 0; x <= drawWidth; x++)
+ {
+ Vector3 start = drawOrigin + new Vector3(x * drawCellSize, 0, 0);
+ Vector3 end = drawOrigin + new Vector3(x * drawCellSize, drawHeight * drawCellSize, 0);
+ Gizmos.DrawLine(start, end);
+ }
+
+ for (int y = 0; y <= drawHeight; y++)
+ {
+ Vector3 start = drawOrigin + new Vector3(0, y * drawCellSize, 0);
+ Vector3 end = drawOrigin + new Vector3(drawWidth * drawCellSize, y * drawCellSize, 0);
+ Gizmos.DrawLine(start, end);
+ }
+
+ // 绘制单元格状态(如果已初始化且启用)
+ if (showCellStates && _isInitialized && _grid != null)
+ {
+ float cellDisplaySize = drawCellSize * 0.9f; // 稍微小一点,留出网格线空间
+ Vector3 cellSizeVec = new Vector3(cellDisplaySize, cellDisplaySize, 0.01f);
+
+ for (int x = 0; x < drawWidth; x++)
+ {
+ for (int y = 0; y < drawHeight; y++)
+ {
+ if (IsValidPosition(x, y))
+ {
+ Vector3 cellCenter = GridToWorld(x, y);
+ GridCellState state = GetCellState(x, y);
+
+ Gizmos.color = state == GridCellState.Occupied ? occupiedCellColor : emptyCellColor;
+ Gizmos.DrawCube(cellCenter, cellSizeVec);
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// 选中时绘制更明显的网格边界
+ ///
+ private void OnDrawGizmosSelected()
+ {
+ if (!showGizmos) return;
+
+ // 使用当前Inspector中的参数或已初始化的参数
+ int drawWidth = _isInitialized ? Width : width;
+ int drawHeight = _isInitialized ? Height : height;
+ float drawCellSize = _isInitialized ? CellSize : cellSize;
+ Vector3 drawOrigin = _isInitialized ? Origin : transform.position;
+
+ if (drawWidth <= 0 || drawHeight <= 0 || drawCellSize <= 0) return;
+
+ // 绘制网格边界(更粗的线)
+ Gizmos.color = new Color(gridLineColor.r, gridLineColor.g, gridLineColor.b, 1f);
+ Vector3 bottomLeft = drawOrigin;
+ Vector3 bottomRight = drawOrigin + new Vector3(drawWidth * drawCellSize, 0, 0);
+ Vector3 topLeft = drawOrigin + new Vector3(0, drawHeight * drawCellSize, 0);
+ Vector3 topRight = drawOrigin + new Vector3(drawWidth * drawCellSize, drawHeight * drawCellSize, 0);
+
+ // 绘制边界框
+ Gizmos.DrawLine(bottomLeft, bottomRight);
+ Gizmos.DrawLine(bottomRight, topRight);
+ Gizmos.DrawLine(topRight, topLeft);
+ Gizmos.DrawLine(topLeft, bottomLeft);
+
+ // 绘制原点标记
+ Gizmos.color = Color.yellow;
+ Gizmos.DrawWireSphere(drawOrigin, 0.1f);
+ }
}
}
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/BlockPuzzleGrid.cs.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleGrid.cs.meta
similarity index 100%
rename from Assets/Scripts/MiniGame/BlockPuzzle/BlockPuzzleGrid.cs.meta
rename to Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleGrid.cs.meta
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/BlockPuzzleGridExample.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleGridExample.cs
similarity index 100%
rename from Assets/Scripts/MiniGame/BlockPuzzle/BlockPuzzleGridExample.cs
rename to Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleGridExample.cs
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/BlockPuzzleGridExample.cs.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleGridExample.cs.meta
similarity index 100%
rename from Assets/Scripts/MiniGame/BlockPuzzle/BlockPuzzleGridExample.cs.meta
rename to Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockPuzzleGridExample.cs.meta
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockShape.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockShape.cs
new file mode 100644
index 000000000..792658e6b
--- /dev/null
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockShape.cs
@@ -0,0 +1,381 @@
+using System.Collections.Generic;
+using AibisDream.Utility;
+using UnityEngine;
+
+namespace AibisDream
+{
+ public class BlockShape : MonoBehaviour, IBlockShape
+ {
+ private SpriteRenderer[,] _cellRenderers;
+
+ // 模块数据
+ [Header("模块数据")]
+ [SerializeField] private int shapeId;
+ [SerializeField] private string shapeName;
+ [SerializeField] private RotationAngle currentRotation;
+ [SerializeField] private int width;
+ [SerializeField] private int height;
+ [SerializeField] private float cellSize;
+ [SerializeField] private string originalPatternStr;
+
+ // 接口实现
+ public int ShapeId => shapeId;
+ public string ShapeName => shapeName;
+ public RotationAngle CurrentRotation => currentRotation;
+ public int Width => width;
+ public int Height => height;
+ public int BlockCount
+ {
+ get
+ {
+ var pattern = GetOriginalPattern();
+ if (pattern == null) return 0;
+
+ int count = 0;
+ for (int i = 0; i < width; i++)
+ {
+ for (int j = 0; j < height; j++)
+ {
+ if (pattern[i, j] != 0)
+ {
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+ }
+
+ public Vector2Int[] GetBlockPositions()
+ {
+ var pattern = GetOriginalPattern();
+ if (pattern == null) return new Vector2Int[0];
+
+ List positions = new List();
+
+ for (int i = 0; i < width; i++)
+ {
+ for (int j = 0; j < height; j++)
+ {
+ if (pattern[i, j] != 0)
+ {
+ positions.Add(new Vector2Int(i, j));
+ }
+ }
+ }
+
+ return positions.ToArray();
+ }
+
+ ///
+ /// 获取单元格渲染器数组(供拖拽组件使用)
+ ///
+ public SpriteRenderer[,] GetCellRenderers()
+ {
+ return _cellRenderers;
+ }
+
+ public int[,] GetCurrentPattern()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public int[,] GetOriginalPattern()
+ {
+ return CommonUtil.DeserializeIntArray(originalPatternStr);
+ }
+
+ public bool HasBlockAt(int x, int y)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void ResetRotation()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void Rotate(RotationAngle angle)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void RotateClockwise()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void RotateCounterClockwise()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ private Sprite CreateDefaultSprite()
+ {
+ Texture2D texture = new Texture2D(1, 1);
+ texture.SetPixel(0, 0, Color.red);
+ texture.Apply();
+ return Sprite.Create(texture, new Rect(0, 0, 1, 1), new Vector2(0.5f, 0.5f), 1f);
+ }
+
+ // 仅限编辑器下使用
+ public void DrawShape()
+ {
+ transform.DestroyAllChildren();
+ _cellRenderers = null;
+
+ // 根据Width和Height,绘制Cells,Cell为SpriteRenderer
+ _cellRenderers = new SpriteRenderer[width, height];
+ var defaultSprite = CreateDefaultSprite();
+ for (int i = 0; i < width; i++)
+ {
+ for (int j = 0; j < height; j++)
+ {
+ var cell = new GameObject($"Cell_{i}_{j}");
+ var cellRenderer = cell.AddComponent();
+ cellRenderer.sprite = defaultSprite;
+ _cellRenderers[i, j] = cellRenderer;
+
+ cell.transform.parent = transform;
+ // 计算Cell应处的位置
+ var cellPosX = i * cellSize;
+ var cellPosY = j * cellSize;
+ cell.transform.localPosition = new Vector3(cellPosX, cellPosY, 0);
+ }
+ }
+
+ // 反序列化并处理
+ var pattern = CommonUtil.DeserializeIntArray(originalPatternStr);
+ // 先判断pattern的维度是否与width和height一致
+ if (pattern.GetLength(0) != width || pattern.GetLength(1) != height)
+ {
+ // 如果不一致,就不处理
+ Debug.LogWarning($"Pattern dimension mismatch: {pattern.GetLength(0)}x{pattern.GetLength(1)} != {width}x{height}");
+ return;
+ }
+ // 如果一致,就读取pattern,并设置对应的cell的SpriteRenderer是否激活
+ for (int i = 0; i < width; i++)
+ {
+ for (int j = 0; j < height; j++)
+ {
+ _cellRenderers[i, j].enabled = pattern[i, j] != 0;
+ }
+ }
+
+ // 更新碰撞体形状
+ UpdatePolygonCollider();
+ }
+
+ public void SaveShape()
+ {
+ // 如果_cellRenderers不为空,则序列化并保存
+ if (_cellRenderers != null)
+ {
+ var pattern = new int[width, height];
+ for (int i = 0; i < width; i++)
+ {
+ for (int j = 0; j < height; j++)
+ {
+ pattern[i, j] = _cellRenderers[i, j].enabled ? 1 : 0;
+ }
+ }
+ Debug.Log($"SaveShape: {CommonUtil.SerializeIntArray(pattern)}");
+ originalPatternStr = CommonUtil.SerializeIntArray(pattern);
+
+ // 保存后更新碰撞体
+ UpdatePolygonCollider();
+ }
+ }
+
+ ///
+ /// 根据originalPattern更新PolygonCollider2D的形状
+ ///
+ public void UpdatePolygonCollider()
+ {
+ var pattern = GetOriginalPattern();
+ if (pattern == null) return;
+
+ // 获取或添加PolygonCollider2D组件
+ PolygonCollider2D polygonCollider = GetComponent();
+ if (polygonCollider == null)
+ {
+ polygonCollider = gameObject.AddComponent();
+ }
+
+ // 生成多边形顶点
+ List vertices = GeneratePolygonVertices(pattern);
+
+ if (vertices.Count > 0)
+ {
+ // 设置多边形路径
+ polygonCollider.pathCount = 1;
+ polygonCollider.SetPath(0, vertices.ToArray());
+ }
+ else
+ {
+ // 如果没有有效格子,清除路径
+ polygonCollider.pathCount = 0;
+ }
+ }
+
+ ///
+ /// 根据pattern生成多边形顶点
+ ///
+ private List GeneratePolygonVertices(int[,] pattern)
+ {
+ List vertices = new List();
+
+ if (pattern == null || width <= 0 || height <= 0 || cellSize <= 0)
+ return vertices;
+
+ // 生成精确的外轮廓(只包含边界点)
+ vertices = GenerateOutlineVertices(pattern);
+
+ return vertices;
+ }
+
+ ///
+ /// 生成精确的外轮廓顶点(只包含边界点)
+ /// 使用Marching Squares算法的简化版本
+ ///
+ private List GenerateOutlineVertices(int[,] pattern)
+ {
+ List outlineVertices = new List();
+ HashSet visitedPoints = new HashSet();
+
+ // 遍历所有格子,找到边界点
+ for (int i = 0; i <= width; i++)
+ {
+ for (int j = 0; j <= height; j++)
+ {
+ // 检查这个角点是否在边界上
+ bool isBoundaryCorner = IsBoundaryCorner(pattern, i, j);
+
+ if (isBoundaryCorner)
+ {
+ // 计算角点的本地坐标
+ // cornerX 和 cornerY 是角点索引(0到width/height)
+ // 需要转换为格子的角点坐标
+ // 角点 (i, j) 对应格子 (i-0.5, j-0.5) 的角点位置
+ float x = (i - 0.5f) * cellSize;
+ float y = (j - 0.5f) * cellSize;
+
+ Vector2Int key = new Vector2Int(Mathf.RoundToInt(x * 100), Mathf.RoundToInt(y * 100));
+ if (!visitedPoints.Contains(key))
+ {
+ outlineVertices.Add(new Vector2(x, y));
+ visitedPoints.Add(key);
+ }
+ }
+ }
+ }
+
+ // 如果没有找到边界点,使用简单包围盒
+ if (outlineVertices.Count == 0)
+ {
+ return GenerateBoundingBox(pattern);
+ }
+
+ // 对顶点进行排序,形成闭合多边形
+ return OrderVerticesForPolygon(outlineVertices);
+ }
+
+ ///
+ /// 检查角点是否在边界上
+ ///
+ private bool IsBoundaryCorner(int[,] pattern, int cornerX, int cornerY)
+ {
+ // 角点位于四个格子的交汇处
+ // 检查周围四个格子的状态
+ bool topLeft = (cornerX > 0 && cornerY > 0) ? pattern[cornerX - 1, cornerY - 1] != 0 : false;
+ bool topRight = (cornerX < width && cornerY > 0) ? pattern[cornerX, cornerY - 1] != 0 : false;
+ bool bottomLeft = (cornerX > 0 && cornerY < height) ? pattern[cornerX - 1, cornerY] != 0 : false;
+ bool bottomRight = (cornerX < width && cornerY < height) ? pattern[cornerX, cornerY] != 0 : false;
+
+ // 如果四个格子状态不一致,说明这个角点在边界上
+ int filledCount = (topLeft ? 1 : 0) + (topRight ? 1 : 0) +
+ (bottomLeft ? 1 : 0) + (bottomRight ? 1 : 0);
+
+ // 边界角点:不是全部填充也不是全部空
+ return filledCount > 0 && filledCount < 4;
+ }
+
+
+ ///
+ /// 生成简单的包围盒(备用方法)
+ ///
+ private List GenerateBoundingBox(int[,] pattern)
+ {
+ List vertices = new List();
+
+ // 找到有效格子的边界
+ int minX = width, maxX = -1, minY = height, maxY = -1;
+ bool hasValidCell = false;
+
+ for (int i = 0; i < width; i++)
+ {
+ for (int j = 0; j < height; j++)
+ {
+ if (pattern[i, j] != 0)
+ {
+ hasValidCell = true;
+ minX = Mathf.Min(minX, i);
+ maxX = Mathf.Max(maxX, i);
+ minY = Mathf.Min(minY, j);
+ maxY = Mathf.Max(maxY, j);
+ }
+ }
+ }
+
+ if (!hasValidCell)
+ return vertices;
+
+ // 计算包围盒的四个角点(本地坐标)
+ float halfSize = cellSize / 2f;
+ float minXWorld = minX * cellSize - width * cellSize / 2f - halfSize;
+ float maxXWorld = (maxX + 1) * cellSize - width * cellSize / 2f + halfSize;
+ float minYWorld = minY * cellSize - height * cellSize / 2f - halfSize;
+ float maxYWorld = (maxY + 1) * cellSize - height * cellSize / 2f + halfSize;
+
+ // 按逆时针顺序添加顶点(Unity的PolygonCollider2D要求)
+ vertices.Add(new Vector2(minXWorld, minYWorld)); // 左下
+ vertices.Add(new Vector2(maxXWorld, minYWorld)); // 右下
+ vertices.Add(new Vector2(maxXWorld, maxYWorld)); // 右上
+ vertices.Add(new Vector2(minXWorld, maxYWorld)); // 左上
+
+ return vertices;
+ }
+
+ ///
+ /// 对顶点进行排序,形成闭合多边形
+ ///
+ private List OrderVerticesForPolygon(List vertices)
+ {
+ if (vertices.Count <= 2)
+ return vertices;
+
+ // 找到中心点
+ Vector2 center = Vector2.zero;
+ foreach (var v in vertices)
+ {
+ center += v;
+ }
+ center /= vertices.Count;
+
+ // 按角度排序(相对于中心点)
+ vertices.Sort((a, b) =>
+ {
+ float angleA = Mathf.Atan2(a.y - center.y, a.x - center.x);
+ float angleB = Mathf.Atan2(b.y - center.y, b.x - center.x);
+ if (angleA.CompareTo(angleB) != 0)
+ {
+ return angleA.CompareTo(angleB);
+ }
+
+ return (a - center).sqrMagnitude.CompareTo((b - center).sqrMagnitude);
+ });
+
+ return vertices;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockShape.cs.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockShape.cs.meta
new file mode 100644
index 000000000..0b9f4bd46
--- /dev/null
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockShape.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4be33b2e5baf96447a7df0d10cb22064
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockShapeDragger.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockShapeDragger.cs
new file mode 100644
index 000000000..5414fa0d1
--- /dev/null
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockShapeDragger.cs
@@ -0,0 +1,405 @@
+using System;
+using AibisDream.Framework;
+using UnityEngine;
+
+namespace AibisDream
+{
+ ///
+ /// 形状拖拽组件
+ /// 实现IBlockShapeDragger接口,处理形状的拖拽、吸附和放置逻辑
+ ///
+ [RequireComponent(typeof(BlockShape))]
+ [RequireComponent(typeof(EventTriggerEx))]
+ public class BlockShapeDragger : MonoBehaviour, IBlockShapeDragger
+ {
+ [Header("拖拽设置")]
+ [SerializeField] private bool isDraggable = true;
+ [SerializeField] private float snapDistance = 0.5f;
+ [SerializeField] private BlockPuzzleGrid targetGridComponent; // Unity组件引用
+
+ [Header("视觉反馈")]
+ [SerializeField] private Color snapColor = new Color(0f, 1f, 0f, 0.7f);
+ [SerializeField] private Color invalidColor = new Color(1f, 0f, 0f, 0.7f);
+ [SerializeField] private Color normalColor = Color.white;
+ [SerializeField] private float dragScale = 1.1f;
+
+ // 拖拽状态
+ private DragState _currentState = DragState.Idle;
+ private bool _isDragging = false;
+ private Vector3 _dragOffset;
+ private Vector3 _originalPosition;
+ private Vector3 _originalScale;
+ private int _originalSortingOrder;
+ private bool _isSnapping = false;
+ private int _snapGridX;
+ private int _snapGridY;
+
+ // 组件引用
+ private BlockShape _blockShape;
+ private SpriteRenderer _spriteRenderer;
+ private Collider2D _collider2D;
+
+ // 事件
+ public event Action OnDragStart;
+ public event Action OnDragUpdate;
+ public event Action OnDragEnd;
+ public event Action OnSnap;
+ public event Action OnUnsnap;
+
+ // 接口实现
+ public DragState CurrentState => _currentState;
+ public bool IsDraggable { get => isDraggable; set => isDraggable = value; }
+ public IBlockPuzzleGrid TargetGrid
+ {
+ get => targetGridComponent;
+ set => targetGridComponent = value as BlockPuzzleGrid;
+ }
+ public float SnapDistance { get => snapDistance; set => snapDistance = value; }
+
+ // 内部使用的网格引用
+ private IBlockPuzzleGrid targetGrid => targetGridComponent;
+
+ private void Awake()
+ {
+ _blockShape = GetComponent();
+ _spriteRenderer = GetComponent();
+ }
+
+ public void StartDrag()
+ {
+ if (!isDraggable || _isDragging) return;
+
+ _isDragging = true;
+ _currentState = DragState.Dragging;
+ _originalPosition = transform.position;
+ _originalScale = transform.localScale;
+
+ // 计算拖拽偏移量
+ Vector3 mouseWorldPos = GetMouseWorldPosition();
+ _dragOffset = transform.position - mouseWorldPos;
+
+ // 提升层级和缩放
+ if (_spriteRenderer != null)
+ {
+ _originalSortingOrder = _spriteRenderer.sortingOrder;
+ _spriteRenderer.sortingOrder = 100;
+ }
+
+ transform.localScale = _originalScale * dragScale;
+
+ OnDragStart?.Invoke(_blockShape);
+ }
+
+ public void UpdateDrag()
+ {
+ if (!_isDragging) return;
+
+ Vector3 mouseWorldPos = GetMouseWorldPosition();
+ Vector3 targetPosition = mouseWorldPos + _dragOffset;
+
+ // 检测是否靠近网格
+ if (targetGrid != null)
+ {
+ bool canSnap = CheckSnapToGrid(targetPosition, out Vector3 snapPos, out int gridX, out int gridY);
+
+ if (canSnap)
+ {
+ // 吸附到网格
+ transform.position = snapPos;
+ _isSnapping = true;
+ _snapGridX = gridX;
+ _snapGridY = gridY;
+ _currentState = DragState.Snapping;
+
+ // 重要:更新拖拽偏移量,使鼠标继续移动时能正确计算位置
+ _dragOffset = snapPos - mouseWorldPos;
+
+ // 检查是否可以放置
+ bool canPlace = CanPlaceAt(gridX, gridY);
+ ShowSnapPreview(true, canPlace);
+
+ OnSnap?.Invoke(_blockShape, snapPos, gridX, gridY);
+ }
+ else
+ {
+ // 自由拖拽
+ transform.position = targetPosition;
+ if (_isSnapping)
+ {
+ _isSnapping = false;
+ ShowSnapPreview(false, false);
+ OnUnsnap?.Invoke(_blockShape);
+ }
+ _currentState = DragState.Dragging;
+ }
+ }
+ else
+ {
+ // 没有网格,自由拖拽
+ transform.position = targetPosition;
+ _currentState = DragState.Dragging;
+ }
+
+ OnDragUpdate?.Invoke(_blockShape, transform.position);
+ }
+
+ public void EndDrag()
+ {
+ if (!_isDragging) return;
+
+ bool placed = false;
+
+ if (_isSnapping && targetGrid != null)
+ {
+ // 尝试放置到网格
+ if (CanPlaceAt(_snapGridX, _snapGridY))
+ {
+ if (TryPlaceOnGrid(_snapGridX, _snapGridY))
+ {
+ placed = true;
+ _currentState = DragState.Placed;
+ OnShapePlaced();
+ }
+ }
+ }
+
+ if (!placed)
+ {
+ // 返回原位置
+ transform.position = _originalPosition;
+ _currentState = DragState.Idle;
+ }
+
+ // 恢复原始状态
+ transform.localScale = _originalScale;
+ if (_spriteRenderer != null)
+ {
+ _spriteRenderer.sortingOrder = _originalSortingOrder;
+ }
+
+ ShowSnapPreview(false, false);
+
+ _isDragging = false;
+ _isSnapping = false;
+
+ OnDragEnd?.Invoke(_blockShape, placed);
+ }
+
+ public void CancelDrag()
+ {
+ if (!_isDragging) return;
+
+ transform.position = _originalPosition;
+ transform.localScale = _originalScale;
+ if (_spriteRenderer != null)
+ {
+ _spriteRenderer.sortingOrder = _originalSortingOrder;
+ }
+
+ ShowSnapPreview(false, false);
+
+ _isDragging = false;
+ _isSnapping = false;
+ _currentState = DragState.Idle;
+
+ OnDragEnd?.Invoke(_blockShape, false);
+ }
+
+ public bool CanPlaceAt(int gridX, int gridY)
+ {
+ if (targetGrid == null || _blockShape == null) return false;
+
+ Vector2Int[] blockPositions = _blockShape.GetBlockPositions();
+ if (blockPositions == null || blockPositions.Length == 0) return false;
+
+ // 形状的坐标系统:
+ // - GetBlockPositions() 返回的坐标中,(0, 0) 是形状的左上角
+ // - gridX, gridY 是形状左下角在网格中的位置
+ // - 需要将形状的相对坐标转换为网格坐标
+ foreach (var blockPos in blockPositions)
+ {
+ // 将形状的相对坐标转换为网格坐标(左下角为基准)
+ // 形状的 (0, 0) 对应网格的 (gridX, gridY + shape.Height - 1)
+ // 形状的 (i, j) 对应网格的 (gridX + i, gridY + shape.Height - 1 - j)
+ int checkX = gridX + blockPos.x;
+ int checkY = gridY + _blockShape.Height - 1 - blockPos.y;
+
+ if (!targetGrid.IsValidPosition(checkX, checkY) ||
+ !targetGrid.IsCellEmpty(checkX, checkY))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public bool GetSnapGridPosition(out int gridX, out int gridY)
+ {
+ if (_isSnapping)
+ {
+ gridX = _snapGridX;
+ gridY = _snapGridY;
+ return true;
+ }
+
+ gridX = 0;
+ gridY = 0;
+ return false;
+ }
+
+ ///
+ /// 检查是否可以吸附到网格
+ ///
+ private bool CheckSnapToGrid(Vector3 worldPos, out Vector3 snapPos, out int gridX, out int gridY)
+ {
+ snapPos = worldPos;
+ gridX = 0;
+ gridY = 0;
+
+ if (targetGrid == null) return false;
+
+ // 将世界坐标转换为网格坐标
+ // 注意:WorldToGrid 需要世界坐标在网格范围内才能返回true
+ // 但我们需要检查所有附近的网格单元格,不仅仅是当前所在的单元格
+ // 所以先尝试直接转换,如果失败则查找最近的网格单元格
+
+ int tempGridX, tempGridY;
+ bool inGrid = targetGrid.WorldToGrid(worldPos, out tempGridX, out tempGridY);
+
+ if (!inGrid)
+ {
+ // 如果不在网格内,尝试查找最近的网格单元格
+ // 计算最近的网格坐标
+ Vector3 localPos = worldPos - targetGrid.Origin;
+ tempGridX = Mathf.FloorToInt(localPos.x / targetGrid.CellSize);
+ tempGridY = Mathf.FloorToInt(localPos.y / targetGrid.CellSize);
+
+ // 检查是否在有效范围内
+ if (!targetGrid.IsValidPosition(tempGridX, tempGridY))
+ {
+ return false;
+ }
+ }
+
+ // 获取网格单元格中心的世界坐标
+ Vector3 gridCenter = targetGrid.GridToWorld(tempGridX, tempGridY);
+
+ // 计算距离
+ float distance = Vector3.Distance(worldPos, gridCenter);
+
+ if (distance <= snapDistance)
+ {
+ // 计算形状应该放置的网格位置
+ // 形状左下角对齐到网格单元格左下角
+ gridX = tempGridX;
+ gridY = tempGridY;
+
+ // 计算形状左下角的世界坐标
+ // 网格单元格左下角的世界坐标 = Origin + (gridX * CellSize, gridY * CellSize)
+ Vector3 gridBottomLeft = targetGrid.Origin + new Vector3(
+ gridX * targetGrid.CellSize,
+ gridY * targetGrid.CellSize,
+ 0
+ );
+
+ // 计算形状中心相对于形状左下角的偏移
+ // 形状的 pattern 中,(0, 0) 是左上角,所以形状左下角在 pattern 中的相对位置是 (0, height-1)
+ // 在形状的本地坐标系中(假设形状中心在 (0, 0)),形状左下角的位置是:
+ // localX = -width * cellSize / 2
+ // localY = -height * cellSize / 2 + (height-1) * cellSize = (height-1) * cellSize - height * cellSize / 2
+ // 形状中心相对于形状左下角的偏移 = (0, 0) - (localX, localY) = (width * cellSize / 2, height * cellSize / 2 - (height-1) * cellSize)
+
+ // 为了简化,我们假设形状的中心在形状的几何中心
+ // 形状中心相对于形状左下角的偏移 = (width * cellSize / 2, height * cellSize / 2)
+ // 但考虑到形状的 pattern 中 (0, 0) 是左上角,形状左下角在 pattern 中的位置是 (0, height-1)
+ // 所以形状中心相对于形状左下角的偏移 = (width * cellSize / 2, (height-1) * cellSize / 2)
+
+ // 实际上,我们需要根据形状的实际布局计算形状中心的位置
+ // 但为了简化,我们直接使用网格单元格左下角作为形状左下角的位置
+ // 然后根据形状的实际布局计算形状中心的位置
+
+ // 形状左下角对齐到网格单元格左下角
+ // 形状中心的世界坐标 = 网格单元格左下角的世界坐标 + 形状中心相对于形状左下角的偏移
+ // 使用网格的 CellSize,因为形状的 cellSize 应该与网格的 CellSize 相同
+ float shapeCenterOffsetX = _blockShape.Width * targetGrid.CellSize / 2f;
+ float shapeCenterOffsetY = (_blockShape.Height - 1) * targetGrid.CellSize / 2f;
+ snapPos = gridBottomLeft + new Vector3(shapeCenterOffsetX, shapeCenterOffsetY, 0);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// 尝试放置到网格
+ ///
+ /// 网格X坐标(形状左下角位置)
+ /// 网格Y坐标(形状左下角位置)
+ private bool TryPlaceOnGrid(int gridX, int gridY)
+ {
+ if (!CanPlaceAt(gridX, gridY)) return false;
+
+ Vector2Int[] blockPositions = _blockShape.GetBlockPositions();
+ if (blockPositions == null) return false;
+
+ // 形状的坐标系统:
+ // - GetBlockPositions() 返回的坐标中,(0, 0) 是形状的左上角
+ // - gridX, gridY 是形状左下角在网格中的位置
+ // - 需要将形状的相对坐标转换为网格坐标
+ foreach (var blockPos in blockPositions)
+ {
+ // 将形状的相对坐标转换为网格坐标(左下角为基准)
+ // 形状的 (0, 0) 对应网格的 (gridX, gridY + shape.Height - 1)
+ // 形状的 (i, j) 对应网格的 (gridX + i, gridY + shape.Height - 1 - j)
+ int x = gridX + blockPos.x;
+ int y = gridY + _blockShape.Height - 1 - blockPos.y;
+ targetGrid.SetCellState(x, y, GridCellState.Occupied);
+ }
+
+ return true;
+ }
+
+ ///
+ /// 显示吸附预览效果
+ ///
+ private void ShowSnapPreview(bool show, bool isValid)
+ {
+ Color previewColor = show ? (isValid ? snapColor : invalidColor) : normalColor;
+
+ // 更新主SpriteRenderer
+ if (_spriteRenderer != null)
+ {
+ _spriteRenderer.color = previewColor;
+ }
+ }
+
+ ///
+ /// 形状放置完成
+ ///
+ private void OnShapePlaced()
+ {
+ // 可以在这里添加放置后的逻辑
+ // 例如:禁用拖拽、播放动画等
+ isDraggable = false;
+ }
+
+ ///
+ /// 获取鼠标世界坐标
+ ///
+ private Vector3 GetMouseWorldPosition()
+ {
+ return CameraKit.GetMouseWorldPos(Input.mousePosition);
+ }
+
+ private void OnDisable()
+ {
+ if (_isDragging)
+ {
+ CancelDrag();
+ }
+ }
+ }
+}
+
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockShapeDragger.cs.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockShapeDragger.cs.meta
new file mode 100644
index 000000000..58d046e4f
--- /dev/null
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Class/BlockShapeDragger.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6ad01079e32d2314eb3719ead5f50ddb
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/GridVisualizer.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Class/GridVisualizer.cs
similarity index 97%
rename from Assets/Scripts/MiniGame/BlockPuzzle/GridVisualizer.cs
rename to Assets/Scripts/MiniGame/BlockPuzzle/Class/GridVisualizer.cs
index 1e6838497..b3708fbf9 100644
--- a/Assets/Scripts/MiniGame/BlockPuzzle/GridVisualizer.cs
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Class/GridVisualizer.cs
@@ -135,8 +135,8 @@ namespace AibisDream
for (int x = 0; x <= _grid.Width; x++)
{
CreateLine(
- _grid.GridToWorld(x, 0),
- _grid.GridToWorld(x, _grid.Height),
+ _grid.GridVerticesToWorld(x, 0)[0],
+ _grid.GridVerticesToWorld(x, _grid.Height)[0],
gridLineWidth,
gridLineColor
);
@@ -145,8 +145,8 @@ namespace AibisDream
for (int y = 0; y <= _grid.Height; y++)
{
CreateLine(
- _grid.GridToWorld(0, y),
- _grid.GridToWorld(_grid.Width, y),
+ _grid.GridVerticesToWorld(0, y)[0],
+ _grid.GridVerticesToWorld(_grid.Width, y)[0],
gridLineWidth,
gridLineColor
);
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/GridVisualizer.cs.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Class/GridVisualizer.cs.meta
similarity index 100%
rename from Assets/Scripts/MiniGame/BlockPuzzle/GridVisualizer.cs.meta
rename to Assets/Scripts/MiniGame/BlockPuzzle/Class/GridVisualizer.cs.meta
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/Class/PlacementValidator.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Class/PlacementValidator.cs
new file mode 100644
index 000000000..c07ab0a86
--- /dev/null
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Class/PlacementValidator.cs
@@ -0,0 +1,112 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace AibisDream
+{
+ ///
+ /// 放置验证器实现
+ /// 负责验证形状是否可以放置在指定位置
+ ///
+ public class PlacementValidator : IPlacementValidator
+ {
+ ///
+ /// 检查形状是否可以放置在指定位置
+ ///
+ /// 网格系统
+ /// 要放置的形状
+ /// 网格X坐标(形状左下角位置)
+ /// 网格Y坐标(形状左下角位置)
+ /// 放置验证结果
+ public PlacementResult CanPlace(IBlockPuzzleGrid grid, IBlockShape shape, int gridX, int gridY)
+ {
+ if (grid == null || shape == null)
+ {
+ return PlacementResult.InvalidPosition;
+ }
+
+ // 获取形状的所有格子位置(相对坐标,基于形状的本地坐标系)
+ Vector2Int[] blockPositions = shape.GetBlockPositions();
+ if (blockPositions == null || blockPositions.Length == 0)
+ {
+ return PlacementResult.InvalidPosition;
+ }
+
+ // 形状的坐标系统:
+ // - GetBlockPositions() 返回的坐标中,(0, 0) 是形状的左上角(在pattern数组中)
+ // - pattern[i, j] 中,i 是 x(从左到右),j 是 y(从上到下,j=0 是顶部)
+ // - gridX, gridY 是形状左下角在网格中的位置
+ // - 需要将形状的相对坐标转换为网格坐标
+ foreach (var blockPos in blockPositions)
+ {
+ // 将形状的相对坐标转换为网格坐标
+ // 形状的 (0, 0) 对应网格的 (gridX, gridY + shape.Height - 1)
+ // 形状的 (i, j) 对应网格的 (gridX + i, gridY + shape.Height - 1 - j)
+ int gridCellX = gridX + blockPos.x;
+ int gridCellY = gridY + shape.Height - 1 - blockPos.y;
+
+ // 检查是否超出边界
+ if (!grid.IsValidPosition(gridCellX, gridCellY))
+ {
+ return PlacementResult.OutOfBounds;
+ }
+
+ // 检查是否与已有块重叠
+ if (!grid.IsCellEmpty(gridCellX, gridCellY))
+ {
+ return PlacementResult.Overlap;
+ }
+ }
+
+ return PlacementResult.Success;
+ }
+
+ ///
+ /// 检查形状是否可以放置在指定位置(详细版本)
+ ///
+ /// 网格系统
+ /// 要放置的形状
+ /// 网格X坐标(形状左下角位置)
+ /// 网格Y坐标(形状左下角位置)
+ /// 失败原因(如果返回false)
+ /// 是否可以放置
+ public bool CanPlaceDetailed(IBlockPuzzleGrid grid, IBlockShape shape, int gridX, int gridY, out PlacementResult failureReason)
+ {
+ failureReason = CanPlace(grid, shape, gridX, gridY);
+ return failureReason == PlacementResult.Success;
+ }
+
+ ///
+ /// 获取形状在指定位置的所有占用格子坐标
+ ///
+ /// 形状
+ /// 网格X坐标(形状左下角位置)
+ /// 网格Y坐标(形状左下角位置)
+ /// 占用格子的网格坐标数组
+ public (int x, int y)[] GetOccupiedCells(IBlockShape shape, int gridX, int gridY)
+ {
+ if (shape == null)
+ {
+ return new (int x, int y)[0];
+ }
+
+ Vector2Int[] blockPositions = shape.GetBlockPositions();
+ if (blockPositions == null || blockPositions.Length == 0)
+ {
+ return new (int x, int y)[0];
+ }
+
+ List<(int x, int y)> occupiedCells = new List<(int x, int y)>();
+
+ foreach (var blockPos in blockPositions)
+ {
+ // 将形状的相对坐标转换为网格坐标(左下角为基准)
+ int gridCellX = gridX + blockPos.x;
+ int gridCellY = gridY + shape.Height - 1 - blockPos.y;
+ occupiedCells.Add((gridCellX, gridCellY));
+ }
+
+ return occupiedCells.ToArray();
+ }
+ }
+}
+
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/Class/PlacementValidator.cs.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Class/PlacementValidator.cs.meta
new file mode 100644
index 000000000..5333b0e2a
--- /dev/null
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Class/PlacementValidator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 826c5312f504d944c924549de95babe7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/Interface.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Interface.meta
new file mode 100644
index 000000000..e0a9cbce1
--- /dev/null
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Interface.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: abf557018657fa642a0d79187ed450eb
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/IBlockPuzzleGameLogic.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockPuzzleGameLogic.cs
similarity index 100%
rename from Assets/Scripts/MiniGame/BlockPuzzle/IBlockPuzzleGameLogic.cs
rename to Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockPuzzleGameLogic.cs
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/IBlockPuzzleGameLogic.cs.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockPuzzleGameLogic.cs.meta
similarity index 100%
rename from Assets/Scripts/MiniGame/BlockPuzzle/IBlockPuzzleGameLogic.cs.meta
rename to Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockPuzzleGameLogic.cs.meta
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/IBlockPuzzleGrid.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockPuzzleGrid.cs
similarity index 95%
rename from Assets/Scripts/MiniGame/BlockPuzzle/IBlockPuzzleGrid.cs
rename to Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockPuzzleGrid.cs
index 1005788f9..33fef4914 100644
--- a/Assets/Scripts/MiniGame/BlockPuzzle/IBlockPuzzleGrid.cs
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockPuzzleGrid.cs
@@ -117,6 +117,12 @@ namespace AibisDream
///
/// 总单元格数量
int GetTotalCellCount();
+
+ ///
+ /// 获取网格顶点信息
+ ///
+ /// 网格四个顶点位置
+ Vector3[] GridVerticesToWorld(int x, int y);
}
}
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/IBlockPuzzleGrid.cs.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockPuzzleGrid.cs.meta
similarity index 100%
rename from Assets/Scripts/MiniGame/BlockPuzzle/IBlockPuzzleGrid.cs.meta
rename to Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockPuzzleGrid.cs.meta
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/IBlockShape.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShape.cs
similarity index 98%
rename from Assets/Scripts/MiniGame/BlockPuzzle/IBlockShape.cs
rename to Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShape.cs
index f0e51bc91..19cc7635d 100644
--- a/Assets/Scripts/MiniGame/BlockPuzzle/IBlockShape.cs
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShape.cs
@@ -100,7 +100,7 @@ namespace AibisDream
/// 创建形状的副本
///
/// 形状副本
- IBlockShape Clone();
+ // IBlockShape Clone();
}
}
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/IBlockShape.cs.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShape.cs.meta
similarity index 100%
rename from Assets/Scripts/MiniGame/BlockPuzzle/IBlockShape.cs.meta
rename to Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShape.cs.meta
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShapeDragger.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShapeDragger.cs
new file mode 100644
index 000000000..37b1cfd9b
--- /dev/null
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShapeDragger.cs
@@ -0,0 +1,105 @@
+using UnityEngine;
+using System;
+
+namespace AibisDream
+{
+ ///
+ /// 拖拽状态
+ ///
+ public enum DragState
+ {
+ Idle, // 空闲
+ Dragging, // 拖拽中
+ Snapping, // 吸附中
+ Placed // 已放置
+ }
+
+ ///
+ /// 形状拖拽接口
+ /// 负责处理形状的拖拽、吸附和放置逻辑
+ ///
+ public interface IBlockShapeDragger
+ {
+ ///
+ /// 当前拖拽状态
+ ///
+ DragState CurrentState { get; }
+
+ ///
+ /// 是否可拖拽
+ ///
+ bool IsDraggable { get; set; }
+
+ ///
+ /// 目标网格
+ ///
+ IBlockPuzzleGrid TargetGrid { get; set; }
+
+ ///
+ /// 吸附距离阈值
+ ///
+ float SnapDistance { get; set; }
+
+ ///
+ /// 拖拽开始事件
+ ///
+ event Action OnDragStart;
+
+ ///
+ /// 拖拽更新事件
+ ///
+ event Action OnDragUpdate;
+
+ ///
+ /// 拖拽结束事件
+ ///
+ event Action OnDragEnd; // bool表示是否成功放置
+
+ ///
+ /// 吸附事件
+ ///
+ event Action OnSnap; // 形状, 位置, 网格X, 网格Y
+
+ ///
+ /// 取消吸附事件
+ ///
+ event Action OnUnsnap;
+
+ ///
+ /// 开始拖拽
+ ///
+ void StartDrag();
+
+ ///
+ /// 更新拖拽位置
+ ///
+ void UpdateDrag();
+
+ ///
+ /// 结束拖拽
+ ///
+ void EndDrag();
+
+ ///
+ /// 取消拖拽(返回原位置)
+ ///
+ void CancelDrag();
+
+ ///
+ /// 检查是否可以放置到指定位置
+ ///
+ /// 网格X坐标
+ /// 网格Y坐标
+ /// 是否可以放置
+ bool CanPlaceAt(int gridX, int gridY);
+
+ ///
+ /// 获取当前吸附的网格坐标
+ ///
+ /// 输出的网格X坐标
+ /// 输出的网格Y坐标
+ /// 是否正在吸附
+ bool GetSnapGridPosition(out int gridX, out int gridY);
+ }
+}
+
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShapeDragger.cs.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShapeDragger.cs.meta
new file mode 100644
index 000000000..5053d37b4
--- /dev/null
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShapeDragger.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5b2cbf04f1d9ef6448d01501a7861a46
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/IBlockShapeFactory.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShapeFactory.cs
similarity index 100%
rename from Assets/Scripts/MiniGame/BlockPuzzle/IBlockShapeFactory.cs
rename to Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShapeFactory.cs
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/IBlockShapeFactory.cs.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShapeFactory.cs.meta
similarity index 100%
rename from Assets/Scripts/MiniGame/BlockPuzzle/IBlockShapeFactory.cs.meta
rename to Assets/Scripts/MiniGame/BlockPuzzle/Interface/IBlockShapeFactory.cs.meta
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/IPlacementValidator.cs b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IPlacementValidator.cs
similarity index 82%
rename from Assets/Scripts/MiniGame/BlockPuzzle/IPlacementValidator.cs
rename to Assets/Scripts/MiniGame/BlockPuzzle/Interface/IPlacementValidator.cs
index 72ed54e51..8020246ce 100644
--- a/Assets/Scripts/MiniGame/BlockPuzzle/IPlacementValidator.cs
+++ b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IPlacementValidator.cs
@@ -22,8 +22,8 @@ namespace AibisDream
///
/// 网格系统
/// 要放置的形状
- /// 网格X坐标(形状左上角位置)
- /// 网格Y坐标(形状左上角位置)
+ /// 网格X坐标(形状左下角位置)
+ /// 网格Y坐标(形状左下角位置)
/// 放置验证结果
PlacementResult CanPlace(IBlockPuzzleGrid grid, IBlockShape shape, int gridX, int gridY);
@@ -32,8 +32,8 @@ namespace AibisDream
///
/// 网格系统
/// 要放置的形状
- /// 网格X坐标(形状左上角位置)
- /// 网格Y坐标(形状左上角位置)
+ /// 网格X坐标(形状左下角位置)
+ /// 网格Y坐标(形状左下角位置)
/// 失败原因(如果返回false)
/// 是否可以放置
bool CanPlaceDetailed(IBlockPuzzleGrid grid, IBlockShape shape, int gridX, int gridY, out PlacementResult failureReason);
@@ -42,10 +42,9 @@ namespace AibisDream
/// 获取形状在指定位置的所有占用格子坐标
///
/// 形状
- /// 网格X坐标(形状左上角位置)
- /// 网格Y坐标(形状左上角位置)
+ /// 网格X坐标(形状左下角位置)
+ /// 网格Y坐标(形状左下角位置)
/// 占用格子的网格坐标数组
(int x, int y)[] GetOccupiedCells(IBlockShape shape, int gridX, int gridY);
}
}
-
diff --git a/Assets/Scripts/MiniGame/BlockPuzzle/IPlacementValidator.cs.meta b/Assets/Scripts/MiniGame/BlockPuzzle/Interface/IPlacementValidator.cs.meta
similarity index 100%
rename from Assets/Scripts/MiniGame/BlockPuzzle/IPlacementValidator.cs.meta
rename to Assets/Scripts/MiniGame/BlockPuzzle/Interface/IPlacementValidator.cs.meta
diff --git a/Assets/Scripts/Utility/CommonUtil.cs b/Assets/Scripts/Utility/CommonUtil.cs
index 92550a5f8..1bdc69c5e 100644
--- a/Assets/Scripts/Utility/CommonUtil.cs
+++ b/Assets/Scripts/Utility/CommonUtil.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Text;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
@@ -7,6 +8,8 @@ using System.Threading.Tasks;
using Unity.VisualScripting;
using UnityEngine;
using Object = UnityEngine.Object;
+using System.Globalization;
+using UnityEditor;
namespace AibisDream.Utility
{
@@ -189,8 +192,21 @@ namespace AibisDream.Utility
return;
}
+ List children = new List();
foreach (Transform child in self)
{
+ children.Add(child);
+ }
+
+ foreach (var child in children)
+ {
+#if UNITY_EDITOR
+ if (!EditorApplication.isPlaying)
+ {
+ Object.DestroyImmediate(child.gameObject);
+ continue;
+ }
+#endif
Object.Destroy(child.gameObject);
}
}
@@ -243,5 +259,47 @@ namespace AibisDream.Utility
{
return Regex.Replace(str.Replace("
", "\n"), "[<|{].*?[>|}]", string.Empty);
}
+
+ public static int[,] DeserializeIntArray(string str)
+ {
+ if (string.IsNullOrWhiteSpace(str))
+ {
+ return new int[0, 0];
+ }
+
+ var array = str.Trim().Split(';');
+ var result = new int[array.Length, array[0].Split(',').Length];
+ for (int i = 0; i < array.Length; i++)
+ {
+ var row = array[i].Split(',');
+ for (int j = 0; j < row.Length; j++)
+ {
+ result[i, j] = int.Parse(row[j], NumberStyles.Integer, CultureInfo.InvariantCulture);
+ }
+ }
+ return result;
+ }
+
+ public static string SerializeIntArray(int[,] array)
+ {
+ var result = new StringBuilder();
+ for (int i = 0; i < array.GetLength(0); i++)
+ {
+ for (int j = 0; j < array.GetLength(1); j++)
+ {
+ result.Append(array[i, j]);
+ if (j < array.GetLength(1) - 1)
+ {
+ result.Append(',');
+ }
+ }
+
+ if (i < array.GetLength(0) - 1)
+ {
+ result.Append(';');
+ }
+ }
+ return result.ToString();
+ }
}
}
\ No newline at end of file