first commint

This commit is contained in:
suqin
2025-12-06 17:48:48 +08:00
commit 37f211ffc6
14 changed files with 5122 additions and 0 deletions

201
make_prefab.py Normal file
View 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 里那种 tilem_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)} 个 tileBorder {len(border_tiles)} 个 tile")
if __name__ == "__main__":
main()