Skip to content

Commit eba085d

Browse files
author
DavidQ
committed
Move Asteroids vector maps into manifest single-source ownership and remove hardcoded runtime maps - PR_26133_113-manifest-vector-map-migration
1 parent 25fb295 commit eba085d

19 files changed

Lines changed: 1105 additions & 295 deletions
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# PR_26133_113-manifest-vector-map-migration Report
2+
3+
## Summary
4+
- Read `docs/dev/PROJECT_INSTRUCTIONS.md` before implementation.
5+
- Used `PR_26133_112-object-vector-shape-geometry-layout_report.md` as prior reference; the `PR_26133_112` delta ZIP was not present under `tmp/`.
6+
- Moved Asteroids vector map ownership into `games/Asteroids/game.manifest.json` under `tools.vector-map-editor.vectorMapDocument`.
7+
- Added manifest-owned vector maps for ship collision, life icon, UFO collision, attract ship/asteroid/UFO, and splash/attract/UI title metadata.
8+
- Added manifest-owned Object Vector runtime role bindings and removed hardcoded role object ID fallbacks from runtime resolution.
9+
- Routed Asteroids gameplay collision geometry, UFO geometry, life icon drawing, and attract silhouettes through manifest-loaded vector maps.
10+
- Runtime now fails visibly when required Asteroids vector maps or role bindings are missing instead of silently falling back to hardcoded vector data.
11+
12+
## Changed Files
13+
- `games/Asteroids/game.manifest.json`
14+
- `games/Asteroids/game/asteroidsVectorMaps.js`
15+
- `games/Asteroids/game/asteroidsObjectVectorRoles.js`
16+
- `games/Asteroids/game/AsteroidsGameScene.js`
17+
- `games/Asteroids/game/AsteroidsAttractAdapter.js`
18+
- `games/Asteroids/game/AsteroidsWorld.js`
19+
- `games/Asteroids/entities/Ship.js`
20+
- `games/Asteroids/entities/Ufo.js`
21+
- `games/Asteroids/index.js`
22+
- `tests/games/asteroidsManifestObjectVectors.mjs`
23+
- `tests/games/AsteroidsAssetReferenceAdoption.test.mjs`
24+
- `tests/games/AsteroidsPlatformDemo.test.mjs`
25+
- `tests/games/AsteroidsVectorTransforms.test.mjs`
26+
- `tests/games/AsteroidsCollisionTimingStress.test.mjs`
27+
- `tests/games/AsteroidsHardening.test.mjs`
28+
- `tests/games/AsteroidsValidation.test.mjs`
29+
- `tests/games/AsteroidsPresentation.test.mjs`
30+
- `tests/playwright/tools/WorkspaceManagerV2.spec.mjs`
31+
- `docs/dev/reports/PR_26133_113-manifest-vector-map-migration_report.md`
32+
33+
## Validation
34+
- PASS: `node --check games/Asteroids/game/asteroidsVectorMaps.js`
35+
- PASS: `node --check games/Asteroids/game/asteroidsObjectVectorRoles.js`
36+
- PASS: `node --check games/Asteroids/game/AsteroidsGameScene.js`
37+
- PASS: `node --check games/Asteroids/entities/Ship.js`
38+
- PASS: `node --check games/Asteroids/entities/Ufo.js`
39+
- PASS: `node --check games/Asteroids/game/AsteroidsWorld.js`
40+
- PASS: `node --check games/Asteroids/index.js`
41+
- PASS: `node -e "JSON.parse(require('fs').readFileSync('games/Asteroids/game.manifest.json','utf8')); console.log('manifest json ok');"`
42+
- PASS: targeted Asteroids manifest/vector-map validation command loaded 8 manifest vector maps with usage counts `{ gameplay: 4, collision: 3, ui: 2, attract: 4, splash: 1 }` and all 6 runtime role bindings.
43+
- PASS: targeted splash/attract/gameplay vector loading validation covered manifest `splash`, `attract`, `gameplay`, `collision`, and `ui` usage buckets, attract vector rendering, gameplay life icon vector rendering, and gameplay Object Vector runtime rendering.
44+
- PASS: targeted Asteroids tests:
45+
- `AsteroidsAssetReferenceAdoption`
46+
- `AsteroidsPlatformDemo`
47+
- `AsteroidsVectorTransforms`
48+
- `AsteroidsCollisionTimingStress`
49+
- `AsteroidsHardening`
50+
- `AsteroidsValidation`
51+
- `AsteroidsPresentation`
52+
- PASS: `git diff --check` (line-ending warnings only)
53+
- PASS: `npm run test:workspace-v2` (56 passed)
54+
55+
## Playwright
56+
- Playwright impacted: Yes.
57+
- Validated Workspace Manager V2 Asteroids manifest loading, vector-map-editor manifest persistence, attract vector map rendering, gameplay Object Vector rendering, gameplay life icon vector rendering, manifest role binding validation, and no hardcoded Asteroids asset injection on empty Asset Manager payloads.
58+
- Expected pass behavior: Asteroids boots from manifest-owned vector maps and Object Vector role bindings, renders attract/gameplay vectors, and exposes vector map diagnostics.
59+
- Expected fail behavior: tests fail if required vector maps are missing, role bindings are missing or tagless, hardcoded fallback injection returns, or Workspace V2 manifest save/status behavior regresses.
60+
- Playwright V8 coverage report was regenerated by the workspace-v2 run at `docs/dev/reports/playwright_v8_coverage_report.txt`; coverage remains advisory.
61+
62+
## Full Samples Smoke
63+
- Skipped full samples smoke test by request.
64+
- Reason: the change is scoped to Asteroids manifest/runtime vector-map ownership and targeted Workspace V2/Asteroids validations passed; shared sample loader/framework behavior was not changed.
65+
66+
## Manual Validation
67+
1. Open Workspace Manager V2 and select the Asteroids game manifest.
68+
2. Launch Asteroids from the workspace.
69+
3. Expected: Asteroids boots without vector map validation errors and attract mode renders manifest-backed ship/asteroid/UFO vectors.
70+
4. Start gameplay and force or wait for a UFO.
71+
5. Expected: ship, asteroids, UFO, collisions, and life icons use manifest-loaded vector/object geometry with no hardcoded vector-map fallback.
72+
6. Temporarily remove a required Asteroids vector map or `objectVectorRoles` binding from the manifest.
73+
7. Expected: boot/runtime validation fails visibly with the missing manifest vector map or role binding named in the error.
74+
75+
## ZIP
76+
- Output path: `tmp/PR_26133_113-manifest-vector-map-migration_delta.zip`

games/Asteroids/entities/Ship.js

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,20 @@ Ship.js
77
import { wrap } from '../utils/math.js';
88
import { transformPoints } from '../../../src/engine/rendering/index.js';
99

10-
const SMALL_VECTOR_MAP = [
11-
{ x: 14, y: 0 },
12-
{ x: -10, y: -8 },
13-
{ x: -6, y: -3 },
14-
{ x: -6, y: 3 },
15-
{ x: -10, y: 8 },
16-
{ x: 14, y: 0 },
17-
];
10+
function normalizePoints(points) {
11+
return Array.isArray(points)
12+
? points.map((point) => ({
13+
x: Number(point?.x ?? 0),
14+
y: Number(point?.y ?? 0),
15+
})).filter((point) => Number.isFinite(point.x) && Number.isFinite(point.y))
16+
: [];
17+
}
1818

1919
export default class Ship {
20-
constructor(x, y) {
20+
constructor(x, y, { collisionPoints = [] } = {}) {
2121
this.spawnX = x;
2222
this.spawnY = y;
23+
this.collisionPoints = normalizePoints(collisionPoints);
2324
this.reset();
2425
}
2526

@@ -55,21 +56,10 @@ export default class Ship {
5556
}
5657

5758
getPoints() {
58-
return transformPoints(SMALL_VECTOR_MAP, {
59+
return transformPoints(this.collisionPoints, {
5960
x: this.x,
6061
y: this.y,
6162
rotation: this.angle,
6263
});
6364
}
64-
65-
getFlamePoints(pulse = 1) {
66-
const rear = this.angle + Math.PI;
67-
const flameReach = (18 + pulse * 9) * 0.5;
68-
const wingSpread = (8 + pulse * 2) * 0.5;
69-
return [
70-
{ x: this.x + Math.cos(rear) * flameReach, y: this.y + Math.sin(rear) * flameReach },
71-
{ x: this.x + Math.cos(this.angle + 2.7) * wingSpread, y: this.y + Math.sin(this.angle + 2.7) * wingSpread },
72-
{ x: this.x + Math.cos(this.angle - 2.7) * wingSpread, y: this.y + Math.sin(this.angle - 2.7) * wingSpread },
73-
];
74-
}
7565
}

games/Asteroids/entities/Ufo.js

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,25 +26,22 @@ const UFO_PROFILES = {
2626
},
2727
};
2828

29-
const VECTOR_MAPS = {
30-
small: [
31-
{ x: -14, y: 3 }, { x: 14, y: 3 }, { x: 9, y: 9 }, { x: -9, y: 9 }, { x: -14, y: 3 }, { x: -9, y: -3 },
32-
{ x: -5, y: -3 }, { x: -5, y: -6 }, { x: -2, y: -9 }, { x: 2, y: -9 }, { x: 5, y: -6 }, { x: 5, y: -3 }, { x: -5, y: -3 },
33-
{ x: 9, y: -3 }, { x: 14, y: 3 },
34-
],
35-
large: [
36-
{ x: -21, y: 4.5 }, { x: 21, y: 4.5 }, { x: 13.5, y: 13.5 }, { x: -13.5, y: 13.5 }, { x: -21, y: 4.5 }, { x: -13.5, y: -4.5 },
37-
{ x: -7.5, y: -4.5 }, { x: -7.5, y: -9 }, { x: -3, y: -13.5 }, { x: 3, y: -13.5 }, { x: 7.5, y: -9 }, { x: 7.5, y: -4.5 }, { x: -7.5, y: -4.5 },
38-
{ x: 13.5, y: -4.5 }, { x: 21, y: 4.5 },
39-
],
40-
};
29+
function normalizePoints(points) {
30+
return Array.isArray(points)
31+
? points.map((point) => ({
32+
x: Number(point?.x ?? 0),
33+
y: Number(point?.y ?? 0),
34+
})).filter((point) => Number.isFinite(point.x) && Number.isFinite(point.y))
35+
: [];
36+
}
4137

4238
export default class Ufo {
43-
constructor(bounds, type = 'large', level = 1, rng = Math.random) {
39+
constructor(bounds, type = 'large', level = 1, rng = Math.random, { collisionPoints = [] } = {}) {
4440
this.bounds = bounds;
4541
this.rng = typeof rng === 'function' ? rng : Math.random;
4642
this.type = UFO_PROFILES[type] ? type : 'large';
4743
this.profile = UFO_PROFILES[this.type];
44+
this.collisionPoints = normalizePoints(collisionPoints);
4845
this.direction = this.rng() > 0.5 ? 1 : -1;
4946
this.x = this.direction > 0 ? -48 : bounds.width + 48;
5047
this.y = randomRange(120, bounds.height - 140, this.rng);
@@ -108,7 +105,7 @@ export default class Ufo {
108105
}
109106

110107
getCollisionPolygon() {
111-
return transformPoints(VECTOR_MAPS[this.type], {
108+
return transformPoints(this.collisionPoints, {
112109
x: this.x,
113110
y: this.y,
114111
});

0 commit comments

Comments
 (0)