Localize map editor to Chinese
This commit is contained in:
+18
-18
@@ -1,35 +1,35 @@
|
|||||||
# Map Editor
|
# 地图编辑器
|
||||||
|
|
||||||
Static browser-based editor for the game's `.map` files.
|
这是一个静态网页地图编辑器,用来编辑游戏使用的 `.map` 文本文件。
|
||||||
|
|
||||||
## Run Locally
|
## 本地运行
|
||||||
|
|
||||||
From the repository root:
|
在仓库根目录执行:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
python -m http.server 8787
|
python -m http.server 8787
|
||||||
```
|
```
|
||||||
|
|
||||||
Open:
|
然后打开:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
http://127.0.0.1:8787/tools/map_editor/
|
http://127.0.0.1:8787/tools/map_editor/
|
||||||
```
|
```
|
||||||
|
|
||||||
The editor can fetch `game/assets/map/stage_01.map` when served from the repo root. It can also open any `.map` file through the file picker.
|
从仓库根目录启动静态服务时,编辑器可以自动读取 `game/assets/map/stage_01.map`。也可以通过“打开 .map”选择任意 `.map` 文件。
|
||||||
|
|
||||||
## Current Scope
|
## 当前能力
|
||||||
|
|
||||||
- Open `.map` text files.
|
- 打开 `.map` 文本文件。
|
||||||
- Visualize world, camera, player spawn, collision, stage rects, tile rects, battle zones, and spawn points.
|
- 可视化世界范围、摄像机范围、玩家出生点、碰撞块、场景矩形、铺砖区、战斗区和敌人出生点。
|
||||||
- Select objects from the canvas or object list.
|
- 从画布或对象列表选择对象。
|
||||||
- Drag objects on the canvas with grid snapping.
|
- 在画布上拖动对象,支持网格吸附。
|
||||||
- Edit selected object numeric properties.
|
- 编辑选中对象的数值和文本属性。
|
||||||
- Add/delete collision rectangles, tile rectangles, battle zones, and spawn points.
|
- 新增/删除图块集、图层、碰撞块、铺砖区、战斗区和出生点。
|
||||||
- Download a serialized `.map` file compatible with `StageMapLoader`.
|
- 下载兼容 `StageMapLoader` 的 `.map` 文本。
|
||||||
|
|
||||||
## Limitations
|
## 当前限制
|
||||||
|
|
||||||
- Browser security prevents direct overwrite of the original local file. Use Download and replace the project `.map` manually, or deploy with a server-side save endpoint later.
|
- 浏览器安全限制不允许静态网页直接覆盖本地源文件。当前需要先下载 `.map`,再手动替换项目里的地图文件;部署到服务器后可以增加服务端保存接口。
|
||||||
- Tileset image preview is not implemented yet; tile rects use fallback colors.
|
- 暂未实现图块集图片预览,铺砖区当前使用 fallback 颜色显示。
|
||||||
- Undo/redo and multi-select are not implemented yet.
|
- 暂未实现撤销/重做和多选。
|
||||||
|
|||||||
+33
-33
@@ -75,10 +75,10 @@ async function loadSampleMap() {
|
|||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP ${response.status}`);
|
throw new Error(`HTTP ${response.status}`);
|
||||||
}
|
}
|
||||||
loadMapText(await response.text(), "Loaded stage_01.map");
|
loadMapText(await response.text(), "已加载 stage_01.map");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setStatus(`Could not fetch stage_01.map. Use Open .map. ${error.message}`);
|
setStatus(`无法读取 stage_01.map,请使用“打开 .map”。${error.message}`);
|
||||||
loadMapText(defaultMapText(), "Loaded built-in starter map");
|
loadMapText(defaultMapText(), "已加载内置起始地图");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ function openFile(event) {
|
|||||||
const file = event.target.files[0];
|
const file = event.target.files[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = () => loadMapText(String(reader.result || ""), `Opened ${file.name}`);
|
reader.onload = () => loadMapText(String(reader.result || ""), `已打开 ${file.name}`);
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ function loadMapText(text, status) {
|
|||||||
setStatus(status);
|
setStatus(status);
|
||||||
refresh();
|
refresh();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setStatus(`Parse failed: ${error.message}`);
|
setStatus(`解析失败:${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ function parseMap(text) {
|
|||||||
};
|
};
|
||||||
map.battleZones.push(currentBattleZone);
|
map.battleZones.push(currentBattleZone);
|
||||||
} else if (command === "spawn") {
|
} 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({
|
currentBattleZone.spawns.push({
|
||||||
id: requireToken(tokens, 1, lineNumber),
|
id: requireToken(tokens, 1, lineNumber),
|
||||||
x: num(tokens, 2, lineNumber),
|
x: num(tokens, 2, lineNumber),
|
||||||
@@ -204,7 +204,7 @@ function parseMap(text) {
|
|||||||
} else if (command === "endbattle_zone") {
|
} else if (command === "endbattle_zone") {
|
||||||
currentBattleZone = null;
|
currentBattleZone = null;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Line ${lineNumber}: unknown command ${command}`);
|
throw new Error(`第 ${lineNumber} 行:未知命令 ${command}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +303,7 @@ function renderPropertyPanel() {
|
|||||||
const object = getSelectedObject();
|
const object = getSelectedObject();
|
||||||
elements.propertyPanel.innerHTML = "";
|
elements.propertyPanel.innerHTML = "";
|
||||||
if (!object) {
|
if (!object) {
|
||||||
elements.selectionSummary.textContent = "Nothing selected.";
|
elements.selectionSummary.textContent = "未选择对象。";
|
||||||
elements.deleteButton.disabled = true;
|
elements.deleteButton.disabled = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -355,7 +355,7 @@ function drawCanvas() {
|
|||||||
drawSelection(ctx);
|
drawSelection(ctx);
|
||||||
|
|
||||||
ctx.restore();
|
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) {
|
function drawWorld(ctx) {
|
||||||
@@ -469,20 +469,20 @@ function line(ctx, x1, y1, x2, y2) {
|
|||||||
|
|
||||||
function collectObjects() {
|
function collectObjects() {
|
||||||
const objects = [
|
const objects = [
|
||||||
objectForPoint("player", "Player Spawn", state.map.playerSpawn),
|
objectForPoint("player", "玩家出生点", state.map.playerSpawn),
|
||||||
objectForRect("camera", "Camera", state.map.camera),
|
objectForRect("camera", "摄像机范围", state.map.camera),
|
||||||
];
|
];
|
||||||
state.map.tilesets.forEach((tileset, index) => objects.push(objectForTileset(`tileset:${index}`, `Tileset ${tileset.id}`, tileset, 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}`, `Collision ${index + 1}`, rect, true)));
|
state.map.collisions.forEach((rect, index) => objects.push(objectForRect(`collision:${index}`, `碰撞块 ${index + 1}`, rect, true)));
|
||||||
state.map.layers.forEach((layer, layerIndex) => {
|
state.map.layers.forEach((layer, layerIndex) => {
|
||||||
objects.push(objectForLayer(`layer:${layerIndex}`, `Layer ${layer.id}`, layer, true));
|
objects.push(objectForLayer(`layer:${layerIndex}`, `图层 ${layer.id}`, layer, true));
|
||||||
layer.rects.forEach((rect, rectIndex) => objects.push(objectForRect(`rect:${layerIndex}:${rectIndex}`, `${layer.id} Rect ${rectIndex + 1}`, rect.bounds, 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} TileRect ${tileIndex + 1}`, tileRect, true)));
|
layer.tileRects.forEach((tileRect, tileIndex) => objects.push(objectForTileRect(`tile:${layerIndex}:${tileIndex}`, `${layer.id} 铺砖区 ${tileIndex + 1}`, tileRect, true)));
|
||||||
});
|
});
|
||||||
state.map.battleZones.forEach((zone, zoneIndex) => {
|
state.map.battleZones.forEach((zone, zoneIndex) => {
|
||||||
objects.push(objectForRect(`zone:${zoneIndex}`, `Battle Zone ${zoneIndex + 1}`, zone.trigger, true, zone.id));
|
objects.push(objectForRect(`zone:${zoneIndex}`, `战斗区 ${zoneIndex + 1}`, zone.trigger, true, zone.id));
|
||||||
objects.push(objectForRect(`zone_camera:${zoneIndex}`, `Zone Camera ${zoneIndex + 1}`, zone.camera, false, 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 ${spawn.id}`, spawn, true)));
|
zone.spawns.forEach((spawn, spawnIndex) => objects.push(objectForPoint(`spawn:${zoneIndex}:${spawnIndex}`, `出生点 ${spawn.id}`, spawn, true)));
|
||||||
});
|
});
|
||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
@@ -495,9 +495,9 @@ function objectForTileset(id, title, tileset, deletable) {
|
|||||||
deletable,
|
deletable,
|
||||||
fields: () => [
|
fields: () => [
|
||||||
textField("ID", () => tileset.id, (v) => { renameTileset(tileset.id, v || tileset.id); }),
|
textField("ID", () => tileset.id, (v) => { renameTileset(tileset.id, v || tileset.id); }),
|
||||||
textField("Texture", () => tileset.texture, (v) => { tileset.texture = v || tileset.texture; }),
|
textField("贴图路径", () => tileset.texture, (v) => { tileset.texture = v || tileset.texture; }),
|
||||||
numberField("Tile W", () => tileset.tileWidth, (v) => { tileset.tileWidth = Math.max(1, v); }),
|
numberField("图块宽", () => tileset.tileWidth, (v) => { tileset.tileWidth = Math.max(1, v); }),
|
||||||
numberField("Tile H", () => tileset.tileHeight, (v) => { tileset.tileHeight = Math.max(1, v); }),
|
numberField("图块高", () => tileset.tileHeight, (v) => { tileset.tileHeight = Math.max(1, v); }),
|
||||||
...colorFields(tileset.color, true),
|
...colorFields(tileset.color, true),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@@ -511,8 +511,8 @@ function objectForLayer(id, title, layer, deletable) {
|
|||||||
deletable,
|
deletable,
|
||||||
fields: () => [
|
fields: () => [
|
||||||
textField("ID", () => layer.id, (v) => { layer.id = v || layer.id; }),
|
textField("ID", () => layer.id, (v) => { layer.id = v || layer.id; }),
|
||||||
textField("Role", () => layer.role, (v) => { layer.role = v; }, ROLE_ORDER),
|
textField("类型", () => layer.role, (v) => { layer.role = v; }, ROLE_ORDER),
|
||||||
numberField("Parallax", () => layer.parallax, (v) => { layer.parallax = v; }, "0.05"),
|
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 }),
|
bounds: () => ({ x: tileRect.x, y: tileRect.y, width: tileRect.columns * tw, height: tileRect.rows * th }),
|
||||||
move(dx, dy) { tileRect.x += dx; tileRect.y += dy; },
|
move(dx, dy) { tileRect.x += dx; tileRect.y += dy; },
|
||||||
fields: () => [
|
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("X", () => tileRect.x, (v) => { tileRect.x = v; }),
|
||||||
numberField("Y", () => tileRect.y, (v) => { tileRect.y = v; }),
|
numberField("Y", () => tileRect.y, (v) => { tileRect.y = v; }),
|
||||||
numberField("Columns", () => tileRect.columns, (v) => { tileRect.columns = Math.max(1, Math.round(v)); }),
|
numberField("列数", () => 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("行数", () => 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.tileIndex, (v) => { tileRect.tileIndex = Math.max(0, Math.round(v)); }),
|
||||||
...colorFields(tileRect.color, false),
|
...colorFields(tileRect.color, false),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@@ -701,7 +701,7 @@ function deleteSelected() {
|
|||||||
if (parts[0] === "tileset") {
|
if (parts[0] === "tileset") {
|
||||||
const tileset = state.map.tilesets[Number(parts[1])];
|
const tileset = state.map.tilesets[Number(parts[1])];
|
||||||
if (tileset && isTilesetUsed(tileset.id)) {
|
if (tileset && isTilesetUsed(tileset.id)) {
|
||||||
setStatus(`Cannot delete tileset ${tileset.id}: it is used by tile_rect.`);
|
setStatus(`不能删除图块集 ${tileset.id}:它仍被 tile_rect 使用。`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.map.tilesets.splice(Number(parts[1]), 1);
|
state.map.tilesets.splice(Number(parts[1]), 1);
|
||||||
@@ -800,17 +800,17 @@ function tokenize(line) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function requireLayer(layer, lineNumber) {
|
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) {
|
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];
|
return tokens[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
function num(tokens, index, lineNumber) {
|
function num(tokens, index, lineNumber) {
|
||||||
const value = Number(requireToken(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;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -881,7 +881,7 @@ function renameTileset(oldId, newId) {
|
|||||||
const cleanId = String(newId).trim();
|
const cleanId = String(newId).trim();
|
||||||
if (!cleanId) return;
|
if (!cleanId) return;
|
||||||
if (cleanId !== oldId && state.map.tilesets.some((item) => item.id === cleanId)) {
|
if (cleanId !== oldId && state.map.tilesets.some((item) => item.id === cleanId)) {
|
||||||
setStatus(`Cannot rename tileset: ${cleanId} already exists.`);
|
setStatus(`不能重命名图块集:${cleanId} 已存在。`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const tileset = state.map.tilesets.find((item) => item.id === oldId);
|
const tileset = state.map.tilesets.find((item) => item.id === oldId);
|
||||||
|
|||||||
+26
-26
@@ -1,72 +1,72 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="zh-CN">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>NS Unknown Game Map Editor</title>
|
<title>NS Unknown Game 地图编辑器</title>
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<div>
|
<div>
|
||||||
<h1>Map Editor</h1>
|
<h1>地图编辑器</h1>
|
||||||
<p>Edits Frostbite2D .map text files used by the game runtime.</p>
|
<p>编辑游戏运行时使用的 Frostbite2D .map 文本地图。</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<button id="loadSampleButton" type="button">Load stage_01.map</button>
|
<button id="loadSampleButton" type="button">加载 stage_01.map</button>
|
||||||
<label class="file-button">
|
<label class="file-button">
|
||||||
Open .map
|
打开 .map
|
||||||
<input id="fileInput" type="file" accept=".map,text/plain">
|
<input id="fileInput" type="file" accept=".map,text/plain">
|
||||||
</label>
|
</label>
|
||||||
<button id="downloadButton" type="button">Download .map</button>
|
<button id="downloadButton" type="button">下载 .map</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="editor-shell">
|
<main class="editor-shell">
|
||||||
<aside class="panel left-panel">
|
<aside class="panel left-panel">
|
||||||
<section>
|
<section>
|
||||||
<h2>Map</h2>
|
<h2>地图</h2>
|
||||||
<div class="field-grid">
|
<div class="field-grid">
|
||||||
<label>
|
<label>
|
||||||
ID
|
地图 ID
|
||||||
<input id="mapIdInput" type="text">
|
<input id="mapIdInput" type="text">
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
World W
|
世界宽
|
||||||
<input id="worldWidthInput" type="number" step="1">
|
<input id="worldWidthInput" type="number" step="1">
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
World H
|
世界高
|
||||||
<input id="worldHeightInput" type="number" step="1">
|
<input id="worldHeightInput" type="number" step="1">
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Grid
|
网格
|
||||||
<input id="gridSizeInput" type="number" step="1" min="1" value="10">
|
<input id="gridSizeInput" type="number" step="1" min="1" value="10">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2>Add</h2>
|
<h2>新增</h2>
|
||||||
<div class="button-grid">
|
<div class="button-grid">
|
||||||
<button id="addTilesetButton" type="button">Tileset</button>
|
<button id="addTilesetButton" type="button">图块集</button>
|
||||||
<button id="addLayerButton" type="button">Layer</button>
|
<button id="addLayerButton" type="button">图层</button>
|
||||||
<button id="addCollisionButton" type="button">Collision</button>
|
<button id="addCollisionButton" type="button">碰撞块</button>
|
||||||
<button id="addTileRectButton" type="button">Tile Rect</button>
|
<button id="addTileRectButton" type="button">铺砖区</button>
|
||||||
<button id="addBattleZoneButton" type="button">Battle Zone</button>
|
<button id="addBattleZoneButton" type="button">战斗区</button>
|
||||||
<button id="addSpawnButton" type="button">Spawn</button>
|
<button id="addSpawnButton" type="button">出生点</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="object-section">
|
<section class="object-section">
|
||||||
<h2>Objects</h2>
|
<h2>对象</h2>
|
||||||
<div id="objectList" class="object-list"></div>
|
<div id="objectList" class="object-list"></div>
|
||||||
</section>
|
</section>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<section class="canvas-panel">
|
<section class="canvas-panel">
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<span id="statusText">Ready</span>
|
<span id="statusText">就绪</span>
|
||||||
<span id="viewText"></span>
|
<span id="viewText"></span>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="mapCanvas" width="1280" height="720"></canvas>
|
<canvas id="mapCanvas" width="1280" height="720"></canvas>
|
||||||
@@ -74,19 +74,19 @@
|
|||||||
|
|
||||||
<aside class="panel right-panel">
|
<aside class="panel right-panel">
|
||||||
<section>
|
<section>
|
||||||
<h2>Selection</h2>
|
<h2>选中对象</h2>
|
||||||
<div id="selectionSummary" class="selection-summary">Nothing selected.</div>
|
<div id="selectionSummary" class="selection-summary">未选择对象。</div>
|
||||||
<div id="propertyPanel" class="property-panel"></div>
|
<div id="propertyPanel" class="property-panel"></div>
|
||||||
<button id="deleteButton" type="button" class="danger-button">Delete Selected</button>
|
<button id="deleteButton" type="button" class="danger-button">删除选中对象</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2>Tilesets</h2>
|
<h2>图块集</h2>
|
||||||
<div id="tilesetList" class="tileset-list"></div>
|
<div id="tilesetList" class="tileset-list"></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2>Output</h2>
|
<h2>导出文本</h2>
|
||||||
<textarea id="outputText" spellcheck="false"></textarea>
|
<textarea id="outputText" spellcheck="false"></textarea>
|
||||||
</section>
|
</section>
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
Reference in New Issue
Block a user