Post-codex-review-5: align event-log с telemetry spec + UX polish
- MatchTracker (codex #1 Low): event-log поля переименованы под telemetry-spec.md v3.10 — ballOwner→ballOwnerBeforeHit, matchTimeSec→matchTimeSeconds (для bumper_hit и goal events). Future-proof для batched emit через .getEvents(). Тест assertion обновлён под новые поля. - Touch zone labels (codex #2 Low): BOOST 14→18px, alpha все лейблы 0.5→0.7 для mobile readability. - Test comment (codex #3 editorial): «player получает hits через ai_setup» → корректная формулировка про defensive trap (атакующий игрок кормит AI как защитника). 50/50 tests, typecheck/lint/build ✅. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -579,7 +579,7 @@ export class MatchScene extends Phaser.Scene {
|
|||||||
.text(sideW / 2, zoneY, '◀ L', {
|
.text(sideW / 2, zoneY, '◀ L', {
|
||||||
fontFamily: 'monospace', fontSize: '20px', color: '#ff006e', fontStyle: 'bold',
|
fontFamily: 'monospace', fontSize: '20px', color: '#ff006e', fontStyle: 'bold',
|
||||||
})
|
})
|
||||||
.setOrigin(0.5).setAlpha(0.5);
|
.setOrigin(0.5).setAlpha(0.7);
|
||||||
|
|
||||||
// Right zone
|
// Right zone
|
||||||
const rightX = GAME_WIDTH - sideW / 2;
|
const rightX = GAME_WIDTH - sideW / 2;
|
||||||
@@ -594,7 +594,7 @@ export class MatchScene extends Phaser.Scene {
|
|||||||
.text(rightX, zoneY, 'R ▶', {
|
.text(rightX, zoneY, 'R ▶', {
|
||||||
fontFamily: 'monospace', fontSize: '20px', color: '#ff006e', fontStyle: 'bold',
|
fontFamily: 'monospace', fontSize: '20px', color: '#ff006e', fontStyle: 'bold',
|
||||||
})
|
})
|
||||||
.setOrigin(0.5).setAlpha(0.5);
|
.setOrigin(0.5).setAlpha(0.7);
|
||||||
|
|
||||||
// Booster zone (центр, узкая) — Phase 2 placeholder
|
// Booster zone (центр, узкая) — Phase 2 placeholder
|
||||||
const boosterZone = this.add.rectangle(GAME_WIDTH / 2, zoneY, boosterW, zoneH * 0.5, PALETTE.accent, 0.05);
|
const boosterZone = this.add.rectangle(GAME_WIDTH / 2, zoneY, boosterW, zoneH * 0.5, PALETTE.accent, 0.05);
|
||||||
@@ -606,9 +606,9 @@ export class MatchScene extends Phaser.Scene {
|
|||||||
});
|
});
|
||||||
this.add
|
this.add
|
||||||
.text(GAME_WIDTH / 2, zoneY, 'BOOST', {
|
.text(GAME_WIDTH / 2, zoneY, 'BOOST', {
|
||||||
fontFamily: 'monospace', fontSize: '14px', color: '#ffbe0b', fontStyle: 'bold',
|
fontFamily: 'monospace', fontSize: '18px', color: '#ffbe0b', fontStyle: 'bold',
|
||||||
})
|
})
|
||||||
.setOrigin(0.5).setAlpha(0.5);
|
.setOrigin(0.5).setAlpha(0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildHUD(): void {
|
private buildHUD(): void {
|
||||||
|
|||||||
@@ -99,7 +99,8 @@ describe('MatchTracker.recordBumperHit — credit и point-counters', () => {
|
|||||||
describe('MatchTracker.recordBumperHit — стэк очков и событий', () => {
|
describe('MatchTracker.recordBumperHit — стэк очков и событий', () => {
|
||||||
it('многократные hits корректно накапливают BP per сторона', () => {
|
it('многократные hits корректно накапливают BP per сторона', () => {
|
||||||
const t = new MatchTracker(0);
|
const t = new MatchTracker(0);
|
||||||
// Player атакует — player получает 3 hits через ai_setup (по 3 pts slingshot)
|
// Player атакует (ballOwner=player) — мяч застревает в AI-setup,
|
||||||
|
// AI фармит как защитник (defensive trap). Player BP не растёт.
|
||||||
t.recordBumperHit(3, 'ai_setup', 'player', 'slingshot', 0, 0);
|
t.recordBumperHit(3, 'ai_setup', 'player', 'slingshot', 0, 0);
|
||||||
t.recordBumperHit(3, 'ai_setup', 'player', 'slingshot', 100, 0.1);
|
t.recordBumperHit(3, 'ai_setup', 'player', 'slingshot', 100, 0.1);
|
||||||
t.recordBumperHit(10, 'ai_setup', 'player', 'turbo', 200, 0.2);
|
t.recordBumperHit(10, 'ai_setup', 'player', 'turbo', 200, 0.2);
|
||||||
@@ -137,7 +138,7 @@ describe('MatchTracker.recordBumperHit — стэк очков и событий
|
|||||||
expect(events[0]?.data).toMatchObject({
|
expect(events[0]?.data).toMatchObject({
|
||||||
source: 'fixed_last_touch',
|
source: 'fixed_last_touch',
|
||||||
bumperType: 'standard',
|
bumperType: 'standard',
|
||||||
ballOwner: 'player',
|
ballOwnerBeforeHit: 'player',
|
||||||
creditedTo: 'player',
|
creditedTo: 'player',
|
||||||
pointsEarned: 5,
|
pointsEarned: 5,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -115,16 +115,18 @@ export class MatchTracker {
|
|||||||
this.uncreditedBumperHits += 1;
|
this.uncreditedBumperHits += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Event-log использует имена полей из telemetry-spec.md v3.10 bumper_hit event,
|
||||||
|
// чтобы при future batched-emit можно было пробрасывать .getEvents() напрямую.
|
||||||
this.events.push({
|
this.events.push({
|
||||||
type: 'bumper_hit',
|
type: 'bumper_hit',
|
||||||
timestamp: now,
|
timestamp: now,
|
||||||
data: {
|
data: {
|
||||||
source,
|
source,
|
||||||
bumperType,
|
bumperType,
|
||||||
ballOwner,
|
ballOwnerBeforeHit: ballOwner,
|
||||||
creditedTo,
|
creditedTo,
|
||||||
pointsEarned,
|
pointsEarned,
|
||||||
matchTimeSec,
|
matchTimeSeconds: matchTimeSec,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -139,6 +141,7 @@ export class MatchTracker {
|
|||||||
} else {
|
} else {
|
||||||
this.aiGoals += 1;
|
this.aiGoals += 1;
|
||||||
}
|
}
|
||||||
|
// Event-log поля совпадают с telemetry-spec.md goal_scored event.
|
||||||
this.events.push({
|
this.events.push({
|
||||||
type: 'goal',
|
type: 'goal',
|
||||||
timestamp: now,
|
timestamp: now,
|
||||||
@@ -146,7 +149,7 @@ export class MatchTracker {
|
|||||||
scorer: scoredBy,
|
scorer: scoredBy,
|
||||||
isAutogoal,
|
isAutogoal,
|
||||||
ballOwnershipBeforeGoal: this.ballOwner,
|
ballOwnershipBeforeGoal: this.ballOwner,
|
||||||
matchTimeSec,
|
matchTimeSeconds: matchTimeSec,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user