Refactor player and goal collision handling using Phaser physics groups
- Add playerGroup for dynamic collision management between all players - Add goalPostsGroup for centralized goal post collision handling - Add addPlayer() and removePlayer() methods for runtime player management - Reduce collision setup from 15+ lines to 2 group-based colliders - Adjust threat detection radius from 8m to 4m for more realistic evasion 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
f26d8a3189
commit
71082f713a
@ -70,7 +70,7 @@ export const CLOSE_RANGE_SHOT_SPEED_MULTIPLIER = 0.6; // Close-range shots have
|
||||
export const GOALIE_RANGE = 3; // meters - how far goalie moves from center
|
||||
|
||||
// Collision avoidance constants
|
||||
export const THREAT_DETECTION_RADIUS = 8; // meters - radius to detect approaching opponents
|
||||
export const THREAT_DETECTION_RADIUS = 4; // meters - radius to detect approaching opponents
|
||||
export const EVASION_ANGLE = Math.PI / 3; // radians (60 degrees) - angle to turn when evading
|
||||
|
||||
// Tackle constants
|
||||
|
||||
@ -48,6 +48,8 @@ export class GameScene extends Phaser.Scene {
|
||||
private rightGoal!: Goal;
|
||||
private puck!: Puck;
|
||||
private players: Player[] = [];
|
||||
private playerGroup!: Phaser.Physics.Arcade.Group;
|
||||
private goalPostsGroup!: Phaser.Physics.Arcade.StaticGroup;
|
||||
private behaviorTrees: Map<string, BehaviorTree> = new Map();
|
||||
|
||||
// Track last reception attempt time for each player to avoid spamming attempts
|
||||
@ -71,6 +73,11 @@ export class GameScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
private createPlayers() {
|
||||
// Create physics group for all players
|
||||
this.playerGroup = this.physics.add.group({
|
||||
collideWorldBounds: false
|
||||
});
|
||||
|
||||
// Create one home center at (-10, 0) - left side of center ice
|
||||
const homeCenter = new Player(
|
||||
this,
|
||||
@ -93,19 +100,43 @@ export class GameScene extends Phaser.Scene {
|
||||
{ speed: 80, skill: 70, tackling: 85, balance: 80, handling: 65 }
|
||||
);
|
||||
|
||||
this.players.push(homeCenter, awayDefender);
|
||||
// Add players to tracking array and physics group
|
||||
this.addPlayer(homeCenter);
|
||||
this.addPlayer(awayDefender);
|
||||
|
||||
// Create behavior trees for each player (reused every frame)
|
||||
this.players.forEach(player => {
|
||||
this.behaviorTrees.set(player.id, new BehaviorTree(player));
|
||||
});
|
||||
|
||||
// Setup player-player collisions
|
||||
this.physics.add.collider(homeCenter, awayDefender, (obj1, obj2) => {
|
||||
// Setup player-player collisions for entire group
|
||||
this.physics.add.collider(this.playerGroup, this.playerGroup, (obj1, obj2) => {
|
||||
this.handlePlayerCollision(obj1 as Player, obj2 as Player);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a player to the scene (can be called at any time for debugging)
|
||||
*/
|
||||
addPlayer(player: Player) {
|
||||
this.players.push(player);
|
||||
this.playerGroup.add(player);
|
||||
this.behaviorTrees.set(player.id, new BehaviorTree(player));
|
||||
|
||||
// Add collision with all goal posts
|
||||
this.physics.add.collider(player, this.goalPostsGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a player from the scene (can be called at any time for debugging)
|
||||
*/
|
||||
removePlayer(playerId: string) {
|
||||
const index = this.players.findIndex(p => p.id === playerId);
|
||||
if (index === -1) return;
|
||||
|
||||
const player = this.players[index];
|
||||
this.players.splice(index, 1);
|
||||
this.playerGroup.remove(player);
|
||||
this.behaviorTrees.delete(playerId);
|
||||
this.lastReceptionAttempt.delete(playerId);
|
||||
player.destroy();
|
||||
}
|
||||
|
||||
private setupEventListeners() {
|
||||
// Listen for goal events
|
||||
this.events.on('goal', (data: { team: string; goal: string }) => {
|
||||
@ -122,29 +153,17 @@ export class GameScene extends Phaser.Scene {
|
||||
// Initialize puck at center ice (0, 0 in game coordinates)
|
||||
this.puck = new Puck(this, 27, 5);
|
||||
|
||||
// Add collisions between puck and goal posts with custom bounce handler
|
||||
this.physics.add.collider(this.puck, this.leftGoal.getLeftPost(), this.handlePuckPostBounce, undefined, this);
|
||||
this.physics.add.collider(this.puck, this.leftGoal.getRightPost(), this.handlePuckPostBounce, undefined, this);
|
||||
this.physics.add.collider(this.puck, this.leftGoal.getBackBar(), this.handlePuckPostBounce, undefined, this);
|
||||
this.physics.add.collider(this.puck, this.rightGoal.getLeftPost(), this.handlePuckPostBounce, undefined, this);
|
||||
this.physics.add.collider(this.puck, this.rightGoal.getRightPost(), this.handlePuckPostBounce, undefined, this);
|
||||
this.physics.add.collider(this.puck, this.rightGoal.getBackBar(), this.handlePuckPostBounce, undefined, this);
|
||||
|
||||
// Add player collisions with goal posts (prevent skating through goals)
|
||||
this.players.forEach(player => {
|
||||
this.physics.add.collider(player, this.leftGoal.getLeftPost());
|
||||
this.physics.add.collider(player, this.leftGoal.getRightPost());
|
||||
this.physics.add.collider(player, this.leftGoal.getBackBar());
|
||||
this.physics.add.collider(player, this.rightGoal.getLeftPost());
|
||||
this.physics.add.collider(player, this.rightGoal.getRightPost());
|
||||
this.physics.add.collider(player, this.rightGoal.getBackBar());
|
||||
});
|
||||
// Add collisions between puck and all goal posts with custom bounce handler
|
||||
this.physics.add.collider(this.puck, this.goalPostsGroup, this.handlePuckPostBounce, undefined, this);
|
||||
}
|
||||
|
||||
private createGoals() {
|
||||
const centerX = (RINK_LENGTH * SCALE) / 2;
|
||||
const centerY = (RINK_WIDTH * SCALE) / 2;
|
||||
|
||||
// Create static physics group for all goal posts
|
||||
this.goalPostsGroup = this.physics.add.staticGroup();
|
||||
|
||||
// Left goal (positioned at left goal line)
|
||||
const leftGoalX = centerX - (GOAL_LINE_OFFSET * SCALE);
|
||||
this.leftGoal = new Goal(this, leftGoalX, centerY, true);
|
||||
@ -152,6 +171,14 @@ export class GameScene extends Phaser.Scene {
|
||||
// Right goal (positioned at right goal line)
|
||||
const rightGoalX = centerX + (GOAL_LINE_OFFSET * SCALE);
|
||||
this.rightGoal = new Goal(this, rightGoalX, centerY, false);
|
||||
|
||||
// Add all goal posts to the group
|
||||
this.goalPostsGroup.add(this.leftGoal.getLeftPost());
|
||||
this.goalPostsGroup.add(this.leftGoal.getRightPost());
|
||||
this.goalPostsGroup.add(this.leftGoal.getBackBar());
|
||||
this.goalPostsGroup.add(this.rightGoal.getLeftPost());
|
||||
this.goalPostsGroup.add(this.rightGoal.getRightPost());
|
||||
this.goalPostsGroup.add(this.rightGoal.getBackBar());
|
||||
}
|
||||
|
||||
private drawRink() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user