Skip to content

Commit 925a866

Browse files
author
DavidQ
committed
1607 core loop
1 parent 0fbdb94 commit 925a866

7 files changed

Lines changed: 125 additions & 89 deletions

docs/dev/CODEX_COMMANDS.md

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,4 @@
1+
12
MODEL: GPT-5.3-codex
23
REASONING: high
3-
4-
COMMAND:
5-
Create BUILD_PR_LEVEL_17_12_SAMPLE_1606_PHYSICS_PLAYGROUND_IMPLEMENTATION.
6-
7-
Goal:
8-
Implement a real, testable improvement to Sample 1606 so the physics playground visibly demonstrates gravity, bounce, and multi-object motion.
9-
10-
Constraints:
11-
- one PR purpose only
12-
- smallest scoped valid change
13-
- no repo-wide scanning
14-
- no zip output from Codex
15-
- keep 2D and networking untouched
16-
- do not modify start_of_day
17-
18-
Implement:
19-
1. Inspect samples/phase-16/1606/PhysicsPlayground3DScene.js.
20-
2. Increase visible gravity and bounce clarity.
21-
3. Ensure at least two or more objects show distinct readable motion/interaction.
22-
4. Keep camera/render readability simple and stable.
23-
5. Extend tests/runtime/Phase16VisibilitySanity.test.mjs only if a surgical targeted check is useful.
24-
6. Update docs/dev/reports/change_summary.txt and docs/dev/reports/validation_checklist.txt.
25-
26-
Validate:
27-
- verify 1606 renders visible 3D content on load
28-
- verify gravity is visually obvious
29-
- verify bounce is clearly visible
30-
- verify multiple objects show distinct motion/interaction
31-
- run targeted smoke for 1606
32-
- run targeted affected sanity check
33-
- verify no 2D regression in targeted checks
34-
- verify no networking regression in targeted checks
35-
36-
Output:
37-
- modify repo files directly
38-
- do not create any zip
39-
- keep commit-ready changes minimal
4+
Implement 1607 loop.

docs/dev/COMMIT_COMMENT.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Implement a real visible physics playground improvement for Sample 1606 with targeted validation<BUILD_PR_LEVEL_17_12_SAMPLE_1606_PHYSICS_PLAYGROUND_IMPLEMENTATION>
1+
1607 core loop
Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1 @@
1-
BUILD_PR_LEVEL_17_12_SAMPLE_1606_PHYSICS_PLAYGROUND_IMPLEMENTATION
2-
3-
Scope:
4-
- Updated only Sample 1606 runtime physics behavior plus a surgical 1606 sanity assertion update.
5-
- Kept 2D systems and networking runtime code untouched.
6-
7-
Runtime changes:
8-
- Increased gravity strength for clearer vertical acceleration.
9-
- Tuned body profiles (size, bounce, mass, initial velocity) for readable and distinct motion.
10-
- Added lightweight AABB body-to-body collision resolution to make multi-object interaction visible.
11-
- Added collision telemetry line in the 1606 runtime panel for quick inspection.
12-
13-
Validation evidence:
14-
- `node --input-type=module -e "... import('./tests/runtime/Phase16VisibilitySanity.test.mjs') ..."` -> PASS
15-
- `node -e "... LaunchSmokeAllEntries ... --sample-range=1606-1606"` -> PASS
16-
- `node -e "... LaunchSmokeAllEntries ... --sample-range=0101-0101"` -> PASS (focused 2D regression check)
17-
- `node -e "... import('./tests/final/MultiplayerNetworkingStack.test.mjs') ..."` -> PASS
18-
- `node -e "... import('./tests/final/NetworkDebugAndServerDashboardCloseout.test.mjs') ..."` -> PASS
1+
1607 adds playable loop
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# Launch Smoke Report
22

3-
Generated: 2026-04-15T21:30:19.616Z
3+
Generated: 2026-04-15T21:41:25.257Z
44

5-
Filters: games=false, samples=true, tools=false, sampleRange=0101-0101
5+
Filters: games=false, samples=true, tools=false, sampleRange=1607-1607
66

77
| Status | Type | Label | Path | Notes | Steps |
88
| --- | --- | --- | --- | --- | --- |
9-
| PASS | sample | 0101 | samples\phase-01\0101\index.html | | npm install --prefix ./tmp ws → npm run test:launch-smoke |
9+
| PASS | sample | 1607 | samples\phase-16\1607\index.html | | npm install --prefix ./tmp ws → npm run test:launch-smoke |
Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
Sample 1606 implementation checklist
2-
[x] 1606 renders visible 3D content on load
3-
[x] gravity is visually obvious
4-
[x] bounce is clearly visible
5-
[x] multiple objects show distinct motion/interaction
6-
[x] sample is readable without extra explanation
7-
[x] targeted affected sanity passes
8-
[x] targeted smoke for 1606 passes
9-
[x] no 2D regression observed in targeted checks
10-
[x] no networking regression observed in targeted checks
1+
2+
[ ] movement
3+
[ ] shooting
4+
[ ] hit
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
Core loop PR for 1607: movement, shooting, hit detection. Testable only.

samples/phase-16/1607/SpaceShooter3DScene.js

Lines changed: 112 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ function createAsteroid(seed) {
2828
};
2929
}
3030

31+
function getCenter(transform3D, size3D) {
32+
return {
33+
x: transform3D.x + size3D.width * 0.5,
34+
y: transform3D.y + size3D.height * 0.5,
35+
z: transform3D.z + size3D.depth * 0.5,
36+
};
37+
}
38+
3139
export default class SpaceShooter3DScene extends Scene {
3240
constructor() {
3341
super();
@@ -48,8 +56,16 @@ export default class SpaceShooter3DScene extends Scene {
4856
this.bulletSpeed = 26;
4957
this.asteroidSpeed = 7.5;
5058
this.fireCooldown = 0;
59+
this.bulletHitPadding = 1.2;
5160
this.score = 0;
5261
this.misses = 0;
62+
this.loopMissLimit = 10;
63+
this.loopNumber = 1;
64+
this.loopElapsedSeconds = 0;
65+
this.loopScoreAtStart = 0;
66+
this.lastLoopScore = 0;
67+
this.lastLoopReason = 'active';
68+
this.resetLatch = false;
5369
}
5470

5571
setCamera3D(camera3D) {
@@ -83,8 +99,33 @@ export default class SpaceShooter3DScene extends Scene {
8399
asteroid.driftY = ((seed * 5) % 10 - 5) * 0.11;
84100
}
85101

102+
startLoop(reason = 'manual-reset') {
103+
this.lastLoopReason = reason;
104+
this.lastLoopScore = this.score - this.loopScoreAtStart;
105+
this.loopNumber += 1;
106+
this.loopElapsedSeconds = 0;
107+
this.loopScoreAtStart = this.score;
108+
this.misses = 0;
109+
this.fireCooldown = 0;
110+
this.bullets = [];
111+
this.ship.transform3D.x = 0;
112+
this.ship.transform3D.y = 0;
113+
this.ship.transform3D.z = 6.5;
114+
115+
this.asteroids.forEach((asteroid, asteroidIndex) => {
116+
this.resetAsteroid(asteroid, asteroidIndex + this.loopNumber * 11);
117+
});
118+
this.syncCamera();
119+
}
120+
86121
step3DPhysics(dt, engine) {
87122
const input = engine.input;
123+
const resetPressed = input?.isDown('KeyR') === true;
124+
if (resetPressed && !this.resetLatch) {
125+
this.startLoop('manual-reset');
126+
}
127+
this.resetLatch = resetPressed;
128+
88129
const moveX = (input?.isDown('KeyD') ? 1 : 0) - (input?.isDown('KeyA') ? 1 : 0);
89130
const moveY = (input?.isDown('KeyW') ? 1 : 0) - (input?.isDown('KeyS') ? 1 : 0);
90131
const moveLength = Math.hypot(moveX, moveY) || 1;
@@ -97,21 +138,63 @@ export default class SpaceShooter3DScene extends Scene {
97138
this.fireCooldown = Math.max(0, this.fireCooldown - dt);
98139
const firePressed = input?.isDown('Space') === true;
99140
if (firePressed && this.fireCooldown <= 0) {
141+
const bulletSize = { width: 0.25, height: 0.25, depth: 0.8 };
142+
const bulletTransform = {
143+
x: this.ship.transform3D.x + this.ship.size3D.width * 0.5 - bulletSize.width * 0.5,
144+
y: this.ship.transform3D.y + this.ship.size3D.height * 0.5 - bulletSize.height * 0.5,
145+
z: this.ship.transform3D.z + 1.7,
146+
};
147+
const bulletCenter = getCenter(bulletTransform, bulletSize);
148+
149+
let target = null;
150+
for (const asteroid of this.asteroids) {
151+
if (asteroid.transform3D.z + asteroid.size3D.depth < bulletTransform.z) {
152+
continue;
153+
}
154+
if (!target || asteroid.transform3D.z < target.transform3D.z) {
155+
target = asteroid;
156+
}
157+
}
158+
159+
let velocityX = 0;
160+
let velocityY = 0;
161+
let velocityZ = this.bulletSpeed;
162+
if (target) {
163+
const targetCenter = getCenter(target.transform3D, target.size3D);
164+
const dx = targetCenter.x - bulletCenter.x;
165+
const dy = targetCenter.y - bulletCenter.y;
166+
const dz = Math.max(0.8, targetCenter.z - bulletCenter.z);
167+
const magnitude = Math.hypot(dx, dy, dz) || 1;
168+
velocityX = (dx / magnitude) * this.bulletSpeed;
169+
velocityY = (dy / magnitude) * this.bulletSpeed;
170+
velocityZ = (dz / magnitude) * this.bulletSpeed;
171+
}
172+
100173
this.bullets.push({
101-
transform3D: {
102-
x: this.ship.transform3D.x + 0.38,
103-
y: this.ship.transform3D.y + 0.2,
104-
z: this.ship.transform3D.z + 1.7,
105-
},
106-
size3D: { width: 0.25, height: 0.25, depth: 0.8 },
174+
transform3D: bulletTransform,
175+
previousTransform3D: { ...bulletTransform },
176+
size3D: bulletSize,
177+
velocity3D: { x: velocityX, y: velocityY, z: velocityZ },
107178
});
108179
this.fireCooldown = 0.13;
109180
}
110181

111182
this.bullets.forEach((bullet) => {
112-
bullet.transform3D.z += this.bulletSpeed * dt;
183+
bullet.previousTransform3D.x = bullet.transform3D.x;
184+
bullet.previousTransform3D.y = bullet.transform3D.y;
185+
bullet.previousTransform3D.z = bullet.transform3D.z;
186+
bullet.transform3D.x += bullet.velocity3D.x * dt;
187+
bullet.transform3D.y += bullet.velocity3D.y * dt;
188+
bullet.transform3D.z += bullet.velocity3D.z * dt;
113189
});
114-
this.bullets = this.bullets.filter((bullet) => bullet.transform3D.z < 40);
190+
this.bullets = this.bullets.filter(
191+
(bullet) =>
192+
bullet.transform3D.z < 40 &&
193+
bullet.transform3D.x > -9 &&
194+
bullet.transform3D.x < 9 &&
195+
bullet.transform3D.y > -5 &&
196+
bullet.transform3D.y < 7,
197+
);
115198

116199
this.asteroids.forEach((asteroid, asteroidIndex) => {
117200
asteroid.transform3D.z -= this.asteroidSpeed * dt;
@@ -133,12 +216,15 @@ export default class SpaceShooter3DScene extends Scene {
133216
const asteroid = this.asteroids[asteroidIndex];
134217
const collided = isAabbColliding3D(
135218
{
136-
x: bullet.transform3D.x,
137-
y: bullet.transform3D.y,
138-
z: bullet.transform3D.z,
139-
width: bullet.size3D.width,
140-
height: bullet.size3D.height,
141-
depth: bullet.size3D.depth,
219+
x: Math.min(bullet.previousTransform3D.x, bullet.transform3D.x) - this.bulletHitPadding,
220+
y: Math.min(bullet.previousTransform3D.y, bullet.transform3D.y) - this.bulletHitPadding,
221+
z: Math.min(bullet.previousTransform3D.z, bullet.transform3D.z) - this.bulletHitPadding,
222+
width: bullet.size3D.width + this.bulletHitPadding * 2,
223+
height: bullet.size3D.height + this.bulletHitPadding * 2,
224+
depth:
225+
Math.abs(bullet.transform3D.z - bullet.previousTransform3D.z) +
226+
bullet.size3D.depth +
227+
this.bulletHitPadding * 2,
142228
},
143229
{
144230
x: asteroid.transform3D.x,
@@ -163,15 +249,20 @@ export default class SpaceShooter3DScene extends Scene {
163249
}
164250
}
165251

252+
this.loopElapsedSeconds += dt;
253+
if (this.misses >= this.loopMissLimit) {
254+
this.startLoop('miss-limit');
255+
}
256+
166257
this.syncCamera();
167258
}
168259

169260
render(renderer) {
170261
drawFrame(renderer, theme, [
171262
'Sample 1607 - 3D Space Shooter',
172-
'Pilot a ship lane, fire at incoming asteroids, and track score.',
173-
'Move: W A S D | Fire: Space',
174-
'Keep the asteroid lane clear before misses stack up.',
263+
'Pilot a ship lane, fire at incoming asteroids, and track looping rounds.',
264+
'Move: W A S D | Fire: Space | Reset round: R',
265+
'Round auto-resets when misses reach the round limit.',
175266
]);
176267

177268
renderer.strokeRect(this.viewport.x, this.viewport.y, this.viewport.width, this.viewport.height, '#d8d5ff', 2);
@@ -202,13 +293,14 @@ export default class SpaceShooter3DScene extends Scene {
202293
drawWireBox(renderer, asteroid.transform3D, asteroid.size3D, cameraState, projectionViewport, '#fb7185', 2);
203294
});
204295

205-
drawPanel(renderer, 620, 34, 300, 126, 'Shooter Runtime', [
296+
drawPanel(renderer, 620, 34, 300, 186, 'Shooter Runtime', [
206297
`Ship: x=${this.ship.transform3D.x.toFixed(2)} y=${this.ship.transform3D.y.toFixed(2)} z=${this.ship.transform3D.z.toFixed(2)}`,
207298
`Bullets: ${this.bullets.length} | Cooldown: ${this.fireCooldown.toFixed(2)} s`,
208299
`Asteroids: ${this.asteroids.length}`,
209300
`Score: ${this.score}`,
210-
`Misses: ${this.misses}`,
301+
`Round ${this.loopNumber} | Misses: ${this.misses}/${this.loopMissLimit}`,
302+
`Round time: ${this.loopElapsedSeconds.toFixed(1)} s | Last round score: ${this.lastLoopScore}`,
303+
`Last round reset: ${this.lastLoopReason}`,
211304
]);
212305
}
213306
}
214-

0 commit comments

Comments
 (0)