/** * sniper_shot.aigameplay — reducer 接口模板 * * Agent 生成实际 reducer 时,必须导出以下函数。 * 此文件是接口约束模板,不是可执行代码。 * * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ * ⚠️ 重要:渲染层(GameScene)不应直接调用 dispatch() * * dispatch() 是一体化接口,内部跑完整个射击判定后只返回最终状态, * 中间过程(瞄准位置、呼吸偏移、命中特效触发点)全部丢失。 * * 渲染层需要分步动画(抖动更新 → 移动精灵 → 枪声+特效 → HUD 刷新), * 因此必须使用下方的「分步函数」逐步驱动,每步之间播放对应动画。 * * dispatch() 的用途:无头测试、AI 模拟、快速跳过动画等场景。 * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */ // ─── 配置类型 ───────────────────────────────────────────────────────────────── export type SniperConfig = { /** 场景宽度(px) */ sceneWidth: number; /** 场景高度(px) */ sceneHeight: number; /** 初始子弹数 */ initialAmmo: number; /** 瞄准镜默认放大倍数 */ defaultZoom: number; /** 呼吸周期(ms) */ breathCycleMs: number; /** 呼吸抖动基础振幅(px,zoom=1 时) */ breathAmplitude: number; /** 风力是否启用 */ windEnabled: boolean; /** 最大误伤次数(超过则游戏失败) */ maxFriendlyFireHits: number; /** 命中敌人基础得分 */ baseScorePerKill: number; }; // ─── 动作类型 ───────────────────────────────────────────────────────────────── export type SniperAction = | { type: 'aim'; dx: number; dy: number } | { type: 'shoot' } | { type: 'tick'; deltaMs: number } | { type: 'reset' }; // ─── 状态类型 ───────────────────────────────────────────────────────────────── export type Vec2 = { x: number; y: number }; export type TargetType = 'enemy' | 'civilian'; export type TargetState = 'alive' | 'dead'; export type MovementPattern = 'static' | 'linear' | 'patrol' | 'random'; export type Target = { id: string; targetType: TargetType; position: Vec2; radius: number; movementPattern: MovementPattern; movementSpeed: number; patrolPoints: Vec2[]; patrolIndex: number; randomMoveTimer: number; moveDirection: Vec2; state: TargetState; }; export type Wind = { direction: number; strength: number; }; export type Scope = { position: Vec2; driftOffset: Vec2; zoom: number; }; export type SniperState = { scope: Scope; targets: Target[]; wind: Wind; ammoCount: number; score: number; friendlyFireCount: number; breathTimer: number; gameOver: boolean; win: boolean; lastShotResult: ShootResult | null; }; // ─── 分步操作返回类型 ───────────────────────────────────────────────────────── export type HitResult = { hit: boolean; targetId: string | null; targetType: TargetType | null; }; export type ShootResult = { hit: boolean; targetId: string | null; isCivilian: boolean; scoreGained: number; scoreLost: number; effectiveScopePos: Vec2; }; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // 必须导出的函数 // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // ─── 初始化 ────────────────────────────────────────────────────────────────── /** * init:根据配置初始化游戏状态 */ export declare function init(config: SniperConfig, targets: Target[], wind?: Wind): SniperState; // ─── 一体化接口(测试/AI 模拟用) ─────────────────────────────────────────── /** * dispatch:接收动作,返回新状态(纯函数,不得修改原 state) * - aim:移动瞄准镜位置 * - shoot:发射子弹,包含命中检测、计分、胜负判定(一步到位) * - tick:更新物理(呼吸抖动、目标移动) * - reset:重置到初始状态 * * ⚠️ 仅用于无头测试和 AI 模拟。渲染层请使用下方分步函数。 */ export declare function dispatch(state: SniperState, action: SniperAction): SniperState; /** * getState:返回当前状态快照 */ export declare function getState(state: SniperState): SniperState; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // 分步函数(渲染层/场景层必须使用这些函数驱动动画) // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ /** * aimScope:玩家拖动屏幕,移动瞄准镜中心位置 * 返回更新后的 scope position(已钳制在场景边界内) * * 场景层根据返回值移动瞄准镜 overlay Sprite/Container 的位置。 */ export declare function aimScope( state: SniperState, dx: number, dy: number, ): { scopePos: Vec2 }; /** * applyBreathDrift:更新呼吸抖动偏移 * 基于正弦函数,每帧调用,deltaMs 为帧时长 * * 场景层将 driftOffset 叠加到瞄准镜显示位置(但不修改 scope.position)。 * driftOffset 随 zoom 增大而减小(放大镜稳定瞄准)。 */ export declare function applyBreathDrift( state: SniperState, deltaMs: number, ): { driftOffset: Vec2 }; /** * shoot:执行射击 * 内部调用 hitDetection,根据结果更新 ammoCount / score / target.state / friendlyFireCount * * 场景层根据返回值: * - 播放枪声音效 * - 若 hit=true 且非平民:播放命中特效 * - 若 hit=true 且平民:播放误伤警告 * - 更新 HUD(弹药数、得分) */ export declare function shoot(state: SniperState): ShootResult; /** * hitDetection:判断有效瞄准位置是否命中任何目标 * 有效瞄准位置 = scope.position + scope.driftOffset + wind_trajectory_offset */ export declare function hitDetection( state: SniperState, scopePos: Vec2, ): HitResult; /** * updateTargets:按运动模式更新所有目标位置 * 每帧调用,deltaMs 为帧时长 * * 场景层根据返回的 targets 数组更新每个目标精灵的位置。 */ export declare function updateTargets( state: SniperState, deltaMs: number, ): Target[]; /** * calculateScore:计算命中该类型目标所得的分数 * - enemy:baseScorePerKill(可加距离/难度系数) * - civilian:负分(-200) */ export declare function calculateScore( hit: boolean, target: Target, ): number;