// assets/scripts/GoalkeeperAI.ts import { _decorator, Component, Node, RigidBody, Vec3, math } from "cc"; const { ccclass, property } = _decorator; @ccclass("GoalkeeperAI") export class GoalkeeperAI extends Component { @property(Node) ball!: Node; @property({ tooltip: "球门线Z(世界坐标)" }) goalLineZ = 10; @property({ tooltip: "守门员水平活动范围X" }) rangeX = 3.5; @property({ tooltip: "移动速度(m/s)" }) speed = 6; @property({ tooltip: "反应延迟(秒)" }) reactDelay = 0.15; private targetX = 0; private tAcc = 0; private tmp = new Vec3(); update(dt: number) { if (!this.ball) return; // 简化预测:用当前速度线性外推到球门线的交点 const rb = this.ball.getComponent(RigidBody); if (!rb) return; rb.getLinearVelocity(this.tmp); const v = this.tmp.clone(); const bp = this.ball.worldPosition.clone(); if (Math.abs(v.z) < 0.1) return; // 几乎不朝球门方向飞 const timeToLine = (this.goalLineZ - bp.z) / v.z; // z 轴朝向球门 if (timeToLine < 0) return; // 已过线或背离 this.tAcc += dt; if (this.tAcc >= this.reactDelay) { const predictX = bp.x + v.x * timeToLine; this.targetX = math.clamp(predictX, -this.rangeX, this.rangeX); this.tAcc = 0; // 下次再延迟 } // 移动守门员 const p = this.node.worldPosition; const dx = this.targetX - p.x; const step = math.clamp(dx, -this.speed * dt, this.speed * dt); this.node.setWorldPosition(p.x + step, p.y, p.z); } }