203 lines
7.4 KiB
Python
203 lines
7.4 KiB
Python
import pandas as pd
|
||
from pathlib import Path
|
||
|
||
# ============= 配置 =============
|
||
|
||
# Excel 路径
|
||
EXCEL_PATH = "found_方块.xlsx" # 根据你的实际文件名改
|
||
|
||
# 作为模板的 prefab(就是你贴出来那份,包含 Ground / Border / Grid)
|
||
TEMPLATE_PREFAB = "Level90116.prefab" # 根据实际文件名改
|
||
OLD_LEVEL_NAME = "Level90116" # 模板 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 = 1
|
||
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), 1, 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), 5, 3) 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), 4, 2) 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), 3, 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()
|