Add player enhancements and debug features
- Add away team defender (LD) for testing behaviors - Add direction indicator (white line) showing player facing direction - Initialize player facing angle based on team (home faces right, away faces left) - Implement speed-based turning physics (faster = wider turns, rotation drops to 30% at max speed) - Add debug visualizations for player targets (line and X marker) when DEBUG is true - Increase rotation speed constant from 1 to 3 rad/s for more responsive turning 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
a3ffc94916
commit
ff97b227c2
@ -25,12 +25,12 @@ export const COLOR_GOAL_CREASE = 0x87ceeb;
|
||||
|
||||
// Game settings
|
||||
export const FPS = 60;
|
||||
export const DEBUG = true;
|
||||
export const DEBUG = false;
|
||||
|
||||
// Player constants
|
||||
export const PLAYER_RADIUS_GOALIE = 12; // pixels
|
||||
export const PLAYER_RADIUS_SKATER = 10; // pixels
|
||||
export const PLAYER_ROTATION_SPEED = 1; // radians per second
|
||||
export const PLAYER_ROTATION_SPEED = 3; // radians per second
|
||||
export const SPEED_SCALE_FACTOR = 10; // speed attribute (0-100) / 10 = m/s
|
||||
export const GOAL_DECELERATION_RATE = 0.9; // Speed multiplier reduction after goal
|
||||
|
||||
|
||||
@ -6,7 +6,8 @@ import {
|
||||
PLAYER_RADIUS_SKATER,
|
||||
SPEED_SCALE_FACTOR,
|
||||
MOVEMENT_STOP_THRESHOLD,
|
||||
GOAL_DECELERATION_RATE
|
||||
GOAL_DECELERATION_RATE,
|
||||
DEBUG
|
||||
} from '../config/constants';
|
||||
import { CoordinateUtils } from '../utils/coordinates';
|
||||
import { MathUtils } from '../utils/math';
|
||||
@ -38,6 +39,13 @@ export class Player extends Phaser.GameObjects.Container {
|
||||
// Rotation (angle in radians, 0 = facing right)
|
||||
private currentAngle: number = 0;
|
||||
|
||||
// Debug visualizations
|
||||
private debugTargetGraphics?: Phaser.GameObjects.Graphics;
|
||||
private debugLineGraphics?: Phaser.GameObjects.Graphics;
|
||||
|
||||
// Direction indicator
|
||||
private directionIndicator!: Phaser.GameObjects.Graphics;
|
||||
|
||||
constructor(
|
||||
scene: Phaser.Scene,
|
||||
id: string,
|
||||
@ -62,6 +70,10 @@ export class Player extends Phaser.GameObjects.Container {
|
||||
this.attributes = attributes;
|
||||
this.state = 'defensive';
|
||||
|
||||
// Initialize facing direction based on team
|
||||
// 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);
|
||||
|
||||
@ -78,6 +90,12 @@ export class Player extends Phaser.GameObjects.Container {
|
||||
this.body.setCollideWorldBounds(true);
|
||||
|
||||
this.createSprite();
|
||||
|
||||
// Create debug graphics if DEBUG is enabled
|
||||
if (DEBUG) {
|
||||
this.debugTargetGraphics = scene.add.graphics();
|
||||
this.debugLineGraphics = scene.add.graphics();
|
||||
}
|
||||
}
|
||||
|
||||
private createSprite() {
|
||||
@ -105,7 +123,28 @@ export class Player extends Phaser.GameObjects.Container {
|
||||
});
|
||||
label.setOrigin(0.5, 0.5);
|
||||
|
||||
this.add([graphics, label]);
|
||||
// Create direction indicator (small line showing facing direction)
|
||||
this.directionIndicator = this.scene.add.graphics();
|
||||
this.updateDirectionIndicator();
|
||||
|
||||
this.add([graphics, label, this.directionIndicator]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the direction indicator to show current facing angle
|
||||
*/
|
||||
private updateDirectionIndicator() {
|
||||
this.directionIndicator.clear();
|
||||
|
||||
const radius = this.playerPosition === 'G' ? PLAYER_RADIUS_GOALIE : PLAYER_RADIUS_SKATER;
|
||||
|
||||
// Draw line pointing right (container rotation will orient it correctly)
|
||||
// Line goes from behind center to near the edge (0=center, 1=edge)
|
||||
const startX = -radius * -0.5; // Start
|
||||
const endX = radius * 1.0; // End
|
||||
|
||||
this.directionIndicator.lineStyle(3, 0x999999, 1);
|
||||
this.directionIndicator.lineBetween(startX, 0, endX, 0); // Horizontal line, rotation handled by container
|
||||
}
|
||||
|
||||
/**
|
||||
@ -166,8 +205,13 @@ export class Player extends Phaser.GameObjects.Container {
|
||||
const targetAngle = Math.atan2(dy, dx);
|
||||
|
||||
// Smoothly rotate toward target angle
|
||||
// Scale rotation speed inversely with current velocity (faster = wider turns)
|
||||
const deltaSeconds = delta / 1000;
|
||||
const maxRotation = PLAYER_ROTATION_SPEED * deltaSeconds;
|
||||
const currentSpeed = Math.sqrt(this.body.velocity.x ** 2 + this.body.velocity.y ** 2);
|
||||
const maxSpeed = (this.attributes.speed / SPEED_SCALE_FACTOR) * SCALE;
|
||||
const speedRatio = maxSpeed > 0 ? currentSpeed / maxSpeed : 0;
|
||||
const turnPenalty = 1 - (speedRatio * 0.7); // At max speed, rotation is 30% of base
|
||||
const maxRotation = PLAYER_ROTATION_SPEED * turnPenalty * deltaSeconds;
|
||||
|
||||
// Calculate shortest angular difference
|
||||
const angleDiff = MathUtils.angleDifference(this.currentAngle, targetAngle);
|
||||
@ -199,5 +243,44 @@ export class Player extends Phaser.GameObjects.Container {
|
||||
const gamePos = CoordinateUtils.screenToGame(this.scene, bodyX, bodyY);
|
||||
this.gameX = gamePos.x;
|
||||
this.gameY = gamePos.y;
|
||||
|
||||
// Update debug visualizations
|
||||
this.updateDebugVisuals();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update debug visualizations (target position and path line)
|
||||
*/
|
||||
private updateDebugVisuals() {
|
||||
if (!DEBUG || !this.debugTargetGraphics || !this.debugLineGraphics) return;
|
||||
|
||||
// Convert target position to screen coordinates
|
||||
const targetScreen = CoordinateUtils.gameToScreen(this.scene, this.targetX, this.targetY);
|
||||
const playerScreen = CoordinateUtils.gameToScreen(this.scene, this.gameX, this.gameY);
|
||||
|
||||
// Clear previous debug graphics
|
||||
this.debugTargetGraphics.clear();
|
||||
this.debugLineGraphics.clear();
|
||||
|
||||
// Draw line from player to target
|
||||
const lineColor = this.team === 'home' ? 0x0000ff : 0xff0000;
|
||||
this.debugLineGraphics.lineStyle(1, lineColor, 0.5);
|
||||
this.debugLineGraphics.lineBetween(playerScreen.x, playerScreen.y, targetScreen.x, targetScreen.y);
|
||||
|
||||
// Draw target marker (X)
|
||||
const markerSize = 5;
|
||||
this.debugTargetGraphics.lineStyle(2, lineColor, 0.8);
|
||||
this.debugTargetGraphics.lineBetween(
|
||||
targetScreen.x - markerSize,
|
||||
targetScreen.y - markerSize,
|
||||
targetScreen.x + markerSize,
|
||||
targetScreen.y + markerSize
|
||||
);
|
||||
this.debugTargetGraphics.lineBetween(
|
||||
targetScreen.x + markerSize,
|
||||
targetScreen.y - markerSize,
|
||||
targetScreen.x - markerSize,
|
||||
targetScreen.y + markerSize
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,11 +49,22 @@ export class GameScene extends Phaser.Scene {
|
||||
'home',
|
||||
'C',
|
||||
-10,
|
||||
-10,
|
||||
-5,
|
||||
{ speed: 80, skill: 75 }
|
||||
);
|
||||
|
||||
this.players.push(homeCenter);
|
||||
// Create one away defender at (15, 0) - right side for defending
|
||||
const awayDefender = new Player(
|
||||
this,
|
||||
'away-LD',
|
||||
'away',
|
||||
'LD',
|
||||
15,
|
||||
0,
|
||||
{ speed: 75, skill: 70 }
|
||||
);
|
||||
|
||||
this.players.push(homeCenter, awayDefender);
|
||||
}
|
||||
|
||||
private setupEventListeners() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user