Localize map editor to Chinese

This commit is contained in:
2026-06-10 00:22:36 +08:00
parent 759abfd527
commit d7bc9e6a24
3 changed files with 77 additions and 77 deletions
+33 -33
View File
@@ -75,10 +75,10 @@ async function loadSampleMap() {
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
loadMapText(await response.text(), "Loaded stage_01.map");
loadMapText(await response.text(), "已加载 stage_01.map");
} catch (error) {
setStatus(`Could not fetch stage_01.map. Use Open .map. ${error.message}`);
loadMapText(defaultMapText(), "Loaded built-in starter map");
setStatus(`无法读取 stage_01.map,请使用“打开 .map”。${error.message}`);
loadMapText(defaultMapText(), "已加载内置起始地图");
}
}
@@ -86,7 +86,7 @@ function openFile(event) {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = () => loadMapText(String(reader.result || ""), `Opened ${file.name}`);
reader.onload = () => loadMapText(String(reader.result || ""), `已打开 ${file.name}`);
reader.readAsText(file);
}
@@ -98,7 +98,7 @@ function loadMapText(text, status) {
setStatus(status);
refresh();
} catch (error) {
setStatus(`Parse failed: ${error.message}`);
setStatus(`解析失败:${error.message}`);
}
}
@@ -195,7 +195,7 @@ function parseMap(text) {
};
map.battleZones.push(currentBattleZone);
} else if (command === "spawn") {
if (!currentBattleZone) throw new Error(`Line ${lineNumber}: spawn outside battle_zone`);
if (!currentBattleZone) throw new Error(` ${lineNumber} 行:spawn 必须写在 battle_zone`);
currentBattleZone.spawns.push({
id: requireToken(tokens, 1, lineNumber),
x: num(tokens, 2, lineNumber),
@@ -204,7 +204,7 @@ function parseMap(text) {
} else if (command === "endbattle_zone") {
currentBattleZone = null;
} else {
throw new Error(`Line ${lineNumber}: unknown command ${command}`);
throw new Error(` ${lineNumber} 行:未知命令 ${command}`);
}
}
@@ -303,7 +303,7 @@ function renderPropertyPanel() {
const object = getSelectedObject();
elements.propertyPanel.innerHTML = "";
if (!object) {
elements.selectionSummary.textContent = "Nothing selected.";
elements.selectionSummary.textContent = "未选择对象。";
elements.deleteButton.disabled = true;
return;
}
@@ -355,7 +355,7 @@ function drawCanvas() {
drawSelection(ctx);
ctx.restore();
elements.viewText.textContent = `zoom ${state.view.scale.toFixed(2)} | grid ${state.gridSize}`;
elements.viewText.textContent = `缩放 ${state.view.scale.toFixed(2)} | 网格 ${state.gridSize}`;
}
function drawWorld(ctx) {
@@ -469,20 +469,20 @@ function line(ctx, x1, y1, x2, y2) {
function collectObjects() {
const objects = [
objectForPoint("player", "Player Spawn", state.map.playerSpawn),
objectForRect("camera", "Camera", state.map.camera),
objectForPoint("player", "玩家出生点", state.map.playerSpawn),
objectForRect("camera", "摄像机范围", state.map.camera),
];
state.map.tilesets.forEach((tileset, index) => objects.push(objectForTileset(`tileset:${index}`, `Tileset ${tileset.id}`, tileset, true)));
state.map.collisions.forEach((rect, index) => objects.push(objectForRect(`collision:${index}`, `Collision ${index + 1}`, rect, true)));
state.map.tilesets.forEach((tileset, index) => objects.push(objectForTileset(`tileset:${index}`, `图块集 ${tileset.id}`, tileset, true)));
state.map.collisions.forEach((rect, index) => objects.push(objectForRect(`collision:${index}`, `碰撞块 ${index + 1}`, rect, true)));
state.map.layers.forEach((layer, layerIndex) => {
objects.push(objectForLayer(`layer:${layerIndex}`, `Layer ${layer.id}`, layer, true));
layer.rects.forEach((rect, rectIndex) => objects.push(objectForRect(`rect:${layerIndex}:${rectIndex}`, `${layer.id} Rect ${rectIndex + 1}`, rect.bounds, true)));
layer.tileRects.forEach((tileRect, tileIndex) => objects.push(objectForTileRect(`tile:${layerIndex}:${tileIndex}`, `${layer.id} TileRect ${tileIndex + 1}`, tileRect, true)));
objects.push(objectForLayer(`layer:${layerIndex}`, `图层 ${layer.id}`, layer, true));
layer.rects.forEach((rect, rectIndex) => objects.push(objectForRect(`rect:${layerIndex}:${rectIndex}`, `${layer.id} 矩形 ${rectIndex + 1}`, rect.bounds, true)));
layer.tileRects.forEach((tileRect, tileIndex) => objects.push(objectForTileRect(`tile:${layerIndex}:${tileIndex}`, `${layer.id} 铺砖区 ${tileIndex + 1}`, tileRect, true)));
});
state.map.battleZones.forEach((zone, zoneIndex) => {
objects.push(objectForRect(`zone:${zoneIndex}`, `Battle Zone ${zoneIndex + 1}`, zone.trigger, true, zone.id));
objects.push(objectForRect(`zone_camera:${zoneIndex}`, `Zone Camera ${zoneIndex + 1}`, zone.camera, false, zone.id));
zone.spawns.forEach((spawn, spawnIndex) => objects.push(objectForPoint(`spawn:${zoneIndex}:${spawnIndex}`, `Spawn ${spawn.id}`, spawn, true)));
objects.push(objectForRect(`zone:${zoneIndex}`, `战斗区 ${zoneIndex + 1}`, zone.trigger, true, zone.id));
objects.push(objectForRect(`zone_camera:${zoneIndex}`, `战斗区镜头 ${zoneIndex + 1}`, zone.camera, false, zone.id));
zone.spawns.forEach((spawn, spawnIndex) => objects.push(objectForPoint(`spawn:${zoneIndex}:${spawnIndex}`, `出生点 ${spawn.id}`, spawn, true)));
});
return objects;
}
@@ -495,9 +495,9 @@ function objectForTileset(id, title, tileset, deletable) {
deletable,
fields: () => [
textField("ID", () => tileset.id, (v) => { renameTileset(tileset.id, v || tileset.id); }),
textField("Texture", () => tileset.texture, (v) => { tileset.texture = v || tileset.texture; }),
numberField("Tile W", () => tileset.tileWidth, (v) => { tileset.tileWidth = Math.max(1, v); }),
numberField("Tile H", () => tileset.tileHeight, (v) => { tileset.tileHeight = Math.max(1, v); }),
textField("贴图路径", () => tileset.texture, (v) => { tileset.texture = v || tileset.texture; }),
numberField("图块宽", () => tileset.tileWidth, (v) => { tileset.tileWidth = Math.max(1, v); }),
numberField("图块高", () => tileset.tileHeight, (v) => { tileset.tileHeight = Math.max(1, v); }),
...colorFields(tileset.color, true),
],
};
@@ -511,8 +511,8 @@ function objectForLayer(id, title, layer, deletable) {
deletable,
fields: () => [
textField("ID", () => layer.id, (v) => { layer.id = v || layer.id; }),
textField("Role", () => layer.role, (v) => { layer.role = v; }, ROLE_ORDER),
numberField("Parallax", () => layer.parallax, (v) => { layer.parallax = v; }, "0.05"),
textField("类型", () => layer.role, (v) => { layer.role = v; }, ROLE_ORDER),
numberField("视差", () => layer.parallax, (v) => { layer.parallax = v; }, "0.05"),
],
};
}
@@ -553,12 +553,12 @@ function objectForTileRect(id, title, tileRect, deletable) {
bounds: () => ({ x: tileRect.x, y: tileRect.y, width: tileRect.columns * tw, height: tileRect.rows * th }),
move(dx, dy) { tileRect.x += dx; tileRect.y += dy; },
fields: () => [
textField("Tileset", () => tileRect.tileset, (v) => { tileRect.tileset = v; }, state.map.tilesets.map((item) => item.id)),
textField("图块集", () => tileRect.tileset, (v) => { tileRect.tileset = v; }, state.map.tilesets.map((item) => item.id)),
numberField("X", () => tileRect.x, (v) => { tileRect.x = v; }),
numberField("Y", () => tileRect.y, (v) => { tileRect.y = v; }),
numberField("Columns", () => tileRect.columns, (v) => { tileRect.columns = Math.max(1, Math.round(v)); }),
numberField("Rows", () => tileRect.rows, (v) => { tileRect.rows = Math.max(1, Math.round(v)); }),
numberField("Tile Index", () => tileRect.tileIndex, (v) => { tileRect.tileIndex = Math.max(0, Math.round(v)); }),
numberField("列数", () => tileRect.columns, (v) => { tileRect.columns = Math.max(1, Math.round(v)); }),
numberField("行数", () => tileRect.rows, (v) => { tileRect.rows = Math.max(1, Math.round(v)); }),
numberField("图块索引", () => tileRect.tileIndex, (v) => { tileRect.tileIndex = Math.max(0, Math.round(v)); }),
...colorFields(tileRect.color, false),
],
};
@@ -701,7 +701,7 @@ function deleteSelected() {
if (parts[0] === "tileset") {
const tileset = state.map.tilesets[Number(parts[1])];
if (tileset && isTilesetUsed(tileset.id)) {
setStatus(`Cannot delete tileset ${tileset.id}: it is used by tile_rect.`);
setStatus(`不能删除图块集 ${tileset.id}:它仍被 tile_rect 使用。`);
return;
}
state.map.tilesets.splice(Number(parts[1]), 1);
@@ -800,17 +800,17 @@ function tokenize(line) {
}
function requireLayer(layer, lineNumber) {
if (!layer) throw new Error(`Line ${lineNumber}: command must be inside layer`);
if (!layer) throw new Error(` ${lineNumber} 行:该命令必须写在 layer`);
}
function requireToken(tokens, index, lineNumber) {
if (tokens.length <= index) throw new Error(`Line ${lineNumber}: missing token ${index}`);
if (tokens.length <= index) throw new Error(` ${lineNumber} 行:缺少第 ${index} 个参数`);
return tokens[index];
}
function num(tokens, index, lineNumber) {
const value = Number(requireToken(tokens, index, lineNumber));
if (!Number.isFinite(value)) throw new Error(`Line ${lineNumber}: invalid number ${tokens[index]}`);
if (!Number.isFinite(value)) throw new Error(` ${lineNumber} 行:无效数字 ${tokens[index]}`);
return value;
}
@@ -881,7 +881,7 @@ function renameTileset(oldId, newId) {
const cleanId = String(newId).trim();
if (!cleanId) return;
if (cleanId !== oldId && state.map.tilesets.some((item) => item.id === cleanId)) {
setStatus(`Cannot rename tileset: ${cleanId} already exists.`);
setStatus(`不能重命名图块集:${cleanId} 已存在。`);
return;
}
const tileset = state.map.tilesets.find((item) => item.id === oldId);