Phase 0-2: Vite/Phaser 4/TS boilerplate + Platform Adapter + core match (vs 4 AI personalities)
Phase 0 (foundation): - package.json, tsconfig.json (strict), vite.config.ts (base: './'), .eslintrc.cjs - index.html, src/main.ts (Phaser game init + platform detection) - src/config/defaults.ts (Remote Config defaults, palette, constants) - src/types/index.ts (все schemas из data-contracts: SaveState, MatchResult, RemoteConfig, etc.) - src/platform/: PlatformAdapter interface + MockPlatformAdapter + YgPlatformAdapter Phase 1 (core mechanics): - src/scenes/: Boot, Preload, MainMenu (Quick Match selector), Setup, Match, Result - src/game/: Table (геометрия + walls + ворота), Ball (last-touch + color tracking), Flipper (player + AI, swing + cooldown), Bumper (4 типа: standard/slingshot/curve/turbo) - src/scoring/: MatchTracker (last-touch + bumper points), calculateScores (unified scoring pipeline per data-contracts v3.8 requirement) - src/ai/: AIPlayer interface + DefensiveAI Easy/Medium Phase 2 (setup + AI personalities): - src/scenes/SetupScene (5 active slots, click-cycle bumper types, 30s timer) - src/ai/personalities/: AggressiveAI, TricksterAI, GhostAI (Easy/Medium; Hard cradle-aim = Phase 3) - src/ai/factory.ts (createAIPlayer) - MainMenuScene: выбор AI-личности + сложности - MatchScene использует factory вместо хардкода Anti-A2W enforcement: calculateScores применяет penalty per v3.5 model (Continue × 0.5, Campaign Skip × 0.7, +1 заряд × 0.9, реролл × 0.85, Boost active × 0.7; ×2 sezon очки только в local). Что НЕ в этом commit'е (следующие фазы): - Phase 3: бустер «Захват» (cradle + slow-mo), Hard AI (cradle-aim solver), Ghost adaptation, YG Player API cloud-save, achievements - Phase 4: Campaign (12 матчей), Tournament (8/16 bracket), шейдеры (CRT + bloom + chromatic aberration), 29 AI-арт ассетов, музыка - Phase 5: реальная YG SDK интеграция (ads + payments), Remote Config Nakama RPC - Phase 6: YG submission Pre-greenlit concept-пакет — ~/Knowledge/Projects/pinball-duel/ (19 файлов, 10 audit-раундов). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
73
src/ai/personalities/DefensiveAI.ts
Normal file
73
src/ai/personalities/DefensiveAI.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import type {
|
||||
AIPlayer,
|
||||
AIPlayerContext,
|
||||
} from '../AIPlayer';
|
||||
import { shouldActivateFlipperBase } from '../AIPlayer';
|
||||
import type {
|
||||
AIDifficulty,
|
||||
AIDifficultyParams,
|
||||
AIPersonality,
|
||||
SetupConfig,
|
||||
} from '../../types';
|
||||
|
||||
// DefensiveAI — «Бэтти-Защитница».
|
||||
// Стратегия: цепкая защита, бустер только на cradle (не реализовано в Phase 1-2).
|
||||
// Setup: 2 slingshot в углах ворот, 1 турбо рядом, 1 вираж в дальнем углу, 1 пустой.
|
||||
// см. ~/Knowledge/Projects/pinball-duel/concepts/bot-ai-design.md#1-defensive-«бэтти-защитница»
|
||||
|
||||
export class DefensiveAI implements AIPlayer {
|
||||
readonly personality: AIPersonality = 'defensive';
|
||||
readonly difficulty: AIDifficulty;
|
||||
readonly params: AIDifficultyParams;
|
||||
|
||||
private lastReactionTimeLeft = 0;
|
||||
private lastReactionTimeRight = 0;
|
||||
|
||||
constructor(difficulty: AIDifficulty, params: AIDifficultyParams) {
|
||||
this.difficulty = difficulty;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
update(ctx: AIPlayerContext): void {
|
||||
// Defensive — реагирует надёжно на любой приближающийся мяч
|
||||
const shouldLeft = shouldActivateFlipperBase(
|
||||
ctx,
|
||||
'left',
|
||||
this.params,
|
||||
this.lastReactionTimeLeft,
|
||||
);
|
||||
if (shouldLeft) {
|
||||
if (ctx.leftFlipper.activate()) {
|
||||
this.lastReactionTimeLeft = performance.now();
|
||||
}
|
||||
}
|
||||
const shouldRight = shouldActivateFlipperBase(
|
||||
ctx,
|
||||
'right',
|
||||
this.params,
|
||||
this.lastReactionTimeRight,
|
||||
);
|
||||
if (shouldRight) {
|
||||
if (ctx.rightFlipper.activate()) {
|
||||
this.lastReactionTimeRight = performance.now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generateSetup(): SetupConfig {
|
||||
// см. bot-ai-design.md#defensive-setup-эвристика
|
||||
return {
|
||||
slots: [
|
||||
{ slotId: 'goal_corner_left', bumperType: 'slingshot' },
|
||||
{ slotId: 'goal_corner_right', bumperType: 'slingshot' },
|
||||
{ slotId: 'near_goal_center', bumperType: 'turbo' },
|
||||
{ slotId: 'mid_left', bumperType: 'curve' },
|
||||
{ slotId: 'mid_right', bumperType: null }, // 1 пустой слот
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
// No state to clean
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user