Skip to content

Commit c5de5dc

Browse files
author
DavidQ
committed
Audit remaining Asteroids direct draw paths after manifest object render cleanup - PR_26133_128-asteroids-effect-render-path-audit
1 parent 798c45f commit c5de5dc

4 files changed

Lines changed: 104 additions & 15 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# PR_26133_128 Asteroids Effect Render Path Audit
2+
3+
## Summary
4+
- Audited the direct renderer draws left after PR_26133_127.
5+
- Kept UI/effect draws out of Object Vector Studio V2 when they are not persistent object geometry.
6+
- Removed the remaining hardcoded object-like effect geometry: ship debris fragments now derive their segment geometry from the manifest-owned ship hull points already loaded by `AsteroidsWorld`.
7+
- Did not change ship flame flicker, asteroid scale tuning, manifest object geometry, or vector map fallback behavior.
8+
9+
## Direct Draw Classification
10+
11+
| Path | Classification | Decision |
12+
| --- | --- | --- |
13+
| Starfield background pixels | Allowed non-object effect/UI draw; intentional runtime effect | Stays as the custom background callback. Stars are procedural background pixels, not Object Vector Studio V2 objects. |
14+
| HUD/menu text | Allowed non-object effect/UI draw | Stays as renderer text. Scores, labels, and prompts are UI text, not game object geometry. |
15+
| Attract text panels | Allowed non-object effect/UI draw | Stays as translucent UI panel rectangles. They frame text and are not authored gameplay objects. |
16+
| Demo trail pixels | Documented as intentional runtime effect | Stays as procedural 2x2 trail pixels tied to demo motion and fade timing. |
17+
| Pause/initials overlays | Allowed non-object effect/UI draw | Stays as modal UI rectangles/text/strokes. They are interface state, not manifest object geometry. |
18+
| Particle effects | Documented as intentional runtime effect | Stays in the generic particle system. Explosion particles are transient circles/rects with randomized size, velocity, and fade. |
19+
| Ship debris fragments | Should use manifest object geometry source; documented as intentional runtime effect | Updated. Debris remains a direct draw effect because fragments need independent velocity/spin/fade, but its hull segments now come from manifest-derived ship geometry instead of a second hardcoded ship shape. |
20+
21+
## Code Changes
22+
- `games/Asteroids/systems/ShipDebrisSystem.js`
23+
- Removed the hardcoded `SHIP_SEGMENTS` ship outline.
24+
- Builds debris segments from injected ship geometry points.
25+
- Fails visibly/actionably if debris spawn is attempted without manifest-derived hull segments.
26+
- `games/Asteroids/game/AsteroidsGameScene.js`
27+
- Passes `this.world.shipCollisionPoints` into `ShipDebrisSystem`; those points are loaded from the Asteroids Object Vector Studio V2 manifest.
28+
- `tests/games/AsteroidsPresentation.test.mjs`
29+
- Added targeted coverage proving ship debris uses the current manifest-owned scaled ship hull points.
30+
31+
## Validation
32+
- PASS: targeted Asteroids node validation:
33+
- `AsteroidsValidation`
34+
- `AsteroidsPresentation`
35+
- `AsteroidsVectorTransforms`
36+
- `AsteroidsPlatformDemo`
37+
- `AsteroidsAssetReferenceAdoption`
38+
- PASS: targeted Workspace Manager V2/Asteroids Playwright validation:
39+
- `npx playwright test tests/playwright/tools/WorkspaceManagerV2.spec.mjs --project=playwright --workers=1 --reporter=list -g "loads Object Vector Studio V2 runtime assets into Asteroids gameplay rendering"`
40+
- PASS: `git diff --check`
41+
- Playwright impacted: Yes. This PR changes an Asteroids runtime effect path and validates launch, attract/demo, gameplay manifest rendering, and bullet/object rendering through the targeted browser slice.
42+
- Full samples smoke test skipped as requested; this PR only touches Asteroids effect render-path audit/cleanup.
43+
44+
## Manual Validation
45+
- Open `/games/Asteroids/index.html`.
46+
- Start gameplay and destroy the ship; expected: debris fragments appear as the same runtime destruction effect, using the manifest-owned ship hull shape as the segment source.
47+
- Let attract/demo run; expected: attract/demo objects still render from manifest Object Vector Studio V2 objects.
48+
- Fire bullets at multiple ship angles; expected: bullet geometry/style remains manifest-owned and bullet rotation follows firing direction.

games/Asteroids/game/AsteroidsGameScene.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,10 @@ export default class AsteroidsGameScene extends Scene {
143143
);
144144
this.gameOverAutoExitRemainingSeconds = 0;
145145
this.audio = new AsteroidsAudio();
146-
this.shipDebris = new ShipDebrisSystem({ rng: this.world.rng });
146+
this.shipDebris = new ShipDebrisSystem({
147+
rng: this.world.rng,
148+
shipGeometryPoints: this.world.shipCollisionPoints,
149+
});
147150
this.particles = new ParticleSystem();
148151
this.lastEnterPressed = false;
149152
this.lastOnePressed = false;

games/Asteroids/systems/ShipDebrisSystem.js

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,29 @@ ShipDebrisSystem.js
66
*/
77
import { randomRange } from '../utils/math.js';
88

9-
const SHIP_SEGMENTS = [
10-
[[14, 0], [-10, -8]],
11-
[[-10, -8], [-6, -3]],
12-
[[-6, -3], [-6, 3]],
13-
[[-6, 3], [-10, 8]],
14-
[[-10, 8], [14, 0]],
15-
];
9+
function normalizePoints(points) {
10+
return Array.isArray(points)
11+
? points.map((point) => ({
12+
x: Number(point?.x ?? 0),
13+
y: Number(point?.y ?? 0),
14+
})).filter((point) => Number.isFinite(point.x) && Number.isFinite(point.y))
15+
: [];
16+
}
17+
18+
function createShipSegments(points) {
19+
const normalized = normalizePoints(points);
20+
return normalized.slice(0, -1).map((start, index) => ({
21+
end: normalized[index + 1],
22+
start,
23+
})).filter((segment) => (
24+
segment.start.x !== segment.end.x
25+
|| segment.start.y !== segment.end.y
26+
));
27+
}
1628

17-
function rotatePoint([x, y], angle) {
29+
function rotatePoint(point, angle) {
30+
const x = Number(point?.x ?? 0);
31+
const y = Number(point?.y ?? 0);
1832
return {
1933
x: x * Math.cos(angle) - y * Math.sin(angle),
2034
y: x * Math.sin(angle) + y * Math.cos(angle),
@@ -27,15 +41,20 @@ function whiteWithAlpha(alpha) {
2741
}
2842

2943
export default class ShipDebrisSystem {
30-
constructor({ rng = Math.random } = {}) {
44+
constructor({ rng = Math.random, shipGeometryPoints = [] } = {}) {
3145
this.fragments = [];
3246
this.rng = typeof rng === 'function' ? rng : Math.random;
47+
this.shipSegments = createShipSegments(shipGeometryPoints);
3348
}
3449

3550
spawn({ x, y, angle = -Math.PI / 2, vx = 0, vy = 0, lifeSeconds = 3 }) {
36-
SHIP_SEGMENTS.forEach((segment, index) => {
37-
const start = rotatePoint(segment[0], angle);
38-
const end = rotatePoint(segment[1], angle);
51+
if (!this.shipSegments.length) {
52+
console.error('FAIL Asteroids ship debris render blocked: manifest ship geometry did not provide debris hull segments.');
53+
return false;
54+
}
55+
this.shipSegments.forEach((segment, index) => {
56+
const start = rotatePoint(segment.start, angle);
57+
const end = rotatePoint(segment.end, angle);
3958
const burstAngle = angle + (-0.9 + index * 0.45);
4059
const speed = 90 + index * 26;
4160
this.fragments.push({
@@ -51,6 +70,7 @@ export default class ShipDebrisSystem {
5170
end,
5271
});
5372
});
73+
return true;
5474
}
5575

5676
clear() {
@@ -74,8 +94,8 @@ export default class ShipDebrisSystem {
7494

7595
render(renderer) {
7696
this.fragments.forEach((fragment) => {
77-
const start = rotatePoint([fragment.start.x, fragment.start.y], fragment.angle);
78-
const end = rotatePoint([fragment.end.x, fragment.end.y], fragment.angle);
97+
const start = rotatePoint(fragment.start, fragment.angle);
98+
const end = rotatePoint(fragment.end, fragment.angle);
7999
const lifeRatio = fragment.maxLifeSeconds > 0
80100
? fragment.lifeSeconds / fragment.maxLifeSeconds
81101
: 0;

tests/games/AsteroidsPresentation.test.mjs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,23 @@ function testAsteroidsGameplayObjectsUseSharedManifestBindings() {
315315
assert.equal(smallUfoCalls.every((call) => call.requireManifestBinding), true);
316316
}
317317

318+
function testAsteroidsShipDebrisUsesManifestShipHullGeometry() {
319+
const scene = new AsteroidsGameScene(createAsteroidsTestSceneOptions({
320+
objectVectorAssets: createObjectVectorAssetSet(),
321+
objectVectorRuntime: createObjectVectorRuntime([]),
322+
}));
323+
const spawned = scene.shipDebris.spawn({
324+
angle: 0,
325+
lifeSeconds: 1,
326+
x: 0,
327+
y: 0,
328+
});
329+
assert.equal(spawned, true);
330+
assert.equal(scene.shipDebris.fragments.length, 5);
331+
assert.deepEqual(scene.shipDebris.fragments[0].start, { x: 15.4, y: 0 });
332+
assert.deepEqual(scene.shipDebris.fragments[0].end, { x: -11, y: -8.8 });
333+
}
334+
318335
function testAsteroidsGameplayBulletsUseManifestObjectGeometry() {
319336
const renderCalls = [];
320337
const payload = loadAsteroidsObjectVectorPayload();
@@ -420,6 +437,7 @@ export function run() {
420437
testAsteroidsMenuHighScoreUsesLeaderboardTop();
421438
testAsteroidsAttractAsteroidsUseManifestObjectsAndStyles();
422439
testAsteroidsGameplayObjectsUseSharedManifestBindings();
440+
testAsteroidsShipDebrisUsesManifestShipHullGeometry();
423441
testAsteroidsGameplayBulletsUseManifestObjectGeometry();
424442
testAsteroidsGameplayRenderDoesNotCoverBackgroundLayer();
425443
}

0 commit comments

Comments
 (0)