hockey-manager-2/src/systems/BehaviorTree.ts
Pierre Wessman a3ffc94916 Restructure behavior tree for scalability
- Separate base behavior nodes into BehaviorNodes.ts (fixes circular dependency)
- Organize behaviors by role (goalie) and context (offensive/defensive/transition)
- Add modular behavior subtrees:
  - GoalieBehavior: Track puck position near net
  - SkaterBehavior: Route to context-specific behaviors
  - PuckCarrierBehavior: Shoot/carry logic (Phase 4)
  - OffensiveSupportBehavior: Placeholder for Phase 5
  - DefensiveBehavior: Placeholder for Phase 6
  - TransitionBehavior: Chase loose puck
- Maintain backward compatibility with static evaluatePlayer()

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-02 09:42:20 +02:00

61 lines
2.2 KiB
TypeScript

import type { Player } from '../entities/Player';
import type { GameState, PlayerAction } from '../types/game';
import { BehaviorNode, Selector, Sequence, Condition } from './BehaviorNodes';
import { GoalieBehavior } from './behaviors/GoalieBehavior';
import { SkaterBehavior } from './behaviors/SkaterBehavior';
// Re-export base classes for convenience
export { BehaviorNode, BehaviorStatus, Selector, Sequence, Condition, Action } from './BehaviorNodes';
/**
* BehaviorTree system for AI decision-making
*
* This system uses a behavior tree pattern to make tactical decisions for players.
* The tree is evaluated every tick (60 FPS) and produces actions based on:
* - Game state (possession, positions, threats)
* - Player attributes (Hockey IQ, Skill, Speed)
* - Tactical context (offensive/defensive situation)
*
* The tree is structured by role (goalie vs skater) at the top level,
* then by game context (offensive/defensive/transition) for skaters.
*
* @example
* const tree = new BehaviorTree(player);
* const action = tree.tick(gameState); // Called every frame in GameScene.update()
*/
export class BehaviorTree {
private root: BehaviorNode;
constructor(private player: Player) {
// Root selector: Choose between goalie and skater behaviors based on position
this.root = new Selector([
// Goalie behavior (checks position internally)
new Sequence([
new Condition((p) => p.playerPosition === 'G'),
new GoalieBehavior()
]),
// Skater behavior (default for all other positions)
new SkaterBehavior()
]);
}
/**
* Evaluates the behavior tree and returns the next action for the player
* Called every frame (60 FPS)
*/
public tick(gameState: GameState): PlayerAction {
const result = this.root.tick(this.player, gameState);
// Result should always be a PlayerAction from our structure
return result as PlayerAction;
}
/**
* Static helper to evaluate any player
* This maintains backward compatibility with existing code
*/
public static evaluatePlayer(player: Player, gameState: GameState): PlayerAction {
const tree = new BehaviorTree(player);
return tree.tick(gameState);
}
}