Add pause-aware goal reset timer with proper scene cleanup

- Add 3-second countdown timer after goal that resets the scene
- Timer pauses when game is paused, respecting pause state
- Freeze all game updates (puck, players, goals) during countdown
- Properly reset timer flags in create() to fix post-restart state
- Add safety checks in Player and Puck update to handle destroyed entities
- Remove player goal deceleration behavior (superseded by scene freeze)
- Add destroy() method to Player for proper resource cleanup
- Clean up goal event listeners before scene restart

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Pierre Wessman 2025-10-04 16:12:21 +02:00
parent ca6a444dec
commit 29885d1992
3 changed files with 45 additions and 22 deletions

View File

@ -6,7 +6,6 @@ import {
PLAYER_RADIUS_SKATER,
SPEED_SCALE_FACTOR,
MOVEMENT_STOP_THRESHOLD,
GOAL_DECELERATION_RATE,
DEBUG,
TACKLE_COOLDOWN,
TACKLE_FALL_DURATION,
@ -97,8 +96,7 @@ export class Player extends Phaser.GameObjects.Container {
// Home team (left side) faces right, Away team (right side) faces left
this.currentAngle = this.team === 'home' ? 0 : Math.PI;
// Listen for goal events
this.scene.events.on('goal', this.onGoal, this);
// Note: Goal events are handled by GameScene (freezes game and resets after 3s)
// Note: Player must be added to scene via scene.add.existing(player) and scene.physics.add.existing(player)
// This is handled by GameScene.addPlayer() method, which also sets up the physics body
@ -182,28 +180,13 @@ export class Player extends Phaser.GameObjects.Container {
this.targetY = targetY;
}
/**
* Handle goal event
*/
private onGoal(_data: { team: string; goal: string }) {
// Gradually decelerate player after goal
const decelerate = () => {
this.speedMultiplier *= GOAL_DECELERATION_RATE;
if (this.speedMultiplier > 0.01) {
this.scene.time.delayedCall(50, decelerate);
} else {
this.speedMultiplier = 0;
}
};
decelerate();
}
/**
* Update player movement each frame
*/
public update(delta: number) {
// Skip update if body doesn't exist (player being destroyed)
if (!this.body) return;
const deltaSeconds = delta / 1000;
// Check if player is fallen and should stay still
@ -466,4 +449,17 @@ export class Player extends Phaser.GameObjects.Container {
this.debugDetectionCircle.fillPath();
this.debugDetectionCircle.strokePath();
}
/**
* Clean up resources when player is destroyed
*/
destroy(fromScene?: boolean) {
// Destroy detection sensor
if (this.detectionSensor) {
this.detectionSensor.destroy();
}
// Call parent destroy
super.destroy(fromScene);
}
}

View File

@ -112,6 +112,9 @@ export class Puck extends Phaser.GameObjects.Container {
* Update puck game coordinates based on physics body position
*/
public update() {
// Skip update if body doesn't exist (puck being destroyed)
if (!this.body) return;
// Use body center position (body.x/y is top-left, need to account for that)
const bodyX = this.body.x + this.body.width / 2;
const bodyY = this.body.y + this.body.height / 2;

View File

@ -61,17 +61,28 @@ export class GameScene extends Phaser.Scene {
private isPaused: boolean = false;
private pauseButton!: Phaser.GameObjects.Text;
// Goal reset timer
private goalResetTimer: number = 0;
private isWaitingForReset: boolean = false;
constructor() {
super({ key: 'GameScene' });
}
create() {
console.log('[GameScene] Creating scene...');
// Reset goal timer flags
this.goalResetTimer = 0;
this.isWaitingForReset = false;
this.drawRink();
this.createGoals();
this.createPuck();
this.createPlayers();
this.setupEventListeners();
this.createPauseButton();
console.log('[GameScene] Scene created. Players:', this.players.length);
}
private createPlayers() {
@ -210,7 +221,9 @@ export class GameScene extends Phaser.Scene {
// Stop the puck (caught by net)
this.puck.body.setVelocity(0, 0);
// Future: update score, trigger celebration, reset to faceoff, etc.
// Start 3-second countdown to reset
this.goalResetTimer = 3000;
this.isWaitingForReset = true;
});
}
@ -327,6 +340,17 @@ export class GameScene extends Phaser.Scene {
update(_time: number, delta: number) {
if (this.isPaused) return;
// Handle goal reset timer
if (this.isWaitingForReset) {
this.goalResetTimer -= delta;
if (this.goalResetTimer <= 0) {
// Clean up before restart
this.events.off('goal');
this.scene.restart();
}
return; // Don't update anything while waiting for reset
}
this.updatePuck();
this.updatePlayers(delta);
this.checkGoals();