first commint
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
GeneratedPrefabs/*.prefab
|
||||||
|
found*.xlsx
|
||||||
|
__pycache__/
|
||||||
0
GeneratedPrefabs/.gitkeep
Normal file
0
GeneratedPrefabs/.gitkeep
Normal file
2924
Level51605.prefab
Normal file
2924
Level51605.prefab
Normal file
File diff suppressed because it is too large
Load Diff
374
Level90093.prefab
Normal file
374
Level90093.prefab
Normal file
@@ -0,0 +1,374 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &2259847937022306430
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 8028822463778547818}
|
||||||
|
- component: {fileID: 9018693869954649929}
|
||||||
|
- component: {fileID: 2817994186257587065}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Ground
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &8028822463778547818
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2259847937022306430}
|
||||||
|
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: 2898016089667496094}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1839735485 &9018693869954649929
|
||||||
|
Tilemap:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2259847937022306430}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_Tiles:
|
||||||
|
- first: {x: -1, y: -2, z: 0}
|
||||||
|
second:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_TileIndex: 0
|
||||||
|
m_TileSpriteIndex: 0
|
||||||
|
m_TileMatrixIndex: 0
|
||||||
|
m_TileColorIndex: 0
|
||||||
|
m_TileObjectToInstantiateIndex: 65535
|
||||||
|
dummyAlignment: 0
|
||||||
|
m_AllTileFlags: 1073741825
|
||||||
|
- first: {x: 5, y: 7, z: 0}
|
||||||
|
second:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_TileIndex: 0
|
||||||
|
m_TileSpriteIndex: 0
|
||||||
|
m_TileMatrixIndex: 0
|
||||||
|
m_TileColorIndex: 0
|
||||||
|
m_TileObjectToInstantiateIndex: 65535
|
||||||
|
dummyAlignment: 0
|
||||||
|
m_AllTileFlags: 1073741825
|
||||||
|
m_AnimatedTiles: {}
|
||||||
|
m_TileAssetArray:
|
||||||
|
- m_RefCount: 34
|
||||||
|
m_Data: {fileID: 11400000, guid: 9094a20fac3bd42409cbd3099244203d, type: 2}
|
||||||
|
m_TileSpriteArray:
|
||||||
|
- m_RefCount: 34
|
||||||
|
m_Data: {fileID: 21300000, guid: bd114e2f7df4b42a3b13cd40db799fc8, type: 3}
|
||||||
|
m_TileMatrixArray:
|
||||||
|
- m_RefCount: 34
|
||||||
|
m_Data:
|
||||||
|
e00: 1
|
||||||
|
e01: 0
|
||||||
|
e02: 0
|
||||||
|
e03: 0
|
||||||
|
e10: 0
|
||||||
|
e11: 1
|
||||||
|
e12: 0
|
||||||
|
e13: 0
|
||||||
|
e20: 0
|
||||||
|
e21: 0
|
||||||
|
e22: 1
|
||||||
|
e23: 0
|
||||||
|
e30: 0
|
||||||
|
e31: 0
|
||||||
|
e32: 0
|
||||||
|
e33: 1
|
||||||
|
m_TileColorArray:
|
||||||
|
- m_RefCount: 34
|
||||||
|
m_Data: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_TileObjectToInstantiateArray: []
|
||||||
|
m_AnimationFrameRate: 1
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_Origin: {x: -1, y: -2, z: 0}
|
||||||
|
m_Size: {x: 7, y: 10, z: 1}
|
||||||
|
m_TileAnchor: {x: 0.5, y: 0.5, z: 0}
|
||||||
|
m_TileOrientation: 0
|
||||||
|
m_TileOrientationMatrix:
|
||||||
|
e00: 1
|
||||||
|
e01: 0
|
||||||
|
e02: 0
|
||||||
|
e03: 0
|
||||||
|
e10: 0
|
||||||
|
e11: 1
|
||||||
|
e12: 0
|
||||||
|
e13: 0
|
||||||
|
e20: 0
|
||||||
|
e21: 0
|
||||||
|
e22: 1
|
||||||
|
e23: 0
|
||||||
|
e30: 0
|
||||||
|
e31: 0
|
||||||
|
e32: 0
|
||||||
|
e33: 1
|
||||||
|
--- !u!483693784 &2817994186257587065
|
||||||
|
TilemapRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2259847937022306430}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 0
|
||||||
|
m_ReceiveShadows: 0
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_StaticShadowCaster: 0
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 0
|
||||||
|
m_ReflectionProbeUsage: 0
|
||||||
|
m_RayTracingMode: 0
|
||||||
|
m_RayTraceProcedural: 0
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
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: 2
|
||||||
|
m_ChunkSize: {x: 32, y: 32, z: 32}
|
||||||
|
m_ChunkCullingBounds: {x: 0.0009765625, y: 0.2492969, z: 0}
|
||||||
|
m_MaxChunkCount: 16
|
||||||
|
m_MaxFrameAge: 16
|
||||||
|
m_SortOrder: 3
|
||||||
|
m_Mode: 1
|
||||||
|
m_DetectChunkCullingBounds: 0
|
||||||
|
m_MaskInteraction: 0
|
||||||
|
--- !u!1 &3331875946433896379
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 8602795678518186784}
|
||||||
|
- component: {fileID: 5346098299145066350}
|
||||||
|
- component: {fileID: 7780568001807741331}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Border
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &8602795678518186784
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3331875946433896379}
|
||||||
|
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: 2898016089667496094}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1839735485 &5346098299145066350
|
||||||
|
Tilemap:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3331875946433896379}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_Tiles:
|
||||||
|
- first: {x: -9, y: -22, z: 0}
|
||||||
|
second:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_TileIndex: 1
|
||||||
|
m_TileSpriteIndex: 1
|
||||||
|
m_TileMatrixIndex: 0
|
||||||
|
m_TileColorIndex: 0
|
||||||
|
m_TileObjectToInstantiateIndex: 65535
|
||||||
|
dummyAlignment: 0
|
||||||
|
m_AllTileFlags: 1073741825
|
||||||
|
m_AnimatedTiles: {}
|
||||||
|
m_TileAssetArray:
|
||||||
|
- m_RefCount: 22
|
||||||
|
m_Data: {fileID: 11400000, guid: c4ba7c97e3d29474283a4c87aa927fe3, type: 2}
|
||||||
|
- m_RefCount: 78
|
||||||
|
m_Data: {fileID: 11400000, guid: 9094a20fac3bd42409cbd3099244203d, type: 2}
|
||||||
|
- m_RefCount: 124
|
||||||
|
m_Data: {fileID: 11400000, guid: 7016a7036b066477abe0d150ae55aa83, type: 2}
|
||||||
|
m_TileSpriteArray:
|
||||||
|
- m_RefCount: 22
|
||||||
|
m_Data: {fileID: 21300000, guid: d3a70cda4c7bc4d60bd25cf11bb9a158, type: 3}
|
||||||
|
- m_RefCount: 78
|
||||||
|
m_Data: {fileID: 21300000, guid: bd114e2f7df4b42a3b13cd40db799fc8, type: 3}
|
||||||
|
- m_RefCount: 124
|
||||||
|
m_Data: {fileID: 21300000, guid: f6c8ef238c4e142aeac514b536a5fc56, type: 3}
|
||||||
|
m_TileMatrixArray:
|
||||||
|
- m_RefCount: 224
|
||||||
|
m_Data:
|
||||||
|
e00: 1
|
||||||
|
e01: 0
|
||||||
|
e02: 0
|
||||||
|
e03: 0
|
||||||
|
e10: 0
|
||||||
|
e11: 1
|
||||||
|
e12: 0
|
||||||
|
e13: 0
|
||||||
|
e20: 0
|
||||||
|
e21: 0
|
||||||
|
e22: 1
|
||||||
|
e23: 0
|
||||||
|
e30: 0
|
||||||
|
e31: 0
|
||||||
|
e32: 0
|
||||||
|
e33: 1
|
||||||
|
m_TileColorArray:
|
||||||
|
- m_RefCount: 224
|
||||||
|
m_Data: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_TileObjectToInstantiateArray: []
|
||||||
|
m_AnimationFrameRate: 1
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_Origin: {x: -22, y: -22, z: 0}
|
||||||
|
m_Size: {x: 24, y: 23, z: 1}
|
||||||
|
m_TileAnchor: {x: 0.5, y: 0.5, z: 0}
|
||||||
|
m_TileOrientation: 0
|
||||||
|
m_TileOrientationMatrix:
|
||||||
|
e00: 1
|
||||||
|
e01: 0
|
||||||
|
e02: 0
|
||||||
|
e03: 0
|
||||||
|
e10: 0
|
||||||
|
e11: 1
|
||||||
|
e12: 0
|
||||||
|
e13: 0
|
||||||
|
e20: 0
|
||||||
|
e21: 0
|
||||||
|
e22: 1
|
||||||
|
e23: 0
|
||||||
|
e30: 0
|
||||||
|
e31: 0
|
||||||
|
e32: 0
|
||||||
|
e33: 1
|
||||||
|
--- !u!483693784 &7780568001807741331
|
||||||
|
TilemapRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3331875946433896379}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 0
|
||||||
|
m_ReceiveShadows: 0
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_StaticShadowCaster: 0
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 0
|
||||||
|
m_ReflectionProbeUsage: 0
|
||||||
|
m_RayTracingMode: 0
|
||||||
|
m_RayTraceProcedural: 0
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
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: 2
|
||||||
|
m_ChunkSize: {x: 32, y: 32, z: 32}
|
||||||
|
m_ChunkCullingBounds: {x: 0.0009765625, y: 0.2574414, z: 0}
|
||||||
|
m_MaxChunkCount: 16
|
||||||
|
m_MaxFrameAge: 16
|
||||||
|
m_SortOrder: 3
|
||||||
|
m_Mode: 1
|
||||||
|
m_DetectChunkCullingBounds: 0
|
||||||
|
m_MaskInteraction: 0
|
||||||
|
--- !u!1 &6718232195078379098
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 2898016089667496094}
|
||||||
|
- component: {fileID: 3111389448725951018}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Level51605
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &2898016089667496094
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6718232195078379098}
|
||||||
|
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:
|
||||||
|
- {fileID: 8028822463778547818}
|
||||||
|
- {fileID: 8602795678518186784}
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!156049354 &3111389448725951018
|
||||||
|
Grid:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 6718232195078379098}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CellSize: {x: 1, y: 0.5, z: 1}
|
||||||
|
m_CellGap: {x: 0, y: 0, z: 0}
|
||||||
|
m_CellLayout: 3
|
||||||
|
m_CellSwizzle: 0
|
||||||
80
README.md
Normal file
80
README.md
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# 关卡生成流水线
|
||||||
|
|
||||||
|
这个仓库包含一套从 Excel 数据自动生成 Unity Prefab 与 C# 关卡字典的脚本。核心流程由 `run_pipeline.py` 串联完成。
|
||||||
|
|
||||||
|
## 环境准备
|
||||||
|
- Python 3.9 及以上(在 Windows PowerShell 上测试)
|
||||||
|
- Excel 源文件(默认 `global.xlsx`)并符合既定的表格结构
|
||||||
|
- 依赖库:`pandas`、`openpyxl`
|
||||||
|
|
||||||
|
安装依赖:
|
||||||
|
```powershell
|
||||||
|
python -m pip install pandas openpyxl
|
||||||
|
```
|
||||||
|
|
||||||
|
## 快速上手
|
||||||
|
1. 将 Excel 文件(如 `global.xlsx`)与脚本放在同一目录。
|
||||||
|
2. 确认模板 Prefab(默认 `Level80317.prefab`)存在。
|
||||||
|
3. 在 PowerShell 中运行:
|
||||||
|
```powershell
|
||||||
|
python .\run_pipeline.py --excel global.xlsx --sheet Sheet2 --start-i 80316
|
||||||
|
```
|
||||||
|
若不传 `--steps`,脚本会依次执行全部三步(抽取数据 → 生成 C# → 生成 Prefab)。
|
||||||
|
可通过 `--steps 1,2` 指定只运行前两步。
|
||||||
|
|
||||||
|
### 输出文件
|
||||||
|
- `found_*.xlsx`:步骤一扫描得到的坐标数据
|
||||||
|
- `generated_levels.cs`:步骤二生成的关卡字典代码
|
||||||
|
- `GeneratedPrefabs/LevelXXXX.prefab`:步骤三输出的 Prefab 文件
|
||||||
|
|
||||||
|
## 三个步骤详解
|
||||||
|
- **步骤 1(`read_excel.py`)**:
|
||||||
|
- 自动补齐 Excel 第一列空白的地图号(从 `--start-i` 指定的值起)。
|
||||||
|
- 在 B~AA 列扫描“币”、“p”、“v”等标记,提取坐标并输出成 `found_币.xlsx`、`found_p.xlsx`、`found_v.xlsx`。
|
||||||
|
- 识别颜色填充的格子,将绿色写入 `found_方块.xlsx`,蓝色/橙色/粉色分别写入 `found_water.xlsx`、`found_wall.xlsx`、`found_jump.xlsx`。
|
||||||
|
|
||||||
|
- **步骤 2(`write_code.py`)**:
|
||||||
|
- 读取步骤一输出的多张 Excel,按地图号分组。
|
||||||
|
- 生成 `Spawn` 配置,写入 `generated_levels.cs`。可在命令行通过 `--output-levels` 指定输出文件名。
|
||||||
|
|
||||||
|
- **步骤 3(`make_prefab.py`)**:
|
||||||
|
- 以模板 Prefab 为基础,逐个地图替换 `Ground`、`Border` 的 `m_Tiles` 块。
|
||||||
|
- 若无对应坐标,自动写成 `m_Tiles: {}`。
|
||||||
|
- Prefab 输出到 `GeneratedPrefabs/` 目录。
|
||||||
|
|
||||||
|
## 脚本内可调参数
|
||||||
|
- **`read_excel.py`**
|
||||||
|
- `columns_to_preview`:控制调试输出中预览的列数,必要时减少日志噪音。
|
||||||
|
- `GREEN_COLORS` / `BLUE_COLORS` / `ORANGE_COLORS` / `PINK_COLORS`:决定颜色识别的十六进制值,适配其他调色方案时需更新。
|
||||||
|
- `find_cells_with_currency_xlsx()` 的 `search_term` 及 `suffixes`:用于识别不同物件符号,扩展至新标记时修改此处。
|
||||||
|
- Excel 列段 `grid_columns`(默认 B~AA):若表格布局变化或列数扩展需同步调整。
|
||||||
|
- **`write_code.py`**
|
||||||
|
- `FILE_P` / `FILE_V` / `FILE_COIN`:输入文件名常量,可在命令行前覆盖或直接修改常量。
|
||||||
|
- `LEVEL_PATH`:Prefab 在 Unity 项目的目标路径模板,适配其他资源组织结构时更新。
|
||||||
|
- `generate_spawn_line()` 内的 `path` 与 `direction_map`:指定生成的 Prefab 引用与方向映射,新角色或朝向枚举需在此扩展。
|
||||||
|
- `boundary` 默认值与 `Spawn` 字段列表:若未来关卡数据结构变化,应相应调整模板字符串。
|
||||||
|
- **`make_prefab.py`**
|
||||||
|
- 顶部 `EXCEL_PATH`、`TEMPLATE_PREFAB`、`OUTPUT_DIR`:分别控制输入表格、Prefab 模板和输出目录。
|
||||||
|
- `TILE_LINE` 模板中的 `m_TileIndex` / `m_TileSpriteIndex`:当新的 TileAsset/Sprite 索引出现时需同步修改。
|
||||||
|
- `replace_tilemap_by_gameobject_name()` 查找的 GameObject 名称(默认 `Ground`、`Border`):若模板结构不同,调整调用处的名称。
|
||||||
|
- Border 层 `tile_index` 分配:当前约定 water=2、wall=0、jump=1,结合实际 Tilemap 资源可重新定义。
|
||||||
|
|
||||||
|
> **适配新任务**:如果未来 Excel 的 sheet 名称、列布局或颜色含义有变化,请同步更新上述常量/映射,必要时扩展 `read_excel.py` 对应的字段重命名逻辑(`df.rename(...)`)。Prefab 模板层级或 Tilemap 名称变更时,也需更新 `make_prefab.py` 中的搜索关键字与 Tile 生成规则。
|
||||||
|
|
||||||
|
## 常用参数
|
||||||
|
- `--excel`: Excel 文件名。
|
||||||
|
- `--sheet`: Sheet 名称。
|
||||||
|
- `--start-i`: 填补地图号的起始值。
|
||||||
|
- `--template`: Prefab 模板路径。
|
||||||
|
- `--steps`: 需要执行的步骤序号(例如 `1,3` 或 `all`)。
|
||||||
|
- `--output-levels`: 生成的 C# 文件名。
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
- **提示缺少某个库**:再次执行依赖安装命令。
|
||||||
|
- **没有生成 Prefab**:确认 `found_方块.xlsx` 存在且列名与脚本对应;模板 Prefab 名称无误。
|
||||||
|
- **Tile 未正确替换**:检查模板中 `Ground`、`Border` 的 GameObject 名称以及 `m_Tiles` 的结构是否发生变化。
|
||||||
|
|
||||||
|
更多命令行参数说明可执行:
|
||||||
|
```powershell
|
||||||
|
python .\run_pipeline.py --help
|
||||||
|
```
|
||||||
100
detect_filled_cells.py
Normal file
100
detect_filled_cells.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
import csv
|
||||||
|
from openpyxl import load_workbook
|
||||||
|
from openpyxl.styles import PatternFill
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_color_hex_from_colorobj(color):
|
||||||
|
"""Try to resolve an openpyxl Color object to ARGB hex string.
|
||||||
|
Returns None if cannot resolve.
|
||||||
|
"""
|
||||||
|
if color is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# direct rgb (may be 'FF00B050' or '00B050')
|
||||||
|
rgb = getattr(color, "rgb", None)
|
||||||
|
if rgb:
|
||||||
|
s = str(rgb)
|
||||||
|
if len(s) == 6:
|
||||||
|
s = "FF" + s
|
||||||
|
return s.upper()
|
||||||
|
|
||||||
|
# try indexed (some workbooks may use indexed colors)
|
||||||
|
idx = getattr(color, "indexed", None) or getattr(color, "index", None)
|
||||||
|
if idx is not None:
|
||||||
|
try:
|
||||||
|
# openpyxl does not always expose a global list here; fallback to None
|
||||||
|
return f"INDEXED{int(idx)}"
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
theme = getattr(color, "theme", None)
|
||||||
|
if theme is not None:
|
||||||
|
try:
|
||||||
|
return f"THEME{int(theme)}"
|
||||||
|
except Exception:
|
||||||
|
return str(theme)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def detect_colored_cells(xlsx_path, sheet_name=None, write_csv=None):
|
||||||
|
"""Detect cells with fills (pattern fills) and return list of dicts:
|
||||||
|
[{'coordinate':'A1','row':1,'col':1,'value':..., 'color': 'FF00B050', 'fill_type': 'solid'}]
|
||||||
|
|
||||||
|
If write_csv is provided (path), write the results to that CSV.
|
||||||
|
"""
|
||||||
|
wb = load_workbook(xlsx_path, data_only=False)
|
||||||
|
ws = wb[sheet_name] if sheet_name else wb.active
|
||||||
|
|
||||||
|
results = []
|
||||||
|
min_row = ws.min_row or 1
|
||||||
|
max_row = ws.max_row or 1
|
||||||
|
min_col = ws.min_column or 1
|
||||||
|
max_col = ws.max_column or 1
|
||||||
|
|
||||||
|
for row in ws.iter_rows(min_row=min_row, max_row=max_row, min_col=min_col, max_col=max_col):
|
||||||
|
for cell in row:
|
||||||
|
fill = cell.fill
|
||||||
|
if fill is None:
|
||||||
|
continue
|
||||||
|
# patternType for PatternFill is fill.fill_type or fill.patternType depending on openpyxl version
|
||||||
|
pattern = getattr(fill, "patternType", None) or getattr(fill, "fill_type", None)
|
||||||
|
if pattern in (None, 'none'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
fg = getattr(fill, 'fgColor', None) or getattr(fill, 'start_color', None) or getattr(fill, 'bgColor', None)
|
||||||
|
color = resolve_color_hex_from_colorobj(fg)
|
||||||
|
if color is None or color.startswith("FF") is False:
|
||||||
|
continue
|
||||||
|
|
||||||
|
results.append({
|
||||||
|
'coordinate': cell.coordinate,
|
||||||
|
'row': cell.row,
|
||||||
|
'col': cell.column,
|
||||||
|
'value': cell.value,
|
||||||
|
'color': color,
|
||||||
|
'fill_type': pattern,
|
||||||
|
})
|
||||||
|
|
||||||
|
if write_csv:
|
||||||
|
keys = ['coordinate', 'row', 'col', 'value', 'color', 'fill_type']
|
||||||
|
with open(write_csv, 'w', newline='', encoding='utf-8') as f:
|
||||||
|
writer = csv.DictWriter(f, fieldnames=keys)
|
||||||
|
writer.writeheader()
|
||||||
|
for r in results:
|
||||||
|
writer.writerow(r)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import argparse
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--xlsx', '-x', required=True, help='Path to xlsx file')
|
||||||
|
parser.add_argument('--sheet', '-s', default=None, help='Sheet name (optional)')
|
||||||
|
parser.add_argument('--csv', '-c', default=None, help='Write results to CSV')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
res = detect_colored_cells(args.xlsx, sheet_name=args.sheet, write_csv=args.csv)
|
||||||
|
for r in res:
|
||||||
|
print(r)
|
||||||
543
generated_levels.cs
Normal file
543
generated_levels.cs
Normal file
@@ -0,0 +1,543 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Platformer.Controller;
|
||||||
|
using UnityEngine;
|
||||||
|
using static Platformer.Manager.GameManager;
|
||||||
|
|
||||||
|
namespace Platformer.Core
|
||||||
|
{
|
||||||
|
public class Levels90001
|
||||||
|
{
|
||||||
|
public Dictionary<int, Level> Levels = new Dictionary<int, Level>()
|
||||||
|
{
|
||||||
|
|
||||||
|
// 关卡 90091
|
||||||
|
{ 90091,new Level(){LevelID = 90091,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(3,3,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.South}, // Map 90091
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,3,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.East}, // Map 90091
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,3,z (Map 90091)
|
||||||
|
new Spawn(){position = new Vector3Int(-3,-6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,-6,z (Map 90091)
|
||||||
|
new Spawn(){position = new Vector3Int(0,-4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置0,-4,z (Map 90091)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90091.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90092
|
||||||
|
{ 90092,new Level(){LevelID = 90092,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(0,-4,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.West}, // Map 90092
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-1,-3,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.South}, // Map 90092
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-4,2,z (Map 90092)
|
||||||
|
new Spawn(){position = new Vector3Int(3,6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,6,z (Map 90092)
|
||||||
|
new Spawn(){position = new Vector3Int(4,2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置4,2,z (Map 90092)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90092.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90093
|
||||||
|
{ 90093,new Level(){LevelID = 90093,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-7,6,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.West}, // Map 90093
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-7,5,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.North}, // Map 90093
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-7,-3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-7,-3,z (Map 90093)
|
||||||
|
new Spawn(){position = new Vector3Int(6,-3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置6,-3,z (Map 90093)
|
||||||
|
new Spawn(){position = new Vector3Int(7,3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置7,3,z (Map 90093)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90093.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90094
|
||||||
|
{ 90094,new Level(){LevelID = 90094,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(0,2,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.West}, // Map 90094
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(3,-7,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.West}, // Map 90094
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,-4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,-4,z (Map 90094)
|
||||||
|
new Spawn(){position = new Vector3Int(0,-7,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置0,-7,z (Map 90094)
|
||||||
|
new Spawn(){position = new Vector3Int(3,-4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,-4,z (Map 90094)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90094.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90095
|
||||||
|
{ 90095,new Level(){LevelID = 90095,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,2,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.West}, // Map 90095
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-2,2,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.West}, // Map 90095
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-1,6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-1,6,z (Map 90095)
|
||||||
|
new Spawn(){position = new Vector3Int(2,4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置2,4,z (Map 90095)
|
||||||
|
new Spawn(){position = new Vector3Int(2,-3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置2,-3,z (Map 90095)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90095.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90096
|
||||||
|
{ 90096,new Level(){LevelID = 90096,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,-2,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.South}, // Map 90096
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,3,z (Map 90096)
|
||||||
|
new Spawn(){position = new Vector3Int(-3,0,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,0,z (Map 90096)
|
||||||
|
new Spawn(){position = new Vector3Int(0,4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置0,4,z (Map 90096)
|
||||||
|
new Spawn(){position = new Vector3Int(0,3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置0,3,z (Map 90096)
|
||||||
|
new Spawn(){position = new Vector3Int(0,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置0,1,z (Map 90096)
|
||||||
|
new Spawn(){position = new Vector3Int(0,0,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置0,0,z (Map 90096)
|
||||||
|
new Spawn(){position = new Vector3Int(3,4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,4,z (Map 90096)
|
||||||
|
new Spawn(){position = new Vector3Int(3,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,1,z (Map 90096)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90096.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90097
|
||||||
|
{ 90097,new Level(){LevelID = 90097,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(0,7,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.East}, // Map 90097
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(1,7,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.West}, // Map 90097
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,-3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-4,-3,z (Map 90097)
|
||||||
|
new Spawn(){position = new Vector3Int(0,-3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置0,-3,z (Map 90097)
|
||||||
|
new Spawn(){position = new Vector3Int(4,-3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置4,-3,z (Map 90097)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90097.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90098
|
||||||
|
{ 90098,new Level(){LevelID = 90098,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,-2,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.East}, // Map 90098
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,1,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.South}, // Map 90098
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(0,6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置0,6,z (Map 90098)
|
||||||
|
new Spawn(){position = new Vector3Int(3,4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,4,z (Map 90098)
|
||||||
|
new Spawn(){position = new Vector3Int(3,2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,2,z (Map 90098)
|
||||||
|
new Spawn(){position = new Vector3Int(3,0,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,0,z (Map 90098)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90098.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90099
|
||||||
|
{ 90099,new Level(){LevelID = 90099,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(0,-4,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.West}, // Map 90099
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-5,3,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.South}, // Map 90099
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,4,z (Map 90099)
|
||||||
|
new Spawn(){position = new Vector3Int(-1,7,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-1,7,z (Map 90099)
|
||||||
|
new Spawn(){position = new Vector3Int(1,7,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置1,7,z (Map 90099)
|
||||||
|
new Spawn(){position = new Vector3Int(3,4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,4,z (Map 90099)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90099.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90100
|
||||||
|
{ 90100,new Level(){LevelID = 90100,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(3,1,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.North}, // Map 90100
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(2,2,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.North}, // Map 90100
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,7,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,7,z (Map 90100)
|
||||||
|
new Spawn(){position = new Vector3Int(-3,4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,4,z (Map 90100)
|
||||||
|
new Spawn(){position = new Vector3Int(2,8,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置2,8,z (Map 90100)
|
||||||
|
new Spawn(){position = new Vector3Int(2,6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置2,6,z (Map 90100)
|
||||||
|
new Spawn(){position = new Vector3Int(2,4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置2,4,z (Map 90100)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90100.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90101
|
||||||
|
{ 90101,new Level(){LevelID = 90101,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(1,-5,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.West}, // Map 90101
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-1,1,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.West}, // Map 90101
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,3,z (Map 90101)
|
||||||
|
new Spawn(){position = new Vector3Int(1,4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置1,4,z (Map 90101)
|
||||||
|
new Spawn(){position = new Vector3Int(1,2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置1,2,z (Map 90101)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90101.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90102
|
||||||
|
{ 90102,new Level(){LevelID = 90102,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(0,1,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.South}, // Map 90102
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-6,0,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.East}, // Map 90102
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-6,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-6,1,z (Map 90102)
|
||||||
|
new Spawn(){position = new Vector3Int(0,-6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置0,-6,z (Map 90102)
|
||||||
|
new Spawn(){position = new Vector3Int(6,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置6,1,z (Map 90102)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90102.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90103
|
||||||
|
{ 90103,new Level(){LevelID = 90103,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,4,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.South}, // Map 90103
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,8,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.West}, // Map 90103
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,7,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-4,7,z (Map 90103)
|
||||||
|
new Spawn(){position = new Vector3Int(1,2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置1,2,z (Map 90103)
|
||||||
|
new Spawn(){position = new Vector3Int(2,6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置2,6,z (Map 90103)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90103.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90104
|
||||||
|
{ 90104,new Level(){LevelID = 90104,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-2,6,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.South}, // Map 90104
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-1,3,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.East}, // Map 90104
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-2,3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-2,3,z (Map 90104)
|
||||||
|
new Spawn(){position = new Vector3Int(3,-2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,-2,z (Map 90104)
|
||||||
|
new Spawn(){position = new Vector3Int(5,-4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置5,-4,z (Map 90104)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90104.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90105
|
||||||
|
{ 90105,new Level(){LevelID = 90105,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,6,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.South}, // Map 90105
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,5,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.East}, // Map 90105
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,1,z (Map 90105)
|
||||||
|
new Spawn(){position = new Vector3Int(0,6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置0,6,z (Map 90105)
|
||||||
|
new Spawn(){position = new Vector3Int(0,-3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置0,-3,z (Map 90105)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90105.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90106
|
||||||
|
{ 90106,new Level(){LevelID = 90106,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-8,1,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.South}, // Map 90106
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,1,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.South}, // Map 90106
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-5,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-5,1,z (Map 90106)
|
||||||
|
new Spawn(){position = new Vector3Int(-4,5,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-4,5,z (Map 90106)
|
||||||
|
new Spawn(){position = new Vector3Int(-1,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-1,1,z (Map 90106)
|
||||||
|
new Spawn(){position = new Vector3Int(1,5,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置1,5,z (Map 90106)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90106.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90107
|
||||||
|
{ 90107,new Level(){LevelID = 90107,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-2,1,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.South}, // Map 90107
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(6,0,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.East}, // Map 90107
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(1,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置1,1,z (Map 90107)
|
||||||
|
new Spawn(){position = new Vector3Int(5,-1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置5,-1,z (Map 90107)
|
||||||
|
new Spawn(){position = new Vector3Int(5,-5,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置5,-5,z (Map 90107)
|
||||||
|
new Spawn(){position = new Vector3Int(6,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置6,1,z (Map 90107)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90107.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90108
|
||||||
|
{ 90108,new Level(){LevelID = 90108,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,1,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.South}, // Map 90108
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(4,-1,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.East}, // Map 90108
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(0,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置0,1,z (Map 90108)
|
||||||
|
new Spawn(){position = new Vector3Int(2,-4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置2,-4,z (Map 90108)
|
||||||
|
new Spawn(){position = new Vector3Int(3,-6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,-6,z (Map 90108)
|
||||||
|
new Spawn(){position = new Vector3Int(4,0,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置4,0,z (Map 90108)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90108.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90109
|
||||||
|
{ 90109,new Level(){LevelID = 90109,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,-5,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.South}, // Map 90109
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(3,0,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.West}, // Map 90109
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-2,0,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-2,0,z (Map 90109)
|
||||||
|
new Spawn(){position = new Vector3Int(2,3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置2,3,z (Map 90109)
|
||||||
|
new Spawn(){position = new Vector3Int(4,5,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置4,5,z (Map 90109)
|
||||||
|
new Spawn(){position = new Vector3Int(4,-5,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置4,-5,z (Map 90109)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90109.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90110
|
||||||
|
{ 90110,new Level(){LevelID = 90110,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(2,-4,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.North}, // Map 90110
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(3,1,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.West}, // Map 90110
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,6,z (Map 90110)
|
||||||
|
new Spawn(){position = new Vector3Int(-3,0,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,0,z (Map 90110)
|
||||||
|
new Spawn(){position = new Vector3Int(-3,-1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,-1,z (Map 90110)
|
||||||
|
new Spawn(){position = new Vector3Int(3,6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,6,z (Map 90110)
|
||||||
|
new Spawn(){position = new Vector3Int(3,0,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,0,z (Map 90110)
|
||||||
|
new Spawn(){position = new Vector3Int(3,-1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,-1,z (Map 90110)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90110.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90111
|
||||||
|
{ 90111,new Level(){LevelID = 90111,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,1,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.West}, // Map 90111
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,-2,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.North}, // Map 90111
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(1,2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置1,2,z (Map 90111)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90111.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90112
|
||||||
|
{ 90112,new Level(){LevelID = 90112,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,3,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.West}, // Map 90112
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-1,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-1,1,z (Map 90112)
|
||||||
|
new Spawn(){position = new Vector3Int(1,-1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置1,-1,z (Map 90112)
|
||||||
|
new Spawn(){position = new Vector3Int(3,-3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,-3,z (Map 90112)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90112.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90113
|
||||||
|
{ 90113,new Level(){LevelID = 90113,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(4,4,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.South}, // Map 90113
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,-4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,-4,z (Map 90113)
|
||||||
|
new Spawn(){position = new Vector3Int(-1,-2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-1,-2,z (Map 90113)
|
||||||
|
new Spawn(){position = new Vector3Int(1,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置1,1,z (Map 90113)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90113.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90114
|
||||||
|
{ 90114,new Level(){LevelID = 90114,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-6,2,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.West}, // Map 90114
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-6,3,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.West}, // Map 90114
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-6,-2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-6,-2,z (Map 90114)
|
||||||
|
new Spawn(){position = new Vector3Int(-2,3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-2,3,z (Map 90114)
|
||||||
|
new Spawn(){position = new Vector3Int(1,2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置1,2,z (Map 90114)
|
||||||
|
new Spawn(){position = new Vector3Int(3,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,1,z (Map 90114)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90114.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90115
|
||||||
|
{ 90115,new Level(){LevelID = 90115,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-5,0,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.West}, // Map 90115
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-5,1,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.North}, // Map 90115
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,0,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,0,z (Map 90115)
|
||||||
|
new Spawn(){position = new Vector3Int(4,0,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置4,0,z (Map 90115)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90115.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90116
|
||||||
|
{ 90116,new Level(){LevelID = 90116,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(6,3,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.West}, // Map 90116
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(6,-7,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.East}, // Map 90116
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-9,-4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-9,-4,z (Map 90116)
|
||||||
|
new Spawn(){position = new Vector3Int(-8,-5,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-8,-5,z (Map 90116)
|
||||||
|
new Spawn(){position = new Vector3Int(-7,-6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-7,-6,z (Map 90116)
|
||||||
|
new Spawn(){position = new Vector3Int(6,-6,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置6,-6,z (Map 90116)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90116.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90117
|
||||||
|
{ 90117,new Level(){LevelID = 90117,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-5,5,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.North}, // Map 90117
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,4,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.East}, // Map 90117
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-3,2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-3,2,z (Map 90117)
|
||||||
|
new Spawn(){position = new Vector3Int(-2,9,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-2,9,z (Map 90117)
|
||||||
|
new Spawn(){position = new Vector3Int(3,2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,2,z (Map 90117)
|
||||||
|
new Spawn(){position = new Vector3Int(5,9,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置5,9,z (Map 90117)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90117.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90118
|
||||||
|
{ 90118,new Level(){LevelID = 90118,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(2,0,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.East}, // Map 90118
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(2,-1,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.East}, // Map 90118
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(1,-9,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置1,-9,z (Map 90118)
|
||||||
|
new Spawn(){position = new Vector3Int(3,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,1,z (Map 90118)
|
||||||
|
new Spawn(){position = new Vector3Int(3,0,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置3,0,z (Map 90118)
|
||||||
|
new Spawn(){position = new Vector3Int(4,2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置4,2,z (Map 90118)
|
||||||
|
new Spawn(){position = new Vector3Int(4,1,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置4,1,z (Map 90118)
|
||||||
|
new Spawn(){position = new Vector3Int(5,3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置5,3,z (Map 90118)
|
||||||
|
new Spawn(){position = new Vector3Int(5,2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置5,2,z (Map 90118)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90118.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90119
|
||||||
|
{ 90119,new Level(){LevelID = 90119,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,4,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.North}, // Map 90119
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,5,0),path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = Direction.East}, // Map 90119
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-1,10,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-1,10,z (Map 90119)
|
||||||
|
new Spawn(){position = new Vector3Int(-1,4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-1,4,z (Map 90119)
|
||||||
|
new Spawn(){position = new Vector3Int(4,10,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置4,10,z (Map 90119)
|
||||||
|
new Spawn(){position = new Vector3Int(4,4,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置4,4,z (Map 90119)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90119.prefab"}},
|
||||||
|
|
||||||
|
// 关卡 90120
|
||||||
|
{ 90120,new Level(){LevelID = 90120,spawns = new List<Spawn>(){
|
||||||
|
|
||||||
|
// --- Player Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(0,-1,0),path = "Assets/Prefabs/Player.prefab", playerDirection = Direction.North}, // Map 90120
|
||||||
|
|
||||||
|
// --- Vehicle Spawns ---
|
||||||
|
|
||||||
|
// --- Coin Spawns ---
|
||||||
|
new Spawn(){position = new Vector3Int(-4,-2,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-4,-2,z (Map 90120)
|
||||||
|
new Spawn(){position = new Vector3Int(-1,3,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置-1,3,z (Map 90120)
|
||||||
|
new Spawn(){position = new Vector3Int(1,-5,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置1,-5,z (Map 90120)
|
||||||
|
new Spawn(){position = new Vector3Int(4,0,0),path = "Assets/Prefabs/Prop_star.prefab",},//金币位置4,0,z (Map 90120)
|
||||||
|
},
|
||||||
|
boundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
levelPath = "Assets/Prefabs/Level/Level90120.prefab"}},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
BIN
global.xlsx
Normal file
BIN
global.xlsx
Normal file
Binary file not shown.
305
inspect_cells.py
Normal file
305
inspect_cells.py
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
import openpyxl
|
||||||
|
import sys
|
||||||
|
try:
|
||||||
|
from openpyxl.styles.colors import COLOR_INDEX
|
||||||
|
except Exception:
|
||||||
|
COLOR_INDEX = []
|
||||||
|
|
||||||
|
FILE = 'global.xlsx'
|
||||||
|
SHEET = 'Sheet1'
|
||||||
|
CELLS = ['P547', 'X458']
|
||||||
|
|
||||||
|
try:
|
||||||
|
wb = openpyxl.load_workbook(FILE, data_only=False)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to open {FILE}: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if SHEET in wb.sheetnames:
|
||||||
|
ws = wb[SHEET]
|
||||||
|
else:
|
||||||
|
print(f"Sheet '{SHEET}' not found. Available sheets: {wb.sheetnames}. Using active sheet '{wb.active.title}'.")
|
||||||
|
ws = wb.active
|
||||||
|
|
||||||
|
|
||||||
|
def color_info(c):
|
||||||
|
if c is None:
|
||||||
|
return None
|
||||||
|
info = {}
|
||||||
|
for attr in ('type','rgb','indexed','index','theme','tint','auto'):
|
||||||
|
try:
|
||||||
|
info[attr] = getattr(c, attr, None)
|
||||||
|
except Exception as e:
|
||||||
|
info[attr] = f"<error: {e}>"
|
||||||
|
# 归一化尝试:把常见的 tuple/list/int/bytes 等 rgb 表示转换为可读字符串
|
||||||
|
info['normalized'], info['original_repr'] = normalize_color_value(c)
|
||||||
|
try:
|
||||||
|
kind, value = safe_resolve_color(c)
|
||||||
|
info['resolved'] = {'kind': kind, 'value': value}
|
||||||
|
except Exception as e:
|
||||||
|
info['resolved'] = {'error': str(e)}
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_color_value(val):
|
||||||
|
"""
|
||||||
|
尝试把颜色对象或多种表示归一化为一个字符串(优先 ARGB hex),并返回 (normalized_str_or_None, original_repr).
|
||||||
|
支持:
|
||||||
|
- openpyxl Color 对象 (会尝试读取 .rgb/.indexed/.index/.theme/.tint)
|
||||||
|
- str (如 'FF00B050', '#FF00B050', 'rgb(0,176,80)')
|
||||||
|
- tuple/list of ints (r,g,b) 或 (r,g,b,a)
|
||||||
|
- int (如 16711680)
|
||||||
|
- bytes
|
||||||
|
任何不能解析的值将返回 (None, repr(val)).
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def as_argb_from_rgb_tuple(tpl):
|
||||||
|
try:
|
||||||
|
comps = list(tpl)
|
||||||
|
if len(comps) == 3:
|
||||||
|
r, g, b = comps
|
||||||
|
a = 255
|
||||||
|
elif len(comps) >= 4:
|
||||||
|
r, g, b, a = comps[:4]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
return "{0:02X}{1:02X}{2:02X}{3:02X}".format(a, r, g, b)
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"as_argb_from_rgb_tuple failed: {e} for {tpl}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# If it's an openpyxl Color-like object, try attributes first
|
||||||
|
try:
|
||||||
|
# guard: if object has .rgb/.indexed etc, prefer those
|
||||||
|
if hasattr(val, 'rgb') or hasattr(val, 'indexed') or hasattr(val, 'index') or hasattr(val, 'theme'):
|
||||||
|
# try .rgb
|
||||||
|
try:
|
||||||
|
rgb = getattr(val, 'rgb', None)
|
||||||
|
if rgb:
|
||||||
|
s = str(rgb)
|
||||||
|
# strip leading '#' if present
|
||||||
|
if s.startswith('#'):
|
||||||
|
s = s[1:]
|
||||||
|
if len(s) == 6:
|
||||||
|
s = 'FF' + s
|
||||||
|
return (s.upper(), repr(rgb))
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"error reading .rgb: {e}")
|
||||||
|
|
||||||
|
# try indexed/index mapping (best-effort)
|
||||||
|
try:
|
||||||
|
idx = getattr(val, 'indexed', None) or getattr(val, 'index', None)
|
||||||
|
if idx is not None:
|
||||||
|
try:
|
||||||
|
idx_int = int(idx)
|
||||||
|
# map using openpyxl COLOR_INDEX if available
|
||||||
|
if COLOR_INDEX and 0 <= idx_int < len(COLOR_INDEX):
|
||||||
|
hexv = COLOR_INDEX[idx_int]
|
||||||
|
if hexv:
|
||||||
|
hexs = hexv.upper()
|
||||||
|
if len(hexs) == 6:
|
||||||
|
hexs = 'FF' + hexs
|
||||||
|
return (hexs, repr(idx_int))
|
||||||
|
return (f'INDEXED_{idx_int}', repr(idx_int))
|
||||||
|
except Exception:
|
||||||
|
return (f'INDEXED_{idx}', repr(idx))
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"error reading .indexed/index: {e}")
|
||||||
|
|
||||||
|
# theme
|
||||||
|
try:
|
||||||
|
theme = getattr(val, 'theme', None)
|
||||||
|
if theme is not None:
|
||||||
|
return (f'THEME_{theme}', repr(theme))
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"error reading .theme: {e}")
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
# not an object we can introspect
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Primitive types
|
||||||
|
# str
|
||||||
|
try:
|
||||||
|
if isinstance(val, str):
|
||||||
|
s = val.strip()
|
||||||
|
if s.startswith('#'):
|
||||||
|
s = s[1:]
|
||||||
|
# If it contains 'rgb(' leave as-is
|
||||||
|
if s.lower().startswith('rgb('):
|
||||||
|
return (s, repr(val))
|
||||||
|
# if hex-like
|
||||||
|
hexchars = ''.join(ch for ch in s if ch.isalnum())
|
||||||
|
if all(c in '0123456789ABCDEFabcdef' for c in hexchars) and len(hexchars) in (6,8):
|
||||||
|
if len(hexchars) == 6:
|
||||||
|
hexchars = 'FF' + hexchars
|
||||||
|
return (hexchars.upper(), repr(val))
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"error normalizing str val: {e}")
|
||||||
|
|
||||||
|
# tuple/list
|
||||||
|
try:
|
||||||
|
if isinstance(val, (tuple, list)):
|
||||||
|
# might be like (r,g,b) or (r,g,b,a)
|
||||||
|
normalized = as_argb_from_rgb_tuple(val)
|
||||||
|
if normalized:
|
||||||
|
return (normalized, repr(val))
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"error normalizing sequence val: {e}")
|
||||||
|
|
||||||
|
# int (maybe packed RGB)
|
||||||
|
try:
|
||||||
|
if isinstance(val, int):
|
||||||
|
v = val & 0xFFFFFFFF
|
||||||
|
# If it's 24-bit or 32-bit
|
||||||
|
if v <= 0xFFFFFF:
|
||||||
|
# assume RGB
|
||||||
|
r = (v >> 16) & 0xFF
|
||||||
|
g = (v >> 8) & 0xFF
|
||||||
|
b = v & 0xFF
|
||||||
|
a = 255
|
||||||
|
else:
|
||||||
|
a = (v >> 24) & 0xFF
|
||||||
|
r = (v >> 16) & 0xFF
|
||||||
|
g = (v >> 8) & 0xFF
|
||||||
|
b = v & 0xFF
|
||||||
|
return ("{0:02X}{1:02X}{2:02X}{3:02X}".format(a, r, g, b), repr(val))
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"error normalizing int val: {e}")
|
||||||
|
|
||||||
|
# bytes
|
||||||
|
try:
|
||||||
|
if isinstance(val, (bytes, bytearray)):
|
||||||
|
hexs = val.hex().upper()
|
||||||
|
if len(hexs) == 6:
|
||||||
|
hexs = 'FF' + hexs
|
||||||
|
return (hexs, repr(val))
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"error normalizing bytes val: {e}")
|
||||||
|
|
||||||
|
# fallback: try to stringify, but filter out known library error messages
|
||||||
|
try:
|
||||||
|
r = repr(val)
|
||||||
|
if 'MUST BE OF TYPE' in r.upper() or 'VALUES MUST' in r.upper():
|
||||||
|
return (None, r)
|
||||||
|
return (r, r)
|
||||||
|
except Exception:
|
||||||
|
return (None, '<unrepresentable>')
|
||||||
|
from openpyxl.styles import colors as _colors
|
||||||
|
|
||||||
|
def safe_resolve_color(fg):
|
||||||
|
# 返回 (kind, value):
|
||||||
|
# - ('argb', 'FF00B050') 或 ('indexed', 35) 或 ('theme', 2) 或 (None, None)
|
||||||
|
try:
|
||||||
|
if fg is None:
|
||||||
|
return (None, None)
|
||||||
|
except Exception:
|
||||||
|
return (None, None)
|
||||||
|
|
||||||
|
# 1) rgb 字符串
|
||||||
|
try:
|
||||||
|
rgb = getattr(fg, 'rgb', None)
|
||||||
|
if rgb:
|
||||||
|
s = str(rgb)
|
||||||
|
if s.startswith('#'):
|
||||||
|
s = s[1:]
|
||||||
|
if len(s) == 6:
|
||||||
|
s = 'FF' + s
|
||||||
|
return ('argb', s.upper())
|
||||||
|
except Exception:
|
||||||
|
# 读取 rgb 可能抛异常,记录并继续回退
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 2) indexed / index -> 尝试映射到 hex
|
||||||
|
try:
|
||||||
|
idx = getattr(fg, 'indexed', None) or getattr(fg, 'index', None)
|
||||||
|
if idx is not None:
|
||||||
|
try:
|
||||||
|
idx_int = int(idx)
|
||||||
|
# COLOR_INDEX 是 openpyxl 内置的索引颜色表
|
||||||
|
hexv = None
|
||||||
|
try:
|
||||||
|
hexv = _colors.COLOR_INDEX[idx_int] # e.g. '00FF00'
|
||||||
|
except Exception:
|
||||||
|
hexv = None
|
||||||
|
if hexv:
|
||||||
|
hexs = hexv.upper()
|
||||||
|
if len(hexs) == 6:
|
||||||
|
hexs = 'FF' + hexs
|
||||||
|
return ('argb', hexs)
|
||||||
|
else:
|
||||||
|
return ('indexed', idx_int)
|
||||||
|
except Exception:
|
||||||
|
return ('indexed', idx)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 3) theme
|
||||||
|
try:
|
||||||
|
theme = getattr(fg, 'theme', None)
|
||||||
|
if theme is not None:
|
||||||
|
return ('theme', theme)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return (None, None)
|
||||||
|
for coord in CELLS:
|
||||||
|
print(f"--- {coord} ---")
|
||||||
|
cell = ws[coord]
|
||||||
|
print('coordinate:', cell.coordinate)
|
||||||
|
print('row, column:', cell.row, cell.column)
|
||||||
|
print('value repr:', repr(cell.value))
|
||||||
|
print('data_type:', getattr(cell, 'data_type', None))
|
||||||
|
print('is_date:', getattr(cell, 'is_date', None))
|
||||||
|
print('number_format:', getattr(cell, 'number_format', None))
|
||||||
|
print('font:', cell.font)
|
||||||
|
try:
|
||||||
|
font_attrs = { 'name': cell.font.name, 'size': cell.font.sz, 'bold': cell.font.bold, 'italic': cell.font.italic, 'color': getattr(cell.font, 'color', None) }
|
||||||
|
except Exception as e:
|
||||||
|
font_attrs = {'error': str(e)}
|
||||||
|
print('font attributes:', font_attrs)
|
||||||
|
|
||||||
|
fill = getattr(cell, 'fill', None)
|
||||||
|
print('fill obj:', type(fill))
|
||||||
|
if fill is not None:
|
||||||
|
try:
|
||||||
|
print(' patternType:', getattr(fill, 'patternType', None))
|
||||||
|
except Exception as e:
|
||||||
|
print(' patternType error:', e)
|
||||||
|
fg = getattr(fill, 'fgColor', None)
|
||||||
|
bg = getattr(fill, 'bgColor', None)
|
||||||
|
print(' fgColor:', color_info(fg))
|
||||||
|
print(' bgColor:', color_info(bg))
|
||||||
|
fg_kind, fg_value = safe_resolve_color(fg)
|
||||||
|
bg_kind, bg_value = safe_resolve_color(bg)
|
||||||
|
print(' fgColor resolved:', {'kind': fg_kind, 'value': fg_value})
|
||||||
|
print(' bgColor resolved:', {'kind': bg_kind, 'value': bg_value})
|
||||||
|
else:
|
||||||
|
print(' fill is None')
|
||||||
|
|
||||||
|
print('alignment:', cell.alignment)
|
||||||
|
print('border:', cell.border)
|
||||||
|
print('protection:', cell.protection)
|
||||||
|
try:
|
||||||
|
comment = cell.comment.text if cell.comment else None
|
||||||
|
except Exception as e:
|
||||||
|
comment = f'<error reading comment: {e}>'
|
||||||
|
print('comment:', comment)
|
||||||
|
try:
|
||||||
|
hyperlink = cell.hyperlink.target if cell.hyperlink else None
|
||||||
|
except Exception as e:
|
||||||
|
hyperlink = f'<error reading hyperlink: {e}>'
|
||||||
|
print('hyperlink:', hyperlink)
|
||||||
|
|
||||||
|
# raw repr of the cell object's __dict__ if available
|
||||||
|
try:
|
||||||
|
d = {k: repr(v) for k,v in cell.__dict__.items()}
|
||||||
|
print('cell.__dict__ keys:', list(cell.__dict__.keys()))
|
||||||
|
except Exception:
|
||||||
|
d = None
|
||||||
|
# don't print full dict to avoid huge output, but show if present
|
||||||
|
print()
|
||||||
|
|
||||||
|
print('Done')
|
||||||
201
make_prefab.py
Normal file
201
make_prefab.py
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
import pandas as pd
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# ============= 配置 =============
|
||||||
|
|
||||||
|
# Excel 路径
|
||||||
|
EXCEL_PATH = "found_方块.xlsx" # 根据你的实际文件名改
|
||||||
|
|
||||||
|
# 作为模板的 prefab(就是你贴出来那份,包含 Ground / Border / Grid)
|
||||||
|
TEMPLATE_PREFAB = "Level90093.prefab" # 根据实际文件名改
|
||||||
|
OLD_LEVEL_NAME = "Level51605" # 模板 prefab 中的旧关卡名
|
||||||
|
|
||||||
|
# 输出目录
|
||||||
|
OUTPUT_DIR = Path("GeneratedPrefabs")
|
||||||
|
OUTPUT_DIR.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
# ============= Tile 行模板 =============
|
||||||
|
|
||||||
|
# 使用 Ground 里那种 tile(m_TileIndex = 0, m_TileSpriteIndex = 0)
|
||||||
|
# 注意:花括号 {{ }} 是为了在 format 之后输出字面上的 { }
|
||||||
|
TILE_LINE = """ - first: {{x: {x}, y: {y}, z: 0}}
|
||||||
|
second:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_TileIndex: {tile_index}
|
||||||
|
m_TileSpriteIndex: {sprite_index}
|
||||||
|
m_TileMatrixIndex: 0
|
||||||
|
m_TileColorIndex: 0
|
||||||
|
m_TileObjectToInstantiateIndex: 65535
|
||||||
|
dummyAlignment: 0
|
||||||
|
m_AllTileFlags: 1073741825
|
||||||
|
"""
|
||||||
|
|
||||||
|
# ============= 工具函数 =============
|
||||||
|
|
||||||
|
def load_template_text() -> str:
|
||||||
|
"""读取整份 prefab 模板文本"""
|
||||||
|
return Path(TEMPLATE_PREFAB).read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def replace_level_name(text: str, map_no) -> str:
|
||||||
|
"""
|
||||||
|
把根节点名字从 Level80317 改为 Level{map_no}
|
||||||
|
(只替换这一行)
|
||||||
|
"""
|
||||||
|
# 注意:只替换一次,避免误伤别的地方
|
||||||
|
old = f"m_Name: {OLD_LEVEL_NAME}"
|
||||||
|
new = f"m_Name: Level{int(map_no)}"
|
||||||
|
return text.replace(old, new, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_tiles_block(coords):
|
||||||
|
"""
|
||||||
|
根据坐标列表生成 m_Tiles: 区块(只包含 m_Tiles 本身,不包括 m_AnimatedTiles 之后的内容)
|
||||||
|
coords: [(x, y, tile_index, sprite_index), ...]
|
||||||
|
"""
|
||||||
|
block = " m_Tiles:\n"
|
||||||
|
for item in coords:
|
||||||
|
if len(item) == 2:
|
||||||
|
x, y = item
|
||||||
|
tile_index = 0
|
||||||
|
sprite_index = 0
|
||||||
|
else:
|
||||||
|
x, y, tile_index, sprite_index = item
|
||||||
|
block += TILE_LINE.format(x=int(x), y=int(y), tile_index=int(tile_index), sprite_index=int(sprite_index))
|
||||||
|
return block
|
||||||
|
|
||||||
|
|
||||||
|
def replace_ground_tiles(text: str, coords) -> str:
|
||||||
|
"""
|
||||||
|
只修改 Ground Tilemap 的 m_Tiles: 列表
|
||||||
|
Border 的 m_Tiles: {} 不动
|
||||||
|
"""
|
||||||
|
# 找到第一个 m_Tiles:(就是 Ground 的)
|
||||||
|
# 本函数保持向后兼容性:如果模板中有多个 Tilemap,默认替换第一个 m_Tiles 区块(通常是 Ground)
|
||||||
|
pos = text.find(" m_Tiles:")
|
||||||
|
if pos == -1:
|
||||||
|
raise RuntimeError("在模板 prefab 中找不到 'm_Tiles:'。")
|
||||||
|
|
||||||
|
pos2 = text.find(" m_AnimatedTiles:", pos)
|
||||||
|
if pos2 == -1:
|
||||||
|
raise RuntimeError("在模板 prefab 中找不到 'm_AnimatedTiles:' 用来截断。")
|
||||||
|
|
||||||
|
before = text[:pos]
|
||||||
|
after = text[pos2:]
|
||||||
|
tiles_block = generate_tiles_block(coords)
|
||||||
|
return before + tiles_block + after
|
||||||
|
|
||||||
|
|
||||||
|
def replace_tilemap_by_gameobject_name(text: str, gameobject_name: str, tiles_coords) -> str:
|
||||||
|
"""
|
||||||
|
根据 GameObject 名称(m_Name)找到紧随其后的第一个 m_Tiles: 块并替换内容。
|
||||||
|
tiles_coords: list of (x,y,tile_index,sprite_index) 或 (x,y)
|
||||||
|
"""
|
||||||
|
lower_text = text.lower()
|
||||||
|
target_name = f"m_name: {gameobject_name.lower()}"
|
||||||
|
name_pos = lower_text.find(target_name)
|
||||||
|
if name_pos == -1:
|
||||||
|
raise RuntimeError(f"在 prefab 中找不到 GameObject 名称: {gameobject_name}")
|
||||||
|
|
||||||
|
tiles_pos = lower_text.find(" m_tiles:", name_pos)
|
||||||
|
if tiles_pos == -1:
|
||||||
|
raise RuntimeError(f"在 prefab 中找不到 {gameobject_name} 对应的 m_Tiles: 区块")
|
||||||
|
|
||||||
|
animated_pos = lower_text.find(" m_animatedtiles:", tiles_pos)
|
||||||
|
if animated_pos == -1:
|
||||||
|
raise RuntimeError("找不到 m_AnimatedTiles 来截断。")
|
||||||
|
|
||||||
|
before = text[:tiles_pos]
|
||||||
|
after = text[animated_pos:]
|
||||||
|
|
||||||
|
if tiles_coords:
|
||||||
|
new_tiles_block = generate_tiles_block(tiles_coords)
|
||||||
|
else:
|
||||||
|
new_tiles_block = " m_Tiles: {}\n"
|
||||||
|
|
||||||
|
return before + new_tiles_block + after
|
||||||
|
|
||||||
|
|
||||||
|
# ============= 主逻辑 =============
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# 读取 Excel
|
||||||
|
df = pd.read_excel(EXCEL_PATH)
|
||||||
|
|
||||||
|
# 根据你的表头改名(如果不完全一样,请把左边字符串改成实际表头)
|
||||||
|
df = df.rename(columns={
|
||||||
|
"地图号 (Map No)": "map",
|
||||||
|
"X坐标 (X No)": "x",
|
||||||
|
"Y坐标 (Y No)": "y",
|
||||||
|
})
|
||||||
|
|
||||||
|
template_text = load_template_text()
|
||||||
|
|
||||||
|
# 尝试读取 border 相关的 found 文件(可选)
|
||||||
|
water_df = None
|
||||||
|
wall_df = None
|
||||||
|
jump_df = None
|
||||||
|
if Path("found_water.xlsx").exists():
|
||||||
|
water_df = pd.read_excel("found_water.xlsx")
|
||||||
|
water_df = water_df.rename(columns={"地图号 (Map No)": "map", "X坐标 (X No)": "x", "Y坐标 (Y No)": "y"})
|
||||||
|
if Path("found_wall.xlsx").exists():
|
||||||
|
wall_df = pd.read_excel("found_wall.xlsx")
|
||||||
|
wall_df = wall_df.rename(columns={"地图号 (Map No)": "map", "X坐标 (X No)": "x", "Y坐标 (Y No)": "y"})
|
||||||
|
if Path("found_jump.xlsx").exists():
|
||||||
|
jump_df = pd.read_excel("found_jump.xlsx")
|
||||||
|
jump_df = jump_df.rename(columns={"地图号 (Map No)": "map", "X坐标 (X No)": "x", "Y坐标 (Y No)": "y"})
|
||||||
|
|
||||||
|
# 按地图号分组,一个 Map 生成一个 prefab
|
||||||
|
for map_no, group in df.groupby("map"):
|
||||||
|
ground_coords = list(zip(group["x"], group["y"]))
|
||||||
|
|
||||||
|
# 1) 换根节点名字 LevelXXXX
|
||||||
|
text_with_name = replace_level_name(template_text, map_no)
|
||||||
|
|
||||||
|
new_text = text_with_name
|
||||||
|
|
||||||
|
# 2) 用当前地图的坐标替换 Ground 的 m_Tiles 区块
|
||||||
|
# 构建 (x,y,tile_index,sprite_index) 列表,Ground 使用索引 0/0(和原模板一致)
|
||||||
|
ground_tiles = [(int(x), int(y), 0, 0) for x, y in ground_coords]
|
||||||
|
if ground_tiles:
|
||||||
|
try:
|
||||||
|
new_text = replace_tilemap_by_gameobject_name(new_text, "Ground", ground_tiles)
|
||||||
|
except Exception as e:
|
||||||
|
# 回退到旧的替换方式
|
||||||
|
new_text = replace_ground_tiles(new_text, ground_coords)
|
||||||
|
|
||||||
|
# 3) 对 Border 图层,合并 water/wall/jump(如果存在)并替换
|
||||||
|
border_tiles = []
|
||||||
|
# water -> m_TileIndex:2, m_TileSpriteIndex:2
|
||||||
|
if water_df is not None:
|
||||||
|
wg = water_df[water_df['map'] == map_no]
|
||||||
|
border_tiles += [(int(x), int(y), 2, 2) for x, y in zip(wg['x'], wg['y'])]
|
||||||
|
# wall -> m_TileIndex:0, m_TileSpriteIndex:0
|
||||||
|
if wall_df is not None:
|
||||||
|
wg = wall_df[wall_df['map'] == map_no]
|
||||||
|
border_tiles += [(int(x), int(y), 0, 0) for x, y in zip(wg['x'], wg['y'])]
|
||||||
|
# jump -> m_TileIndex:1, m_TileSpriteIndex:1
|
||||||
|
if jump_df is not None:
|
||||||
|
wg = jump_df[jump_df['map'] == map_no]
|
||||||
|
border_tiles += [(int(x), int(y), 1, 1) for x, y in zip(wg['x'], wg['y'])]
|
||||||
|
|
||||||
|
if border_tiles:
|
||||||
|
try:
|
||||||
|
new_text = replace_tilemap_by_gameobject_name(new_text, "Border", border_tiles)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"警告:替换 Border 时出错: {e}")
|
||||||
|
else:
|
||||||
|
# 没有 border 坐标,清空 Border 图层
|
||||||
|
try:
|
||||||
|
new_text = replace_tilemap_by_gameobject_name(new_text, "Border", [])
|
||||||
|
except Exception as e:
|
||||||
|
print(f"警告:清空 Border 时出错: {e}")
|
||||||
|
|
||||||
|
# 4) 写出新 prefab
|
||||||
|
out_path = OUTPUT_DIR / f"Level{int(map_no)}.prefab"
|
||||||
|
out_path.write_text(new_text, encoding="utf-8")
|
||||||
|
|
||||||
|
print(f"生成 {out_path} ,共 Ground {len(ground_tiles)} 个 tile,Border {len(border_tiles)} 个 tile")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
256
read_excel.py
Normal file
256
read_excel.py
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
import os
|
||||||
|
import pandas as pd
|
||||||
|
from openpyxl import load_workbook
|
||||||
|
|
||||||
|
|
||||||
|
def _merge_read_config(config):
|
||||||
|
defaults = {
|
||||||
|
"columns_to_preview": 3,
|
||||||
|
"green_colors": {"FF92D050", "FF00B050"},
|
||||||
|
"blue_colors": {"FF00B0F0", "FF0070C0"},
|
||||||
|
"orange_colors": {"FFC55B11", "FFC55C10", "FFB45F06"},
|
||||||
|
"pink_colors": {"FFEF949F", "FFFF99FF"},
|
||||||
|
"log_file": "w.log",
|
||||||
|
}
|
||||||
|
if not config:
|
||||||
|
return defaults
|
||||||
|
for key, value in config.items():
|
||||||
|
if value is not None:
|
||||||
|
defaults[key] = value
|
||||||
|
return defaults
|
||||||
|
|
||||||
|
|
||||||
|
def _load_map_dataframe(file_path, sheet_name, start_i):
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
print(f"错误:文件未找到,请检查路径。Path: {file_path}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
df = pd.read_excel(file_path, sheet_name=sheet_name, engine="openpyxl")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"读取 XLSX 文件时发生错误: {e}")
|
||||||
|
if "No module named 'openpyxl'" in str(e):
|
||||||
|
print("\n请确保您已经安装了 openpyxl 库:pip install openpyxl")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if len(df.columns) < 2:
|
||||||
|
print("错误:表格至少需要两列 (地图编号与 Y 坐标)。")
|
||||||
|
return None
|
||||||
|
|
||||||
|
map_col = df.columns[0]
|
||||||
|
y_col = df.columns[1]
|
||||||
|
grid_columns = df.columns[1:27]
|
||||||
|
|
||||||
|
i = start_i
|
||||||
|
for row in df.itertuples():
|
||||||
|
if pd.isna(row[1]):
|
||||||
|
df.at[row.Index, map_col] = i
|
||||||
|
else:
|
||||||
|
i = row[1]
|
||||||
|
|
||||||
|
return df, map_col, y_col, grid_columns
|
||||||
|
|
||||||
|
|
||||||
|
def _write_color_output(filename, rows, columns, success_msg, empty_msg):
|
||||||
|
if os.path.exists(filename):
|
||||||
|
os.remove(filename)
|
||||||
|
if rows:
|
||||||
|
pd.DataFrame(rows, columns=columns).to_excel(filename, index=False)
|
||||||
|
print(success_msg)
|
||||||
|
else:
|
||||||
|
print(empty_msg)
|
||||||
|
|
||||||
|
|
||||||
|
def find_cells_with_currency_xlsx(file_path, sheet_name="Sheet1", start_i=90091, search_term="币", config=None):
|
||||||
|
"""
|
||||||
|
读取 XLSX 文件,查找包含指定词语(默认为“币”)的单元格,
|
||||||
|
并返回这些单元格的 (地图号, X, Y[, 方向]),结果同时保存为 found_xxx.xlsx。
|
||||||
|
"""
|
||||||
|
print(f"--- 正在处理文件: {os.path.basename(file_path)} ---")
|
||||||
|
|
||||||
|
df_info = _load_map_dataframe(file_path, sheet_name, start_i)
|
||||||
|
if df_info is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
cfg = _merge_read_config(config)
|
||||||
|
|
||||||
|
df, map_col, y_col, grid_columns = df_info
|
||||||
|
results = []
|
||||||
|
|
||||||
|
# 2. 遍历 B~AA 每一列,在地图区域里搜索 币 / p / v
|
||||||
|
for column in grid_columns:
|
||||||
|
column_series = df[column].astype(str).fillna("")
|
||||||
|
|
||||||
|
if search_term in ["p", "v"]:
|
||||||
|
# p/v 支持后缀方向
|
||||||
|
suffixes = ["W", "S", "N", "E", "w", "s", "n", "e"]
|
||||||
|
search_terms = [search_term] + [search_term + s for s in suffixes]
|
||||||
|
matching_rows = column_series.apply(
|
||||||
|
lambda x: any(term in x for term in search_terms)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
search_terms = [search_term]
|
||||||
|
matching_rows = column_series.str.contains(search_term, regex=False, na=False)
|
||||||
|
|
||||||
|
matching_indices = df[matching_rows].index.tolist()
|
||||||
|
|
||||||
|
if not matching_indices:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for idx in matching_indices:
|
||||||
|
# 地图号和坐标:直接从 A、B 列取值
|
||||||
|
map_no = df.at[idx, map_col] # A 列 = 地图编号
|
||||||
|
y_no = df.at[idx, y_col] # B 列 = Y 坐标
|
||||||
|
x_no = column # 列名本身 = X 坐标(-12 ~ 12)
|
||||||
|
|
||||||
|
# 提取方向(只对 p / v 有意义)
|
||||||
|
direction = ""
|
||||||
|
if search_term in ["p", "v"]:
|
||||||
|
cell_text = str(df.loc[idx, column])
|
||||||
|
direction = cell_text[len(search_term):] if len(cell_text) > len(search_term) else ""
|
||||||
|
|
||||||
|
if search_term in ["p", "v"]:
|
||||||
|
results.append((map_no, x_no, y_no, direction))
|
||||||
|
else:
|
||||||
|
results.append((map_no, x_no, y_no))
|
||||||
|
|
||||||
|
# 4. 保存币 / p / v 结果到 Excel
|
||||||
|
output_file = f"found_{search_term}.xlsx"
|
||||||
|
if search_term in ["p", "v"]:
|
||||||
|
results_df = pd.DataFrame(
|
||||||
|
results,
|
||||||
|
columns=["地图号 (Map No)", "X坐标 (X No)", "Y坐标 (Y No)", "方向 (Direction)"]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
results_df = pd.DataFrame(
|
||||||
|
results,
|
||||||
|
columns=["地图号 (Map No)", "X坐标 (X No)", "Y坐标 (Y No)"]
|
||||||
|
)
|
||||||
|
|
||||||
|
results_df.to_excel(output_file, index=False)
|
||||||
|
print(f"\n🔖 已将结果保存到文件: {output_file}")
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def scan_color_blocks(file_path, sheet_name="Sheet1", start_i=90091, config=None):
|
||||||
|
"""扫描地图区域内的颜色格子,并把结果写入对应的 Excel 文件。"""
|
||||||
|
|
||||||
|
print("\n开始扫描颜色图案格子…")
|
||||||
|
|
||||||
|
df_info = _load_map_dataframe(file_path, sheet_name, start_i)
|
||||||
|
if df_info is None:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
cfg = _merge_read_config(config)
|
||||||
|
|
||||||
|
df, map_col, y_col, grid_columns = df_info
|
||||||
|
|
||||||
|
try:
|
||||||
|
wb = load_workbook(file_path, data_only=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"读取 XLSX 文件时发生错误: {e}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
ws = wb[sheet_name]
|
||||||
|
except KeyError:
|
||||||
|
active_sheet = wb.active
|
||||||
|
print(f"未找到工作表 {sheet_name},使用活动表 {active_sheet.title}。")
|
||||||
|
ws = active_sheet
|
||||||
|
|
||||||
|
block_results = []
|
||||||
|
water_results = []
|
||||||
|
wall_results = []
|
||||||
|
jump_results = []
|
||||||
|
|
||||||
|
excel_row_offset = 2 # DataFrame 行索引 0 对应 Excel 的第 2 行
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(filename=cfg["log_file"], level=logging.INFO)
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
for idx in df.index:
|
||||||
|
map_no = df.at[idx, map_col]
|
||||||
|
y_val = df.at[idx, y_col]
|
||||||
|
|
||||||
|
try:
|
||||||
|
y_int = int(y_val)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if y_int < -12 or y_int > 12:
|
||||||
|
continue
|
||||||
|
|
||||||
|
excel_row = idx + excel_row_offset
|
||||||
|
|
||||||
|
for col in grid_columns[1:]: # 从 C 列开始(跳过 Y 轴列)
|
||||||
|
col_idx = df.columns.get_loc(col) + 1 # openpyxl 的列号从 1 开始
|
||||||
|
cell = ws.cell(row=excel_row, column=col_idx)
|
||||||
|
fill = cell.fill
|
||||||
|
|
||||||
|
if fill is None or fill.patternType in (None, "none"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
fg = fill.fgColor
|
||||||
|
rgb = getattr(fg, "rgb", None)
|
||||||
|
index = getattr(fg, "index", None)
|
||||||
|
color_code = rgb or index
|
||||||
|
|
||||||
|
if color_code is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
c = str(color_code).upper()
|
||||||
|
if c.startswith("FF"):
|
||||||
|
log.info("Cell at Row %s, Column %s has color code: %s", excel_row, col_idx, c)
|
||||||
|
|
||||||
|
if c in cfg["green_colors"]:
|
||||||
|
block_results.append((map_no, col, y_val))
|
||||||
|
if c in cfg["blue_colors"]:
|
||||||
|
water_results.append((map_no, col, y_val))
|
||||||
|
if c in cfg["orange_colors"]:
|
||||||
|
wall_results.append((map_no, col, y_val))
|
||||||
|
if c in cfg["pink_colors"]:
|
||||||
|
jump_results.append((map_no, col, y_val))
|
||||||
|
|
||||||
|
columns = ["地图号 (Map No)", "X坐标 (X No)", "Y坐标 (Y No)"]
|
||||||
|
|
||||||
|
_write_color_output(
|
||||||
|
"found_方块.xlsx",
|
||||||
|
block_results,
|
||||||
|
columns,
|
||||||
|
"🔖 已将所有绿色图案格子的坐标保存到文件: found_方块.xlsx",
|
||||||
|
"未发现任何绿色图案格子。",
|
||||||
|
)
|
||||||
|
|
||||||
|
_write_color_output(
|
||||||
|
"found_water.xlsx",
|
||||||
|
water_results,
|
||||||
|
columns,
|
||||||
|
"🔖 已将蓝色 (water) 格子保存到文件: found_water.xlsx",
|
||||||
|
"未发现蓝色 (water) 格子。",
|
||||||
|
)
|
||||||
|
|
||||||
|
_write_color_output(
|
||||||
|
"found_wall.xlsx",
|
||||||
|
wall_results,
|
||||||
|
columns,
|
||||||
|
"🔖 已将橙色 (wall) 格子保存到文件: found_wall.xlsx",
|
||||||
|
"未发现橙色 (wall) 格子。",
|
||||||
|
)
|
||||||
|
|
||||||
|
_write_color_output(
|
||||||
|
"found_jump.xlsx",
|
||||||
|
jump_results,
|
||||||
|
columns,
|
||||||
|
"🔖 已将粉色 (jump) 格子保存到文件: found_jump.xlsx",
|
||||||
|
"未发现粉色 (jump) 格子。",
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"block": block_results,
|
||||||
|
"water": water_results,
|
||||||
|
"wall": wall_results,
|
||||||
|
"jump": jump_results,
|
||||||
|
}
|
||||||
134
run_pipeline.py
Normal file
134
run_pipeline.py
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
run_pipeline.py
|
||||||
|
|
||||||
|
串联三步处理脚本:
|
||||||
|
1) 从 Excel 抽取币 / p / v 与绿色方块(使用 read_excel.py 中的函数)
|
||||||
|
2) 根据 found_*.xlsx 生成 C# 关卡代码(调用 write_code.py 的 main)
|
||||||
|
3) 根据 found_方块.xlsx 生成 prefab(调用 make_prefab.py 的 main)
|
||||||
|
|
||||||
|
用法示例:
|
||||||
|
python run_pipeline.py --excel global.xlsx --sheet Sheet2 --start-i 80316
|
||||||
|
python run_pipeline.py --steps 1,2 # 只执行前两步
|
||||||
|
|
||||||
|
可配置项:--start-i, --excel, --sheet, --template, --steps
|
||||||
|
|
||||||
|
注意:本脚本会 import 现有模块并调用它们的 main 函数 / 函数。
|
||||||
|
请确保安装依赖:openpyxl, pandas
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
def parse_steps(s: str) -> List[int]:
|
||||||
|
parts = [p.strip() for p in s.split(",") if p.strip()]
|
||||||
|
steps = []
|
||||||
|
for p in parts:
|
||||||
|
if p.isdigit():
|
||||||
|
steps.append(int(p))
|
||||||
|
elif p.lower() == "all":
|
||||||
|
return [1, 2, 3]
|
||||||
|
return steps
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Run pipeline: read_excel -> write_code -> make_prefab")
|
||||||
|
parser.add_argument("--excel", default="global.xlsx", help="输入 Excel 文件 (默认: global.xlsx)")
|
||||||
|
parser.add_argument("--sheet", default="Sheet2", help="Excel 的 sheet 名称 (默认: Sheet2)")
|
||||||
|
parser.add_argument("--start-i", type=int, default=80316, help="A 列地图号的起始值 (默认: 80316)")
|
||||||
|
parser.add_argument("--template", default="Level90093.prefab", help="prefab 模板文件 (默认: Level90093.prefab)")
|
||||||
|
parser.add_argument("--steps", default="all", help="要执行的步骤,例如: 1,2,3 或 all (默认: all)")
|
||||||
|
parser.add_argument("--output-levels", default="generated_levels.cs", help="生成的 C# 文件名 (默认: generated_levels.cs)")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
steps = parse_steps(args.steps)
|
||||||
|
if not steps:
|
||||||
|
steps = [1, 2, 3]
|
||||||
|
|
||||||
|
# 确保当前工作目录是脚本所在目录(便于相对路径文件读写)
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
os.chdir(script_dir)
|
||||||
|
|
||||||
|
print("流水线开始,工作目录:", script_dir)
|
||||||
|
print("将执行步骤:", steps)
|
||||||
|
|
||||||
|
# STEP 1: run read_excel.find_cells_with_currency_xlsx for 币, p, v
|
||||||
|
if 1 in steps:
|
||||||
|
print("\n=== 步骤 1: 从 Excel 中抽取 币 / p / v 与绿色方块 ===")
|
||||||
|
try:
|
||||||
|
import read_excel
|
||||||
|
except Exception as e:
|
||||||
|
print("无法导入 read_excel.py:", e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# 调用函数(函数会自己写出 found_币.xlsx / found_p.xlsx / found_v.xlsx / found_方块.xlsx)
|
||||||
|
found_coin = read_excel.find_cells_with_currency_xlsx(args.excel, sheet_name=args.sheet, start_i=args.start_i, search_term="币")
|
||||||
|
found_p = read_excel.find_cells_with_currency_xlsx(args.excel, sheet_name=args.sheet, start_i=args.start_i, search_term="p")
|
||||||
|
found_v = read_excel.find_cells_with_currency_xlsx(args.excel, sheet_name=args.sheet, start_i=args.start_i, search_term="v")
|
||||||
|
color_summary = read_excel.scan_color_blocks(args.excel, sheet_name=args.sheet, start_i=args.start_i)
|
||||||
|
|
||||||
|
if color_summary:
|
||||||
|
block_len = len(color_summary.get("block", []))
|
||||||
|
water_len = len(color_summary.get("water", []))
|
||||||
|
wall_len = len(color_summary.get("wall", []))
|
||||||
|
jump_len = len(color_summary.get("jump", []))
|
||||||
|
print(
|
||||||
|
"步骤1完成:发现 币 {0} / p {1} / v {2} 条目;颜色格子 block {3} / water {4} / wall {5} / jump {6}.".format(
|
||||||
|
len(found_coin), len(found_p), len(found_v), block_len, water_len, wall_len, jump_len
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(f"步骤1完成:发现 币 {len(found_coin)} / p {len(found_p)} / v {len(found_v)} 条目。")
|
||||||
|
|
||||||
|
# STEP 2: run write_code.py to generate generated_levels.cs
|
||||||
|
if 2 in steps:
|
||||||
|
print("\n=== 步骤 2: 使用 found_*.xlsx 生成 C# 关卡文件 ===")
|
||||||
|
try:
|
||||||
|
import write_code
|
||||||
|
except Exception as e:
|
||||||
|
print("无法导入 write_code.py:", e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# 允许覆盖 write_code 中的文件名常量
|
||||||
|
write_code.FILE_P = getattr(write_code, 'FILE_P', 'found_p.xlsx')
|
||||||
|
write_code.FILE_V = getattr(write_code, 'FILE_V', 'found_v.xlsx')
|
||||||
|
write_code.FILE_COIN = getattr(write_code, 'FILE_COIN', 'found_币.xlsx')
|
||||||
|
write_code.OUTPUT_FILE = args.output_levels
|
||||||
|
|
||||||
|
# 调用其 main() 来生成文件
|
||||||
|
try:
|
||||||
|
write_code.main()
|
||||||
|
print(f"步骤2完成:已生成 {args.output_levels}")
|
||||||
|
except Exception as e:
|
||||||
|
print("执行 write_code.main() 时出错:", e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# STEP 3: run make_prefab.py to generate prefab files
|
||||||
|
if 3 in steps:
|
||||||
|
print("\n=== 步骤 3: 使用 found_方块.xlsx 生成 prefab ===")
|
||||||
|
try:
|
||||||
|
import make_prefab
|
||||||
|
except Exception as e:
|
||||||
|
print("无法导入 make_prefab.py:", e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# 覆盖模板与输入 Excel 路径
|
||||||
|
make_prefab.EXCEL_PATH = getattr(make_prefab, 'EXCEL_PATH', 'found_方块.xlsx')
|
||||||
|
make_prefab.TEMPLATE_PREFAB = args.template
|
||||||
|
|
||||||
|
try:
|
||||||
|
make_prefab.main()
|
||||||
|
print("步骤3完成:Prefab 已生成到 GeneratedPrefabs/ 目录")
|
||||||
|
except Exception as e:
|
||||||
|
print("执行 make_prefab.main() 时出错:", e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("\n流水线全部完成。")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
53
test_detect_filled_cells.py
Normal file
53
test_detect_filled_cells.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
from openpyxl import Workbook
|
||||||
|
from openpyxl.styles import PatternFill
|
||||||
|
|
||||||
|
from detect_filled_cells import detect_colored_cells
|
||||||
|
|
||||||
|
|
||||||
|
def create_sample_workbook(path):
|
||||||
|
wb = Workbook()
|
||||||
|
ws = wb.active
|
||||||
|
ws.title = 'Sheet1'
|
||||||
|
|
||||||
|
# A1: solid green with full ARGB
|
||||||
|
ws['A1'].fill = PatternFill(start_color='FF00B050', end_color='FF00B050', fill_type='solid')
|
||||||
|
ws['A1'].value = 'block'
|
||||||
|
|
||||||
|
# B2: solid blue with 6-digit rgb (should be treated as FF+rgb)
|
||||||
|
ws['B2'].fill = PatternFill(start_color='00B0F0', end_color='00B0F0', fill_type='solid')
|
||||||
|
ws['B2'].value = 'water'
|
||||||
|
|
||||||
|
# C3: no fill
|
||||||
|
ws['C3'].value = 'empty'
|
||||||
|
|
||||||
|
wb.save(path)
|
||||||
|
|
||||||
|
|
||||||
|
def run_test():
|
||||||
|
tf = tempfile.NamedTemporaryFile(delete=False, suffix='.xlsx')
|
||||||
|
tf.close()
|
||||||
|
try:
|
||||||
|
create_sample_workbook(tf.name)
|
||||||
|
print(f"Saved sample workbook to: {tf.name}")
|
||||||
|
|
||||||
|
results = detect_colored_cells(tf.name, sheet_name='Sheet1')
|
||||||
|
print('Detected colored cells:')
|
||||||
|
for r in results:
|
||||||
|
print(r)
|
||||||
|
|
||||||
|
assert any(r['coordinate'] == 'A1' for r in results), 'A1 should be detected'
|
||||||
|
assert any(r['coordinate'] == 'B2' for r in results), 'B2 should be detected'
|
||||||
|
assert all(r['coordinate'] != 'C3' for r in results), 'C3 should not be detected'
|
||||||
|
|
||||||
|
print('\nTest passed')
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
os.unlink(tf.name)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
run_test()
|
||||||
149
write_code.py
Normal file
149
write_code.py
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
|
||||||
|
# 确保文件名与您上传的保持一致
|
||||||
|
FILE_P = "found_p.xlsx"
|
||||||
|
FILE_V = "found_v.xlsx"
|
||||||
|
FILE_COIN = "found_币.xlsx"
|
||||||
|
|
||||||
|
OUTPUT_FILE = "Levels90001.cs"
|
||||||
|
LEVEL_PATH = "Assets/Prefabs/Level/Level{map_id}.prefab" # 假设 levelPath 随 LevelID 变化
|
||||||
|
|
||||||
|
# 1. 读取并标准化数据
|
||||||
|
def load_data():
|
||||||
|
try:
|
||||||
|
# Player Data
|
||||||
|
df_p = pd.read_excel(FILE_P)
|
||||||
|
df_p.columns = ['MapID', 'X', 'Y', 'Direction']
|
||||||
|
|
||||||
|
# Vehicle Data
|
||||||
|
df_v = pd.read_excel(FILE_V)
|
||||||
|
df_v.columns = ['MapID', 'X', 'Y', 'Direction']
|
||||||
|
|
||||||
|
# Coin Data
|
||||||
|
df_coin = pd.read_excel(FILE_COIN)
|
||||||
|
# Coin 文件中没有 Direction 列
|
||||||
|
df_coin.columns = ['MapID', 'X', 'Y']
|
||||||
|
|
||||||
|
return df_p, df_v, df_coin
|
||||||
|
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
print(f"错误:找不到文件 {e.filename}。请确保所有 CSV 文件与脚本在同一目录下。")
|
||||||
|
return None, None, None
|
||||||
|
|
||||||
|
# 2. 生成单个 Spawn() 字符串
|
||||||
|
def generate_spawn_line(data_row, spawn_type):
|
||||||
|
map_id = data_row['MapID']
|
||||||
|
x, y, z = data_row['X'], data_row['Y'], 0 # Z 坐标固定为 0
|
||||||
|
|
||||||
|
position_str = f"new Vector3Int({x},{y},{z})"
|
||||||
|
|
||||||
|
if spawn_type == 'player':
|
||||||
|
direction = data_row['Direction']
|
||||||
|
# 将 CSV 中的 N/S/E/W 转换为 C# 枚举 Direction.North/South/East/West
|
||||||
|
direction_map = {'N': 'Direction.North', 'S': 'Direction.South', 'E': 'Direction.East', 'W': 'Direction.West'}
|
||||||
|
dir_enum = direction_map.get(direction, 'Direction.North') # 默认值
|
||||||
|
return f'new Spawn(){{position = {position_str},path = "Assets/Prefabs/Player.prefab", playerDirection = {dir_enum}}}, // Map {map_id}'
|
||||||
|
|
||||||
|
elif spawn_type == 'vehicle':
|
||||||
|
direction = data_row['Direction']
|
||||||
|
direction_map = {'N': 'Direction.North', 'S': 'Direction.South', 'E': 'Direction.East', 'W': 'Direction.West'}
|
||||||
|
dir_enum = direction_map.get(direction, 'Direction.North')
|
||||||
|
return f'new Spawn(){{position = {position_str},path = "Assets/Prefabs/Vehicle.prefab", vehicleDirection = {dir_enum}}}, // Map {map_id}'
|
||||||
|
|
||||||
|
elif spawn_type == 'coin':
|
||||||
|
# 金币没有方向
|
||||||
|
return f'new Spawn(){{position = {position_str},path = "Assets/Prefabs/Prop_star.prefab",}},//金币位置{x},{y},z (Map {map_id})'
|
||||||
|
|
||||||
|
# 3. 生成完整的 C# Level 代码块
|
||||||
|
def generate_level_code(map_id, df_p_group, df_v_group, df_coin_group):
|
||||||
|
|
||||||
|
# 构建所有 Spawn 行
|
||||||
|
spawn_lines = []
|
||||||
|
|
||||||
|
# Player Spawns
|
||||||
|
spawn_lines.append('\n\t\t// --- Player Spawns ---')
|
||||||
|
for _, row in df_p_group.iterrows():
|
||||||
|
spawn_lines.append('\t\t' + generate_spawn_line(row, 'player'))
|
||||||
|
|
||||||
|
# Vehicle Spawns
|
||||||
|
spawn_lines.append('\n\t\t// --- Vehicle Spawns ---')
|
||||||
|
for _, row in df_v_group.iterrows():
|
||||||
|
spawn_lines.append('\t\t' + generate_spawn_line(row, 'vehicle'))
|
||||||
|
|
||||||
|
# Coin Spawns
|
||||||
|
spawn_lines.append('\n\t\t// --- Coin Spawns ---')
|
||||||
|
for _, row in df_coin_group.iterrows():
|
||||||
|
spawn_lines.append('\t\t' + generate_spawn_line(row, 'coin'))
|
||||||
|
|
||||||
|
spawns_block = '\n'.join(spawn_lines)
|
||||||
|
|
||||||
|
# 填充模板
|
||||||
|
code_template = f"""
|
||||||
|
\n\t\t// 关卡 {map_id}
|
||||||
|
\t\t{{ {map_id},new Level(){{LevelID = {map_id},spawns = new List<Spawn>(){{
|
||||||
|
{spawns_block}
|
||||||
|
\t\t}},
|
||||||
|
\t\tboundary = new Vector3Int(20,20,0), // 边界默认值
|
||||||
|
\t\tlevelPath = "{LEVEL_PATH.format(map_id=map_id)}"}}}},"""
|
||||||
|
|
||||||
|
return code_template
|
||||||
|
|
||||||
|
# 4. 主执行函数
|
||||||
|
def main():
|
||||||
|
df_p, df_v, df_coin = load_data()
|
||||||
|
if df_p is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 获取所有唯一的地图号
|
||||||
|
all_map_ids = set(df_p['MapID'].unique()) | set(df_v['MapID'].unique()) | set(df_coin['MapID'].unique())
|
||||||
|
|
||||||
|
all_map_ids = sorted(list(all_map_ids)) # 按顺序生成
|
||||||
|
|
||||||
|
generated_code = []
|
||||||
|
|
||||||
|
print(f"发现 {len(all_map_ids)} 个唯一的地图号:{all_map_ids}")
|
||||||
|
|
||||||
|
|
||||||
|
for map_id in all_map_ids:
|
||||||
|
# 按当前 MapID 过滤数据
|
||||||
|
p_group = df_p[df_p['MapID'] == map_id] if map_id in df_p['MapID'].values else pd.DataFrame()
|
||||||
|
v_group = df_v[df_v['MapID'] == map_id] if map_id in df_v['MapID'].values else pd.DataFrame()
|
||||||
|
coin_group = df_coin[df_coin['MapID'] == map_id] if map_id in df_coin['MapID'].values else pd.DataFrame()
|
||||||
|
|
||||||
|
if not p_group.empty or not v_group.empty or not coin_group.empty:
|
||||||
|
code_block = generate_level_code(map_id, p_group, v_group, coin_group)
|
||||||
|
generated_code.append(code_block)
|
||||||
|
print(f"成功生成关卡 {map_id} 的代码块。")
|
||||||
|
else:
|
||||||
|
print(f"警告:地图 {map_id} 在所有文件中均无数据,跳过。")
|
||||||
|
|
||||||
|
|
||||||
|
# 将结果写入文件(在循环外,只写一次)
|
||||||
|
# 把 Levels80212.cs 的第1-10行作为文件头部, 最后3行作为结尾
|
||||||
|
header = '''using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Platformer.Controller;
|
||||||
|
using UnityEngine;
|
||||||
|
using static Platformer.Manager.GameManager;
|
||||||
|
|
||||||
|
namespace Platformer.Core
|
||||||
|
{
|
||||||
|
public class Levels80001
|
||||||
|
{
|
||||||
|
public Dictionary<int, Level> Levels = new Dictionary<int, Level>()
|
||||||
|
{'''
|
||||||
|
footer = '''
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}'''
|
||||||
|
|
||||||
|
with open(OUTPUT_FILE, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(header)
|
||||||
|
f.write('\t\t'.join(generated_code))
|
||||||
|
f.write(footer)
|
||||||
|
|
||||||
|
print(f"\n--- 所有代码已成功生成并保存到文件:{OUTPUT_FILE} ---")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user