You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Cannon.js物理刚体以固定速度朝动态目标移动?

解决Cannon.js刚体固定速度追踪目标的问题

我完全懂你的困扰——直接拿位置差当速度确实会让追踪的刚体“疯跑”,距离越远速度越快,完全没法控制节奏。下面给你几个实用的方案,完美实现固定速度的AI追踪,直到碰撞目标:

1. 基础方案:归一化方向向量(最直接)

核心思路是先算出追踪的方向向量,把它变成长度为1的单位向量,再乘以你想要的固定速度,这样不管距离多远,刚体的移动速度都是恒定的。

代码示例:

// 计算目标与当前刚体的方向向量(这里假设是X-Z平面的2D追踪,Y轴设为0)
const direction = new CANNON.Vec3(
  target.position.x - body.position.x,
  0,
  target.position.z - body.position.z
);

// 归一化方向向量:把向量长度缩为1,确保后续乘以速度后大小固定
direction.normalize();

// 设置固定移动速度,比如设为5(数值根据你的场景调整)
const moveSpeed = 5;
body.velocity.x = direction.x * moveSpeed;
body.velocity.z = direction.z * moveSpeed;

⚠️ 注意:如果两个物体位置完全重合,归一化会出问题,所以可以加个距离判断:

const distance = direction.length();
if (distance > 0.1) { // 小于0.1就认为已经接近目标,停止移动
  direction.normalize();
  body.velocity.x = direction.x * moveSpeed;
  body.velocity.z = direction.z * moveSpeed;
} else {
  body.velocity.set(0, 0, 0);
}

2. 物理真实方案:用冲量/力控制(推荐)

直接修改velocity有时候会显得很生硬,尤其是当刚体受到摩擦力、重力等其他力影响时。用applyImpulse或applyForce可以让追踪更符合物理引擎的特性,自动补偿外力的影响。

代码示例(用冲量):

const moveSpeed = 5;
const direction = new CANNON.Vec3(
  target.position.x - body.position.x,
  0,
  target.position.z - body.position.z
);
direction.normalize();

// 计算期望的目标速度
const desiredVelocity = direction.scale(moveSpeed);
// 计算当前速度与目标速度的差值
const velocityDelta = desiredVelocity.vsub(body.velocity);

// 冲量 = 质量 × 速度变化,直接施加冲量让刚体快速趋近目标速度
const impulse = velocityDelta.scale(body.mass);
body.applyImpulse(impulse, body.position);

这个方法的好处是:如果刚体在移动中碰到障碍物、受到摩擦力减速,引擎会自动调整冲量,保持你设置的追踪速度,效果更真实。

3. 流畅AI优化:平滑转向

如果要让AI的追踪更自然,不会突然猛转方向,可以加个缓动因子,让速度平滑过渡:

const moveSpeed = 5;
const smoothFactor = 0.1; // 数值越小转向越平滑,范围0-1

const direction = new CANNON.Vec3(
  target.position.x - body.position.x,
  0,
  target.position.z - body.position.z
);
direction.normalize();

const desiredVelocity = direction.scale(moveSpeed);

// 缓动更新速度,让转向更丝滑
body.velocity.x = body.velocity.x + (desiredVelocity.x - body.velocity.x) * smoothFactor;
body.velocity.z = body.velocity.z + (desiredVelocity.z - body.velocity.z) * smoothFactor;

碰撞后停止追踪

最后,如果你需要刚体碰到目标后立刻停止,可以监听Cannon.js的碰撞事件:

body.addEventListener('collide', (event) => {
  // 判断碰撞的物体是不是目标
  if (event.body === target) {
    // 停止移动
    body.velocity.set(0, 0, 0);
    // 这里可以加碰撞后的逻辑,比如触发攻击、播放动画等
  }
});

根据你的场景选对应的方案就行:简单需求用归一化方向,追求物理真实用冲量,做流畅AI就加平滑转向~

内容的提问来源于stack exchange,提问作者Matt DeVenge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:04:40