docs(procgen): demonstrate script-first hot reload pipeline
This commit is contained in:
1 parent
d6d04d5f28
commit
fd3146578e
5 files changed
+139
-3
No files matched your search
@@ -17,6 +17,52 @@ local grid = gen.generate("dungeon.bsp", p);
|
||||
|
||||
`Params` 描述 seed、尺寸和算法参数;`Grid2D` 是结果;`OutputSpec` 决定写入 TileLayer、Image 或 Texture;`Procgen` 按注册算法名执行。
|
||||
|
||||
## 纯脚本 PointSet 管线
|
||||
|
||||
程序化世界编排使用普通 Squirrel 函数,不要求节点图。`PointSet` 是带位置、法线、
|
||||
旋转、缩放、密度、独立 seed 和自定义属性的 3D 采样集合。`sampleGrid`、
|
||||
`filterHeight`、`filterDensity`、`excludeRadius`、`jitterPoints` 和 `selfPrune`
|
||||
均返回新的集合,不修改输入,因此中间结果可以命名、检查、复用或分支:
|
||||
|
||||
```squirrel
|
||||
local rootSeed = 42;
|
||||
local candidates = procgen.sampleGrid(32, 20, 2.0,
|
||||
procgen.deriveSeed(rootSeed, "trees"), 0.75);
|
||||
local outsideRoad = procgen.excludeRadius(candidates, 20.0, 12.0, 4.0);
|
||||
local trees = procgen.selfPrune(outsideRoad, 1.8);
|
||||
```
|
||||
|
||||
不要让不同内容共享一个可变随机流。用 `deriveSeed(root, "trees")`、
|
||||
`deriveSeed(root, "rocks")` 为分支派生稳定 seed;修改岩石管线不会扰动树木结果。
|
||||
|
||||
### 事务式 hot reload
|
||||
|
||||
命名 `ProcgenContext` 是一次完整重建的 staging 区。`publish` 会复制输出,
|
||||
`commitSystem` 成功后才原子替换该系统的上次快照;`fail`、`abortSystem`、脚本异常或
|
||||
未提交的 context 都不会破坏旧结果:
|
||||
|
||||
```squirrel
|
||||
function rebuildForest(seed) {
|
||||
local ctx = procgen.beginSystem("forest", seed);
|
||||
try {
|
||||
local points = procgen.sampleGrid(32, 20, 2.0, ctx.seedFor("trees"), 0.8);
|
||||
local trees = procgen.selfPrune(points, 1.8);
|
||||
ctx.trace("self prune", points.getCount(), trees.getCount(), 0.0);
|
||||
if (!ctx.publish("trees", trees)) throw ctx.getError();
|
||||
if (!procgen.commitSystem(ctx)) throw procgen.lastError();
|
||||
} catch (error) {
|
||||
ctx.fail(error.tostring());
|
||||
procgen.commitSystem(ctx); // 失败并关闭 staging;旧快照仍然有效
|
||||
}
|
||||
}
|
||||
|
||||
eve_reload <- function() { rebuildForest(42); };
|
||||
```
|
||||
|
||||
`getSystemOutput` 返回已提交输出的副本;`getSystemRevision` 可判断是否成功换代;
|
||||
`getSystemDebugReport` 输出 seed、revision、命名阶段点数/耗时和最终输出点数。
|
||||
可运行示例见 [`examples/procgen-script-pipeline`](../../../examples/procgen-script-pipeline/README.md)。
|
||||
|
||||
## 目标导向指南
|
||||
|
||||
### 生成可玩的地牢层
|
||||
@@ -203,13 +249,13 @@ local mesh = gen.generateMesh("mesh.stonewall", p, gfx); // 或 mesh.fence / mes
|
||||
|
||||
下列方法名来自当前 Squirrel 绑定;同一模块创建的辅助对象(例如 `World`、`Body`、`Source`)的方法也列在这里。
|
||||
|
||||
- `addObject()`、`addObjectAt()`、`applyToLayer()`、`autotileGrid()`、`buildMesh()`、`clearObjects()`、`fill()`、`generate()`、`generateImage()`、`generateMesh()`、`generateNormalImage()`
|
||||
- `abort()`、`abortSystem()`、`add()`、`addObject()`、`addObjectAt()`、`applyToLayer()`、`autotileGrid()`、`beginSystem()`、`buildMesh()`、`clear()`、`clearObjects()`、`commitSystem()`、`deriveSeed()`、`empty()`、`excludeRadius()`、`fail()`、`fill()`、`filterDensity()`、`filterHeight()`、`generate()`、`generateImage()`、`generateMesh()`、`generateNormalImage()`
|
||||
- `generateTexture()`、`generateTo()`、`getAlgorithmCount()`、`getAlgorithmId()`、`getCell()`、`getDetail()`、`getFloat()`、`getHeight()`、`getInt()`
|
||||
- `getLayer()`、`getMeshRecipeCount()`、`getMeshRecipeId()`、`getMeta()`、`getName()`、`getObjectCount()`、`getObjectGid()`、`getObjectHeight()`、`getObjectName()`、`getObjectType()`
|
||||
- `getObjectWidth()`、`getObjectX()`、`getObjectY()`、`getPalette()`、`getPaletteGid()`、`getPath()`、`getSeed()`、`getString()`
|
||||
- `getTarget()`、`getTextureRecipeCount()`、`getTextureRecipeId()`、`getWidth()`、`gridToJson()`、`has()`、`hasAlgorithm()`、`hasMeshRecipe()`、`hasTextureRecipe()`
|
||||
- `lastError()`、`newGrid()`、`newOutput()`、`newParams()`、`randomSeed()`、`resize()`、`setCell()`、`setDetail()`、`setFloat()`、`setInt()`
|
||||
- `setLayer()`、`setMeta()`、`setPalette()`、`setPaletteGid()`、`setPath()`、`setSeed()`、`setSize()`、`setString()`
|
||||
- `getDensity()`、`getError()`、`getFloatAttribute()`、`getNormalX()`、`getNormalY()`、`getNormalZ()`、`getOutput()`、`getOutputCount()`、`getOutputName()`、`getPointSeed()`、`getScaleX()`、`getScaleY()`、`getScaleZ()`、`getStringAttribute()`、`getSystemDebugReport()`、`getSystemOutput()`、`getSystemOutputCount()`、`getSystemOutputName()`、`getSystemRevision()`、`getSystemSeed()`、`getTraceCount()`、`getTraceInputCount()`、`getTraceMilliseconds()`、`getTraceName()`、`getTraceOutputCount()`、`getX()`、`getY()`、`getYaw()`、`getZ()`、`hasFailed()`、`hasFloatAttribute()`、`hasOutput()`、`hasStringAttribute()`、`hasSystem()`、`isActive()`、`jitterPoints()`、`lastError()`、`newGrid()`、`newOutput()`、`newParams()`、`newPointSet()`、`publish()`、`randomSeed()`、`removeSystem()`、`resize()`、`sampleGrid()`、`seedFor()`、`selfPrune()`、`setCell()`、`setDensity()`、`setDetail()`、`setFloat()`、`setFloatAttribute()`、`setInt()`
|
||||
- `setLayer()`、`setMeta()`、`setNormal()`、`setPalette()`、`setPaletteGid()`、`setPath()`、`setPointSeed()`、`setPosition()`、`setScale()`、`setSeed()`、`setSize()`、`setString()`、`setStringAttribute()`、`setYaw()`、`trace()`
|
||||
- `setTarget()`
|
||||
|
||||
## 使用要点
|
||||
|
||||
@@ -57,6 +57,7 @@ make run/<platform>-debug GAME=examples/<name>
|
||||
| 示例 | 演示能力 |
|
||||
|---|---|
|
||||
| [procgen](procgen/README.md) | 六种地图算法(BSP / Cellular / Drunkard / Maze / 地形 / WFC)+ 纹理配方 |
|
||||
| [procgen-script-pipeline](procgen-script-pipeline/README.md) | 纯脚本 PointSet 组合、确定性 seed、事务式 hot reload |
|
||||
| [roguelike-generator](roguelike-generator/README.md) | 种子驱动的房间走廊地牢:autotile、装饰、2D ↔ 2.5D |
|
||||
| [tree-generator](tree-generator/README.md) | 确定性树木:Weber-Penn / 空间殖民两种骨架算法 |
|
||||
| [bush-generator](bush-generator/README.md) | 低多边形灌木配方(mesh.bush)与参数实时调节 |
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Procgen Script Pipeline
|
||||
|
||||
纯 Squirrel 程序化生成示例,不使用节点图:网格采样、排除区和自裁剪通过普通函数组合,
|
||||
最终 `PointSet` 在一个命名事务中原子提交。
|
||||
|
||||
```powershell
|
||||
make run/win32-debug GAME=examples/procgen-script-pipeline
|
||||
```
|
||||
|
||||
- 修改并保存 `main.nut`:`eve_reload` 会重建 `forest`;生成失败时保留上次结果。
|
||||
- 按 `R`:更换根 seed 并重新生成。
|
||||
- 控制台会输出每个命名阶段的输入/输出点数、系统 revision 和 seed。
|
||||
|
||||
示例目前用中央圆形排除区模拟道路或广场。未来的 Surface、Spline 和 Volume 输入可继续
|
||||
返回 `PointSet`,不需要改变脚本编排形式。
|
||||
@@ -0,0 +1,6 @@
|
||||
config <- {
|
||||
width = 960
|
||||
height = 640
|
||||
title = "EVEngine Procgen — Script Pipeline"
|
||||
hotReload = true
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
// Code-first procedural pipeline. Edit this file while the example is running:
|
||||
// eve_reload rebuilds a complete staging snapshot and atomically commits it.
|
||||
|
||||
if (!("forestSeed" in getroottable())) forestSeed <- 42;
|
||||
if (!("forestPoints" in getroottable())) forestPoints <- null;
|
||||
if (!("pipelineStatus" in getroottable())) pipelineStatus <- "not generated";
|
||||
|
||||
gfx.setBackgroundColor(0.055, 0.075, 0.07, 1.0);
|
||||
|
||||
function rebuildForest() {
|
||||
local ctx = procgen.beginSystem("forest", forestSeed);
|
||||
if (ctx == null) {
|
||||
pipelineStatus = procgen.lastError();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
local candidates = procgen.sampleGrid(28, 18, 28.0, ctx.seedFor("candidates"), 0.8);
|
||||
ctx.trace("sampleGrid", 0, candidates.getCount(), 0.0);
|
||||
|
||||
// This circular exclusion stands in for a future road/spline exclusion input.
|
||||
local awayFromPlaza = procgen.excludeRadius(candidates, 380.0, 230.0, 105.0);
|
||||
ctx.trace("exclude plaza", candidates.getCount(), awayFromPlaza.getCount(), 0.0);
|
||||
|
||||
local trees = procgen.selfPrune(awayFromPlaza, 32.0);
|
||||
ctx.trace("self prune", awayFromPlaza.getCount(), trees.getCount(), 0.0);
|
||||
if (!ctx.publish("trees", trees)) throw ctx.getError();
|
||||
|
||||
if (!procgen.commitSystem(ctx)) throw procgen.lastError();
|
||||
forestPoints = procgen.getSystemOutput("forest", "trees");
|
||||
pipelineStatus = procgen.getSystemDebugReport("forest");
|
||||
print("\n" + pipelineStatus + "\n");
|
||||
} catch (error) {
|
||||
ctx.fail(error.tostring());
|
||||
// A failed commit closes staging but leaves the last committed forest intact.
|
||||
procgen.commitSystem(ctx);
|
||||
forestPoints = procgen.getSystemOutput("forest", "trees");
|
||||
pipelineStatus = "rebuild failed, previous snapshot kept: " + error.tostring();
|
||||
}
|
||||
}
|
||||
|
||||
eve_init <- function() {
|
||||
rebuildForest();
|
||||
};
|
||||
|
||||
eve_reload <- function() {
|
||||
rebuildForest();
|
||||
};
|
||||
|
||||
eve_update <- function(dt) {
|
||||
if (key_just_pressed("R")) {
|
||||
forestSeed += 1;
|
||||
rebuildForest();
|
||||
}
|
||||
};
|
||||
|
||||
eve_render <- function() {
|
||||
gfx.clear();
|
||||
gfx.drawSolidRect(380.0 - 105.0, 230.0 - 105.0, 210.0, 210.0, 0.12, 0.15, 0.14, 1.0);
|
||||
if (forestPoints == null) return;
|
||||
for (local i = 0; i < forestPoints.getCount(); i += 1) {
|
||||
local x = 70.0 + forestPoints.getX(i);
|
||||
local y = 70.0 + forestPoints.getZ(i);
|
||||
local size = 5.0 + (forestPoints.getPointSeed(i) % 5);
|
||||
gfx.drawSolidRect(x - size * 0.5, y - size * 0.5, size, size,
|
||||
0.18, 0.48, 0.25, 1.0);
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user