2025-10-02 08:29:43 +02:00

119 lines
3.2 KiB
TypeScript

import Phaser from 'phaser';
import { SCALE, MAX_PUCK_VELOCITY } from '../config/constants';
import { CoordinateUtils } from '../utils/coordinates';
import type { PuckState, TeamSide, Position } from '../types/game';
export class Puck extends Phaser.GameObjects.Container {
declare body: Phaser.Physics.Arcade.Body;
// Position in game coordinates (meters)
public gameX: number;
public gameY: number;
// Puck state
public state: PuckState;
public possession: TeamSide | null;
public carrier: string | null; // PlayerID
constructor(scene: Phaser.Scene, gameX: number = 0, gameY: number = 0) {
// Convert game coordinates to screen coordinates
const screenPos = CoordinateUtils.gameToScreen(scene, gameX, gameY);
super(scene, screenPos.x, screenPos.y);
this.gameX = gameX;
this.gameY = gameY;
this.state = 'loose';
this.possession = null;
this.carrier = null;
// Add to scene
scene.add.existing(this);
scene.physics.add.existing(this);
this.body = this.body as Phaser.Physics.Arcade.Body;
// Set physics body size to match the puck visual (10px diameter)
this.body.setSize(10, 10);
this.body.setOffset(-5, -5); // Center the body on the container
// Set max velocity (allow up to x m/s)
this.body.setMaxVelocity(MAX_PUCK_VELOCITY * SCALE, MAX_PUCK_VELOCITY * SCALE);
// Set initial velocity to 0 (stationary)
this.body.setVelocity(0, 0);
// Add bounce to keep it moving
this.body.setBounce(1, 1);
this.body.setCollideWorldBounds(true);
// Enable high-velocity collision detection
this.body.setCircle(5); // Use circular body instead of rectangle for better collision
this.createSprite();
}
private createSprite() {
const graphics = this.scene.add.graphics();
// Draw puck as black circle (5px radius)
graphics.fillStyle(0x000000, 1);
graphics.fillCircle(0, 0, 5);
// Add white highlight for visibility on ice
graphics.fillStyle(0xffffff, 0.3);
graphics.fillCircle(-1, -1, 2);
this.add(graphics);
}
/**
* Update puck position in game coordinates (meters)
*/
public setGamePosition(gameX: number, gameY: number) {
this.gameX = gameX;
this.gameY = gameY;
// Convert to screen coordinates
const screenPos = CoordinateUtils.gameToScreen(this.scene, gameX, gameY);
this.setPosition(screenPos.x, screenPos.y);
}
/**
* Set puck to be carried by a player
*/
public setCarrier(playerId: string, team: TeamSide) {
this.carrier = playerId;
this.possession = team;
this.state = 'carried';
}
/**
* Set puck to loose state
*/
public setLoose() {
this.carrier = null;
this.state = 'loose';
}
/**
* Get puck position in game coordinates
*/
public getGamePosition(): Position {
return { x: this.gameX, y: this.gameY };
}
/**
* Update puck game coordinates based on physics body position
*/
public update() {
// 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;
const gamePos = CoordinateUtils.screenToGame(this.scene, bodyX, bodyY);
this.gameX = gamePos.x;
this.gameY = gamePos.y;
}
}