// assets/scripts/Preview.ts import { _decorator, Component, Node, Prefab, instantiate, Vec3 } from "cc"; import { BallPhysics } from "./BallPhysics"; const { ccclass, property } = _decorator; @ccclass("Preview") export class Preview extends Component { @property(Prefab) pointPrefab: Prefab = null!; @property(Node) goal: Node = null!; @property({ tooltip: "轨迹点数量" }) maxPoints = 30; @property({ tooltip: "步长时间(秒)" }) timeStep = 0.05; @property(BallPhysics) ballPhys: BallPhysics = null!; private points: Node[] = []; clear() { for (const p of this.points) p.destroy(); this.points.length = 0; } /** 显示预测轨迹 */ showTrajectory(startPos: Vec3, dir: Vec3, speed: number, spin: Vec3) { this.clear(); if (!this.pointPrefab || !this.ballPhys) return; const goalZ = this.goal?.worldPosition?.z; // 初始状态 let pos = startPos.clone(); let v = dir.clone().multiplyScalar(speed); let w = spin.clone(); // 自旋 // 迭代预测 // let age = 0; for (let i = 0; i < this.maxPoints; i++) { // age += this.timeStep; // 保存点 const p = instantiate(this.pointPrefab); p.setWorldPosition(pos); p.setParent(this.node); this.points.push(p); // === 模拟 BallPhysics.update(dt) === // const dt = this.timeStep; const dt = this.timeStep * 0.5; // 空气阻力 const speedNow = v.length(); if (speedNow > 0.01) { const drag = v.clone().multiplyScalar(-this.ballPhys.dragK * speedNow); v.add(drag.multiplyScalar(dt)); } // 马格努斯效应:F = k * (ω × v) if (w.lengthSqr() > 0.0001 && v.lengthSqr() > 0.0001) { // const tFactor = 1.0 / (1.0 + age * 2.0); // age 是飞行时间,越久衰减越快 // const magnus = w // .clone() // .cross(v) // .multiplyScalar(this.ballPhys.magnusK * tFactor); // v.add(magnus.multiplyScalar(dt)); const magnus = w.clone().cross(v).multiplyScalar(this.ballPhys.magnusK); v.add(magnus.multiplyScalar(dt)); } // 重力 v.y += -9.8 * dt; // 移动 pos = pos.add(v.clone().multiplyScalar(dt)); if ( (startPos.z > goalZ && pos.z <= goalZ) || (startPos.z < goalZ && pos.z >= goalZ) ) { break; } } } }