Files
EVEngine/docs/usr/modules/editor.md
T
西风逍遥游andCursor Agent 618fe97da4 feat(editor): 编辑器构件模块 — Gizmo / 笔刷 / UI 壳 (#36)
* feat(editor): 新增编辑器构件模块(gizmo / 笔刷 / UI 壳)

引擎不内置完整 3D 或地图编辑器,改为提供可组装构件:
TransformGizmo + GizmoManager(平移/旋转/缩放/包围盒)、
TileBuffer + Brush(paint/erase/fill/line/rect/stamp)、
以及 Toolbar / Inspector / Dock / History 辅助快速搭建编辑器 UI。
参考 Three.js、Babylon.js、ImGuizmo、Unity GridBrush 与 Godot 插件 API。

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* docs(editor): 标记编辑器模块 Phase A 已实现

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* fix(editor): avoid CHECK(unique_ptr) so zeroerr can compile tests

zeroerr's CHECK copies the expression for printing; unique_ptr is
non-copyable and broke unit_test on Linux/macOS/Windows.

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-08-12 17:35:09 +08:00

118 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 编辑器构件模块
**脚本入口:** `eve.Editor()`
引擎**不附带**完整 3D 场景编辑器或 2D 地图编辑器,而是提供组装自定义编辑器所需的构件:3D 变换操作框、地图笔刷、以及 Toolbar / Inspector / Dock / History 等 UI 状态辅助。
设计参考了 Three.js `TransformControls`、Babylon.js `GizmoManager`、ImGuizmo、Unity `GridBrushBase` 与 Godot 编辑器插件的常见 API 形态;详见[编辑器模块设计](../../dev/编辑器模块设计.md)。
## 基本用法
```squirrel
local editor = eve.Editor();
// 3D 操作框
local gizmo = editor.newGizmo();
gizmo.setMode("translate"); // translate | rotate | scale | bound
gizmo.setSpace("world"); // local | world
gizmo.setPosition(0, 1, 0);
gizmo.setSize(1.0);
// 每帧:用相机射线拾取并拖拽
local axis = gizmo.pick(rayOx, rayOy, rayOz, rayDx, rayDy, rayDz);
if (axis != "" && mouseDown) {
gizmo.beginDrag(axis, rayOx, rayOy, rayOz, rayDx, rayDy, rayDz);
}
if (gizmo.isDragging()) {
gizmo.updateDrag(rayOx, rayOy, rayOz, rayDx, rayDy, rayDz);
// 把 gizmo.getPosition* / getRotation* / getScale* 写回场景节点
}
if (mouseUp) gizmo.endDrag();
// 绘制:遍历 getPart* 用调试线 / 网格画出轴、环、平面
for (local i = 0; i < gizmo.getPartCount(); i++) {
local kind = gizmo.getPartKind(i); // axis | plane | ring | box | center | handle
// ...
}
```
## 地图笔刷
```squirrel
local buf = editor.newTileBuffer(64, 64);
local brush = editor.newBrush();
brush.setTool("paint"); // paint | erase | fill | line | rect | stamp
brush.setTile(3);
brush.setSize(3);
brush.setShape("circle");
brush.paintAt(buf, tx, ty);
// 同步到 map.TileLayer(示例)
for (local y = 0; y < buf.getHeight(); y++)
for (local x = 0; x < buf.getWidth(); x++)
layer.setTile(x, y, buf.getGid(x, y));
```
## 编辑器壳
```squirrel
local dock = editor.newDock();
dock.setRegionSize("left", 200);
dock.layout(config.width, config.height);
// 用 dock.getRegionX/Y/W/H("center"|"left"|...) 放置 ui 窗口
local toolbar = editor.newToolbar();
toolbar.addTool("move", "Move");
toolbar.addTool("paint", "Paint");
toolbar.setShortcut("move", "W");
local insp = editor.newInspector();
insp.addChoice("mode", "Mode", "translate,rotate,scale", "translate");
insp.addFloat3("pos", "Position", 0, 0, 0);
```
## 对象关系
| 类型 | 职责 |
|------|------|
| `TransformGizmo` | 单对象 TRS/包围盒手柄、射线交互、绘制部件 |
| `GizmoManager` | 多 mode 开关 + attach,转发 pick/drag(Babylon 风格) |
| `TileBuffer` | 与 `map` 解耦的 GID 网格 |
| `Brush` | 笔刷工具;产出 preview / change 列表 |
| `EditorHistory` | 撤销栈;瓦片分组可 `applyLastToBuffer` |
| Toolbar / Inspector / Dock | 仅状态与矩形,由 `ui` 渲染 |
## 目标导向指南
### 给场景节点加平移旋转缩放
创建 `GizmoManager`,`attach()` 后按需 `setPositionEnabled` / `setRotationEnabled` / `setScaleEnabled`;把相机 `screenToRay` 交给 `pick` / `updateDrag`,再写回 `scene` 节点 local TRS。
### 做简易 tile 地图编辑器
`TileBuffer` + `Brush` + `EditorHistory`:每次 `paintAt` 后把 `getChange*` 记入 `beginGroup`/`recordTile`/`endGroup`;Undo 时 `applyLastToBuffer`。用 `EditorDock` 划分调色板与视口,用 `EditorToolbar` 切换 paint/erase/fill。
## 常见问题
- 期望引擎弹出完整编辑器窗口——本模块只提供构件,需自行用 `ui` / `graphics` 组装。
- 笔刷直接改 `TileLayer`——请先画在 `TileBuffer`,再同步,避免模块硬耦合。
- `getPart*` 在 mode/TRS 变化后过期——调用 `rebuildParts()` 或任意 set*(多数 set 已自动重建)。
## API 快查
- 模块:`newGizmo` / `newGizmoManager` / `newTileBuffer` / `newBrush` / `newToolbar` / `newInspector` / `newDock` / `newHistory`
- Gizmo:`setMode` / `setSpace` / `setPosition` / `setRotationEuler` / `setScale` / `setBounds` / `setSnap*` / `pick` / `beginDrag` / `updateDrag` / `endDrag` / `getPart*`
- Manager:`set*Enabled` / `attach` / `detach` / `getGizmo` / `pick` / `beginDrag` / `updateDrag`
- Brush:`setTool` / `setSize` / `setShape` / `setTile` / `paintAt` / `eraseAt` / `floodFill` / `paintLine` / `paintRect` / `preview*` / `getChange*`
- History:`push` / `beginGroup` / `recordTile` / `endGroup` / `undo` / `redo` / `applyLastToBuffer`
## 使用要点
- 模块与辅助对象应长期持有;不要每帧 `newGizmo()`。
- 枚举一律 string,非法值抛异常。
- 绘制与输入由宿主完成;本模块不做 GPU 提交。
**源码:** [`src/modules/editor/`](../../../src/modules/editor/)
**设计文档:** [`docs/dev/编辑器模块设计.md`](../../dev/编辑器模块设计.md)
**相关测试:** [`test/editor.cpp`](../../../test/editor.cpp)