移动刚体
动态刚体响应力和冲量。力在一段时间内作用,冲量瞬间改变速度。两者都由 RigidBodyComponent 提供,只影响动态刚体;静态不移动,运动学由你定位,因此调用无效。
本页所有操作都调用 rigidbody,各开发方式完全相同,区别只在代码运行位置。
运行物理代码
按住按键时通常每帧施力,因此需要能够逐帧运行并访问实体的位置:
- 引擎
- 编辑器
- React
- Web Components
订阅应用 update,或按照脚本编程为实体附加脚本:
app.on('update', (dt) => {
// While the right arrow key is held, push the box along the world X axis
if (app.keyboard.isPressed(pc.KEY_RIGHT)) {
box.rigidbody.applyForce(10, 0, 0);
}
});
添加 Script 组件,通过脚本 update 驱动刚体:
import { Script, KEY_RIGHT } from 'playcanvas';
export class Push extends Script {
static scriptName = 'push';
update(dt) {
// While the right arrow key is held, push the body along the world X axis
if (this.app.keyboard.isPressed(KEY_RIGHT)) {
this.entity.rigidbody.applyForce(10, 0, 0);
}
}
}
脚本创建和附加方法见脚本入门。
在 <Entity> 内放置组件,通过 useParent 获取实体,通过 useAppEvent 每帧执行:
import { KEY_RIGHT } from 'playcanvas';
import { useApp, useParent, useAppEvent } from '@playcanvas/react/hooks';
function Push() {
const app = useApp();
const entity = useParent();
useAppEvent('update', (dt) => {
// While the right arrow key is held, push the body along the world X axis
if (app.keyboard.isPressed(KEY_RIGHT)) {
entity.rigidbody?.applyForce(10, 0, 0);
}
});
return null;
}
<Entity name="box">
<Collision type="box" />
<RigidBody type="dynamic" />
<Push />
</Entity>
加载导出与编辑器标签页相同 Push 类的脚本,再附加到实体:
<pc-asset src="push.mjs"></pc-asset>
<pc-entity name="box">
<pc-collision type="box"></pc-collision>
<pc-rigid-body type="dynamic"></pc-rigid-body>
<pc-script>
<pc-script-instance name="push"></pc-script-instance>
</pc-script>
</pc-entity>
力
持续推动重物时,应在推动期间持续施力。力累积到下一物理步,每帧施力产生持续加速度;相同力下,较重刚体加速更慢:
// Push along the world X axis, every frame while the push lasts
entity.rigidbody.applyForce(10, 0, 0);
冲量
炮弹发射应施加一次冲量。冲量是动量的瞬间变化,因此只施加一次,而非每帧:
// Launch up and to the right, once
entity.rigidbody.applyImpulse(10, 10, 0);
两个方法都接受 Vec3,适合运行时计算方向:
// Launch the body along the direction it is facing
const impulse = entity.forward.clone().mulScalar(10);
entity.rigidbody.applyImpulse(impulse);
在指定点施加
默认作用于质心,只改变速度,不使刚体旋转。传入可选作用点,可同时产生旋转。两个方法对点的解释不同:
applyForce(force, point):点是相对刚体位置的世界空间偏移。applyImpulse(impulse, point):点位于实体局部空间。
// Impulse: the point is in the entity's local space, so this pushes up on the
// point 1 unit along the entity's local Z axis and makes the body tip over
entity.rigidbody.applyImpulse(new pc.Vec3(0, 10, 0), new pc.Vec3(0, 0, 1));
// Force: the point is a world space offset from the body, so transform the
// same local point into world space first
const offset = entity.getWorldTransform().transformVector(new pc.Vec3(0, 0, 1));
entity.rigidbody.applyForce(new pc.Vec3(0, 10, 0), offset);
也可传入六个数字,前三个为力或冲量,后三个为作用点。
扭矩
让刚体旋转而不平移时,施加扭矩。applyTorque 对应持续力,applyTorqueImpulse 对应冲量。两者接受 Vec3 或三个数字,方向表示世界空间旋转轴,长度表示强度:
// Keep spinning the body about the world Y axis while called every frame
entity.rigidbody.applyTorque(0, 5, 0);
// Give the body a single kick of spin about the world X axis
entity.rigidbody.applyTorqueImpulse(2, 0, 0);
直接设置速度
有时希望无论质量如何都以精确速度移动,例如角色立即达到最高速,或重置投射物。可直接赋值 linearVelocity 和 angularVelocity:
// Move at 5 units per second along the world X axis, keeping the current vertical speed
const velocity = entity.rigidbody.linearVelocity;
entity.rigidbody.linearVelocity = new pc.Vec3(5, velocity.y, 0);
// Stop all motion
entity.rigidbody.linearVelocity = pc.Vec3.ZERO;
entity.rigidbody.angularVelocity = pc.Vec3.ZERO;
速度 getter 返回只读快照,原地修改返回向量无效,应始终赋新值。完整角色实现见引擎第一人称和第三人称控制器脚本。
运动学运动
运动学刚体忽略力、冲量和速度。移动实体后,物理引擎在下一步开始读取新变换;站在运动学平台上的动态刚体会被带动:
// Slide a platform back and forth along the world X axis
let time = 0;
app.on('update', (dt) => {
time += dt;
platform.setPosition(Math.sin(time) * 2, 0.5, 0);
});
阻尼与轴向系数影响上述行为。阻尼随时间减速,某轴系数为 0 则禁止该轴移动或旋转,可用于保持角色直立或限制到 2D 平面。
另请参阅
- 刚体:类型、质量、阻尼和轴向系数。
- 碰撞事件:响应刚体碰撞。
- 力与冲量:施加力、冲量和扭矩的教程。
- RigidBodyComponent:本页方法的 API 参考。