/** * basketball_shot.aigameplay — reducer 接口模板 * * Agent 生成实际 reducer 时,必须导出以下函数。 * 此文件是接口约束模板,不是可执行代码。 * * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ * ⚠️ 重要:渲染层(GameScene)不应直接调用 dispatch() * * dispatch() 一步完成整个投篮模拟,丢失中间轨迹数据。 * 渲染层需要播放球的飞行动画,必须使用 calculateTrajectory * 获取轨迹点列表,逐帧插值渲染球的位置。 * * dispatch() 的用途:无头测试、AI 模拟、批量计算等场景。 * ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */ // ─── 配置类型 ───────────────────────────────────────────────────────────────── export type BasketballConfig = { /** 重力加速度(像素/秒²),默认 980 */ gravity: number; /** 最大初始速度(像素/秒) */ maxSpeed: number; /** 连击倍率步进,默认 0.5(每次连击增加 0.5x) */ comboMultiplierStep: number; /** 入筐容差系数,默认 0.15(增大让入筐更宽松) */ rimTolerance: number; /** 每关投篮次数 */ initialShots: number; /** 目标分数 */ goalScore: number; /** 每次投中基础分 */ baseScore: number; /** 模拟步长(秒),默认 1/120 */ simulationStep: number; }; // ─── 核心类型 ───────────────────────────────────────────────────────────────── export type Vector2 = { x: number; y: number }; export type Hoop = { position: Vector2; // 篮筐中心 radius: number; // 篮筐内径半径 rimY: number; // 篮筐顶部 y(球必须从上方穿过) }; export type PlayerPosition = { position: Vector2; // 玩家(球的起始位置) label?: string; // 例如 "3-point line", "mid-range" }; // ─── 动作类型 ───────────────────────────────────────────────────────────────── export type BasketballAction = | { type: 'aim'; angle: number; power: number } // 设置投篮参数 | { type: 'shoot'; angle: number; power: number } // 投篮(一步完成) | { type: 'reset' }; // ─── 状态类型 ───────────────────────────────────────────────────────────────── export type BasketballState = { hoop: Hoop; playerPosition: PlayerPosition; score: number; shotsRemaining: number; comboCount: number; /** 当前连击倍率 = 1 + comboCount × comboMultiplierStep */ comboMultiplier: number; gameOver: boolean; win: boolean; /** 上一次投篮是否命中 */ lastShotScored: boolean; /** 上一次投篮轨迹(用于渲染层 replay 或回放) */ lastTrajectory: TrajectoryPoint[] | null; }; // ─── 分步操作返回类型 ───────────────────────────────────────────────────────── /** 轨迹点(位置 + 时间戳) */ export type TrajectoryPoint = { position: Vector2; t: number; // 飞行时间(秒) }; /** 投篮模拟结果 */ export type ShotResult = { trajectoryPoints: TrajectoryPoint[]; // 完整轨迹点列表 scored: boolean; // 是否入筐 finalPosition: Vector2; // 落点 hoopContactPoint?: Vector2; // 入筐接触点(若 scored) }; /** 入筐检测结果 */ export type HoopCheckResult = { scored: boolean; /** 球心穿过 rimY 时的 x 偏移量(0 = 完美中心) */ centerOffset: number; }; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // 必须导出的函数 // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // ─── 初始化 ────────────────────────────────────────────────────────────────── /** * init:根据配置初始化游戏状态 */ export declare function init(config: BasketballConfig & { hoop: Hoop; playerPosition: PlayerPosition }): BasketballState; // ─── 一体化接口(测试/AI 模拟用) ─────────────────────────────────────────── /** * dispatch:接收动作,返回新状态(纯函数) * - aim:更新当前瞄准参数(不消耗次数) * - shoot:执行完整投篮模拟,更新状态 * - reset:重置游戏 * * ⚠️ 仅用于无头测试和 AI 模拟。渲染层请使用下方分步函数。 */ export declare function dispatch(state: BasketballState, action: BasketballAction): BasketballState; /** * getState:返回当前状态快照 */ export declare function getState(state: BasketballState): BasketballState; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // 分步函数(渲染层/场景层必须使用这些函数驱动动画) // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ /** * calculateTrajectory:根据起始位置、角度、力度计算完整抛物线轨迹 * 公式:x(t)=x0+vx·t, y(t)=y0+vy·t+0.5·g·t²(g 为正值,y 轴向下为正) * * 渲染层用途: * 1. 玩家调整参数时实时预览轨迹(虚线) * 2. 实际投篮时获取逐帧插值点 */ export declare function calculateTrajectory( startPos: Vector2, angle: number, // 投篮仰角(度),相对水平方向 power: number, // 力度百分比 0~100 config: Pick, ): TrajectoryPoint[]; /** * checkHoop:检测球在某一时刻是否穿过篮筐 * 条件:球从 rimY 上方穿越到下方,且球心 x 在 hoop.radius × (1 + rimTolerance) 内 * * 渲染层在逐帧播放轨迹动画时调用,检测入筐瞬间以触发入筐动画 */ export declare function checkHoop( ball: Vector2, prevBall: Vector2, // 上一帧位置(用于判断穿越方向) hoop: Hoop, rimTolerance: number, ): HoopCheckResult; /** * updateScore:根据本次投篮结果更新分数和连击数 * - 命中:score += baseScore × comboMultiplier;comboCount++ * - 未中:comboCount = 0;comboMultiplier = 1 * - shotsRemaining-- * - 检测 gameOver 和 win */ export declare function updateScore( state: BasketballState, isHit: boolean, config: Pick, ): BasketballState; /** * simulateShot:执行完整投篮模拟,返回轨迹点和结果 * 内部调用 calculateTrajectory + checkHoop,不修改 state * * 渲染层调用流程: * 1. const result = simulateShot(state, angle, power) * 2. 逐帧渲染 result.trajectoryPoints * 3. 结束后调用 updateScore(state, result.scored, config) */ export declare function simulateShot( state: BasketballState, angle: number, power: number, config: BasketballConfig, ): ShotResult;