feat(tools): 添加 CLI 模块管理命令和文档验证 demos
- CLI 新增 list/add/remove 命令管理项目模块 - 创建 demos 包验证模块文档正确性 - 包含 Timer/FSM/Pathfinding/Procgen/Spatial 5个模块的完整测试
This commit is contained in:
164
packages/tools/demos/src/pathfinding.demo.ts
Normal file
164
packages/tools/demos/src/pathfinding.demo.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* Pathfinding Module Demo - Tests APIs from docs/modules/pathfinding/index.md
|
||||
*/
|
||||
|
||||
import {
|
||||
createGridMap,
|
||||
createAStarPathfinder,
|
||||
createLineOfSightSmoother,
|
||||
createCatmullRomSmoother,
|
||||
manhattanDistance,
|
||||
octileDistance
|
||||
} from '@esengine/pathfinding';
|
||||
|
||||
function assert(condition: boolean, message: string): void {
|
||||
if (!condition) throw new Error(`FAILED: ${message}`);
|
||||
console.log(` ✓ ${message}`);
|
||||
}
|
||||
|
||||
function section(name: string): void {
|
||||
console.log(`\n▶ ${name}`);
|
||||
}
|
||||
|
||||
export async function runPathfindingDemo(): Promise<void> {
|
||||
console.log('═══════════════════════════════════════');
|
||||
console.log(' Pathfinding Module Demo');
|
||||
console.log('═══════════════════════════════════════');
|
||||
|
||||
// 1. Create Grid Map
|
||||
section('1. createGridMap()');
|
||||
const grid = createGridMap(20, 20);
|
||||
assert(grid !== null, 'Grid created');
|
||||
assert(grid.width === 20, 'Width is 20');
|
||||
assert(grid.height === 20, 'Height is 20');
|
||||
|
||||
// 2. Walkability
|
||||
section('2. setWalkable() / isWalkable()');
|
||||
assert(grid.isWalkable(5, 5), 'Initially walkable');
|
||||
grid.setWalkable(5, 5, false);
|
||||
assert(!grid.isWalkable(5, 5), 'Set to not walkable');
|
||||
grid.setWalkable(5, 5, true);
|
||||
assert(grid.isWalkable(5, 5), 'Restored to walkable');
|
||||
|
||||
// 3. Set Obstacles
|
||||
section('3. Setting Obstacles');
|
||||
grid.setWalkable(5, 5, false);
|
||||
grid.setWalkable(5, 6, false);
|
||||
grid.setWalkable(5, 7, false);
|
||||
assert(!grid.isWalkable(5, 6), 'Obstacle set');
|
||||
|
||||
// 4. Create Pathfinder
|
||||
section('4. createAStarPathfinder()');
|
||||
const pathfinder = createAStarPathfinder(grid);
|
||||
assert(pathfinder !== null, 'Pathfinder created');
|
||||
|
||||
// 5. Find Path
|
||||
section('5. findPath()');
|
||||
const result = pathfinder.findPath(0, 0, 15, 15);
|
||||
assert(result.found, 'Path found');
|
||||
assert(result.path.length > 0, `Path has ${result.path.length} points`);
|
||||
assert(result.cost > 0, `Path cost: ${result.cost.toFixed(2)}`);
|
||||
assert(result.nodesSearched > 0, `Searched ${result.nodesSearched} nodes`);
|
||||
|
||||
// 6. Path Blocked
|
||||
section('6. Path Blocked');
|
||||
// Create a wall
|
||||
for (let y = 0; y < 20; y++) {
|
||||
grid.setWalkable(10, y, false);
|
||||
}
|
||||
const blocked = pathfinder.findPath(0, 0, 15, 15);
|
||||
assert(!blocked.found, 'No path when fully blocked');
|
||||
|
||||
// Clear wall
|
||||
for (let y = 0; y < 20; y++) {
|
||||
grid.setWalkable(10, y, true);
|
||||
}
|
||||
|
||||
// 7. Movement Cost
|
||||
section('7. setCost()');
|
||||
const gridCost = createGridMap(10, 10);
|
||||
gridCost.setCost(5, 5, 10); // High cost tile
|
||||
const costResult = createAStarPathfinder(gridCost).findPath(0, 0, 9, 9);
|
||||
assert(costResult.found, 'Path found with cost');
|
||||
|
||||
// 8. Heuristics
|
||||
section('8. Heuristic Functions');
|
||||
const d1 = manhattanDistance({ x: 0, y: 0 }, { x: 3, y: 4 });
|
||||
assert(d1 === 7, `Manhattan distance: ${d1}`);
|
||||
|
||||
const d2 = octileDistance({ x: 0, y: 0 }, { x: 3, y: 4 });
|
||||
assert(d2 > 0, `Octile distance: ${d2.toFixed(2)}`);
|
||||
|
||||
// 9. Grid Options
|
||||
section('9. Grid Options');
|
||||
const gridOpts = createGridMap(10, 10, {
|
||||
allowDiagonal: false,
|
||||
heuristic: manhattanDistance
|
||||
});
|
||||
assert(gridOpts !== null, 'Grid with options created');
|
||||
|
||||
// 10. Path Smoothing - Line of Sight
|
||||
section('10. Line of Sight Smoother');
|
||||
const gridSmooth = createGridMap(20, 20);
|
||||
const pf = createAStarPathfinder(gridSmooth);
|
||||
const rawPath = pf.findPath(0, 0, 10, 10);
|
||||
|
||||
const losSmoother = createLineOfSightSmoother();
|
||||
const smoothed = losSmoother.smooth(rawPath.path, gridSmooth);
|
||||
assert(smoothed.length <= rawPath.path.length, `Smoothed: ${rawPath.path.length} -> ${smoothed.length} points`);
|
||||
|
||||
// 11. Catmull-Rom Smoother
|
||||
section('11. Catmull-Rom Smoother');
|
||||
const crSmoother = createCatmullRomSmoother(5, 0.5);
|
||||
const curved = crSmoother.smooth(rawPath.path, gridSmooth);
|
||||
assert(curved.length >= rawPath.path.length, `Curved path has ${curved.length} points`);
|
||||
|
||||
// 12. loadFromArray
|
||||
section('12. loadFromArray()');
|
||||
const gridArr = createGridMap(5, 3);
|
||||
gridArr.loadFromArray([
|
||||
[0, 0, 0, 1, 0],
|
||||
[0, 1, 0, 1, 0],
|
||||
[0, 1, 0, 0, 0]
|
||||
]);
|
||||
assert(!gridArr.isWalkable(3, 0), 'Loaded obstacle at (3,0)');
|
||||
assert(!gridArr.isWalkable(1, 1), 'Loaded obstacle at (1,1)');
|
||||
assert(gridArr.isWalkable(0, 0), 'Loaded walkable at (0,0)');
|
||||
|
||||
// 13. loadFromString
|
||||
section('13. loadFromString()');
|
||||
const gridStr = createGridMap(5, 3);
|
||||
gridStr.loadFromString(`
|
||||
.....
|
||||
.#.#.
|
||||
.#...
|
||||
`);
|
||||
assert(!gridStr.isWalkable(1, 1), 'Loaded # as obstacle');
|
||||
assert(gridStr.isWalkable(0, 0), 'Loaded . as walkable');
|
||||
|
||||
// 14. setRectWalkable
|
||||
section('14. setRectWalkable()');
|
||||
const gridRect = createGridMap(10, 10);
|
||||
gridRect.setRectWalkable(2, 2, 4, 4, false);
|
||||
assert(!gridRect.isWalkable(3, 3), 'Rect set as obstacle');
|
||||
assert(gridRect.isWalkable(0, 0), 'Outside rect is walkable');
|
||||
|
||||
// 15. Pathfinder Options
|
||||
section('15. Pathfinder Options');
|
||||
const limitedResult = pathfinder.findPath(0, 0, 15, 15, {
|
||||
maxNodes: 100,
|
||||
heuristicWeight: 1.5
|
||||
});
|
||||
assert(limitedResult !== null, 'findPath with options works');
|
||||
|
||||
// 16. Reset Grid
|
||||
section('16. reset()');
|
||||
grid.reset();
|
||||
assert(grid.isWalkable(5, 5), 'Grid reset - all walkable');
|
||||
|
||||
console.log('\n═══════════════════════════════════════');
|
||||
console.log(' Pathfinding Demo: ALL TESTS PASSED ✓');
|
||||
console.log('═══════════════════════════════════════\n');
|
||||
}
|
||||
|
||||
runPathfindingDemo().catch(console.error);
|
||||
Reference in New Issue
Block a user