刚体
刚体是参与物理模拟的实体,需要两个组件:rigidbody 决定物理引擎如何处理实体,collision 提供形状。只有 rigidbody、没有 collision 时,不会参与碰撞,也不起作用。形状见碰撞形状,本页介绍刚体自身。
刚体类型
刚体的 type 决定谁控制运动:
- Static(静态):不移动,用于地面、墙壁和其他环境。引擎只在创建时定位,不再检查实体,开销较低。
- Dynamic(动态):完整模拟,受重力、碰撞、力和冲量影响,由物理引擎控制位置和旋转。
- Kinematic(运动学):由你通过实体变换控制,能推动动态刚体,但不受其影响,也不受重力。适用于移动平台、动画门和其他按脚本而非物理规律运动的对象。
下面创建一个一米见方的动态盒体,会落到下方物体上:
- 引擎
- 编辑器
- React
- Web Components
const box = new pc.Entity('box');
box.addComponent('render', { type: 'box' });
box.addComponent('collision', { type: 'box' });
box.addComponent('rigidbody', { type: pc.BODYTYPE_DYNAMIC, mass: 2 });
box.setPosition(0, 5, 0);
app.root.addChild(box);
选中实体,点击 Add Component,从 Physics 分组添加 Rigid Body 和 Collision。将刚体 Type 设为 Dynamic,Inspector 会显示质量和材质属性。默认半尺寸为 0.5 的盒形碰撞体,匹配一个单位的渲染立方体。
import { Entity } from '@playcanvas/react';
import { Render, Collision, RigidBody } from '@playcanvas/react/components';
<Entity name="box" position={[0, 5, 0]}>
<Render type="box" />
<Collision type="box" />
<RigidBody type="dynamic" mass={2} />
</Entity>
<pc-entity name="box" position="0 5 0">
<pc-render type="box"></pc-render>
<pc-collision type="box"></pc-collision>
<pc-rigid-body type="dynamic" mass="2"></pc-rigid-body>
</pc-entity>
质量与材质
四个属性描述重量和接触时的表面行为:
| 属性 | 说明 |
|---|---|
| Mass | 动态刚体质量,单位千克。较重物体需要更大力加速,也更容易推开轻物体。默认为 1,静态和运动学忽略此值 |
| Friction | 抵抗滑动程度,0 到 1,默认为 0.5 |
| Rolling Friction | 滚动阻力,避免球体和圆柱永远滚动,默认为 0 |
| Restitution | 弹性,0 到 1,默认为 0。接触双方的值相乘,因此球设为 1、地板设为 0 时仍不会反弹 |
- 引擎
- 编辑器
- React
- Web Components
entity.rigidbody.mass = 5;
entity.rigidbody.friction = 0.8;
entity.rigidbody.rollingFriction = 0.1;
entity.rigidbody.restitution = 0.6;
在 Rigid Body 上设置 Mass、Friction、Rolling Friction 和 Restitution。质量仅动态刚体显示。
<RigidBody type="dynamic" mass={5} friction={0.8} rollingFriction={0.1} restitution={0.6} />
<pc-rigid-body type="dynamic" mass="5" friction="0.8" rolling-friction="0.1" restitution="0.6"></pc-rigid-body>
阻尼与轴向系数
两组属性决定动态刚体运动后的行为:
- Linear Damping 和 Angular Damping:每秒损失的速度比例,0 到 1,类似空气阻力,默认为 0。
- Linear Factor 和 Angular Factor:按世界轴缩放移动和旋转,0 表示锁定该轴。角度系数
0, 0, 0可保持角色直立;线性系数1, 1, 0配合角度系数0, 0, 1可将刚体限制在 XY 平面,实现 2D 游戏。默认均为1, 1, 1。
- 引擎
- 编辑器
- React
- Web Components
// Slow the body down over time, like air resistance
entity.rigidbody.linearDamping = 0.2;
entity.rigidbody.angularDamping = 0.2;
// Keep a character upright: no rotation about any axis
entity.rigidbody.angularFactor = new pc.Vec3(0, 0, 0);
// Confine a body to the XY plane of a 2D game
entity.rigidbody.linearFactor = new pc.Vec3(1, 1, 0);
在 Rigid Body 上设置这些属性,仅动态刚体显示。
<RigidBody type="dynamic" linearDamping={0.2} angularDamping={0.2} angularFactor={[0, 0, 0]} />
<pc-rigid-body type="dynamic" linear-damping="0.2" angular-damping="0.2" angular-factor="0 0 0"></pc-rigid-body>
重力缩放
重力缩放为单个动态刚体乘以世界重力。默认 1 正常下落,0 到 1 下落较缓,0 不受重力,负数像气球上升。它作用于当前世界重力,之后世界重力变化也会跟随。静态和运动学刚体不受重力,因此此属性无效。
线性系数为 0 会锁定轴向所有运动,而重力缩放为 0 仅移除重力,仍响应碰撞、力和冲量。若要模拟小行星中心引力等自定义重力,设为 0,再每帧自行施加对应力。
无论通过代码、React prop 还是 Web Components 特性修改,都不会唤醒休眠刚体。静置盒体改为负重力后仍保持原位,直到被扰动。因此修改可能休眠的刚体后,应调用 activate(),参见休眠。
- 引擎
- 编辑器
- React
- Web Components
// Fall under half the world gravity
entity.rigidbody.gravityScale = 0.5;
// Drift slowly upwards like a balloon, waking the body in case it is asleep
entity.rigidbody.gravityScale = -0.2;
entity.rigidbody.activate();
在 Rigid Body 上设置 Gravity Scale,与阻尼和轴向系数一样,仅动态刚体显示。
<RigidBody type="dynamic" gravityScale={-0.2} />
<pc-rigid-body type="dynamic" gravity-scale="-0.2"></pc-rigid-body>
休眠
动态刚体静止后,物理引擎会将其休眠,直到被扰动才恢复模拟。施加力、冲量、扭矩、赋速度、传送或被其他刚体碰撞,都会自动唤醒,也可手动唤醒:
if (!entity.rigidbody.isActive()) {
entity.rigidbody.activate();
}
移动与传送
刚体类型决定位置和旋转由谁控制,也决定移动方式:
| 类型 | 移动方式 | 设置实体变换的效果 |
|---|---|---|
| Dynamic | 力、冲量、速度,或使用 teleport 跳转 | 不移动刚体;运动刚体下一步覆盖修改,休眠刚体留在原位 |
| Kinematic | 实体变换 | 下一物理步跟随 |
| Static | 原本不应移动,可用 teleport 重新定位 | 不影响刚体,保持创建时位置 |
下面的调用在各种开发方式中相同。React 可在 <Entity> 内组件通过 useParent 获取实体;Web Components 通过 <pc-entity> 的 entity 属性访问。移动刚体介绍逐帧代码的位置。
动态刚体
动态刚体的位置和旋转由物理引擎控制。使用力或速度移动;重新生成等需要跳转时,调用 rigidbody 的 teleport。传送不会清空速度,若要到达后静止,应先重置速度:
// Move to a position, keeping the current rotation
entity.rigidbody.teleport(0, 10, 0);
// Move and rotate, with the rotation given as Euler angles in degrees
entity.rigidbody.teleport(new pc.Vec3(0, 10, 0), new pc.Vec3(0, 90, 0));
// Respawn at rest: clear the old motion, then move and rotate with a quaternion
entity.rigidbody.linearVelocity = pc.Vec3.ZERO;
entity.rigidbody.angularVelocity = pc.Vec3.ZERO;
entity.rigidbody.teleport(spawn.getPosition(), spawn.getRotation());
linearVelocity 和 angularFactor 等向量属性返回只读快照,应赋新向量,而非修改返回对象。
运动学刚体
运动学刚体相反:用 setPosition、setRotation、lookAt 等变换 API 移动实体,刚体下一步跟随,并带动停在上面的动态刚体:
// A platform that slides back and forth along the X axis
platform.setPosition(Math.sin(time) * 2, 0.5, 0);
静态刚体
引擎仅在创建时读取静态刚体的位置和旋转,之后不再检查。这降低了开销,但运行中移动实体只会让模型移动,其他物体仍与原位置的隐形形状碰撞。
门、升降台等运行中移动的对象应设为运动学。若只是重排关卡等偶尔定位静态刚体,可以用 teleport 同时移动实体和刚体:
// Move a static wall, and its body, to a new position
wall.rigidbody.teleport(0, 0, 10);
传送静态刚体不会唤醒停在它上面的物体,已休眠者仍保持原位,即使悬浮在空中。
缩放
刚体只有位置和旋转,没有缩放,因此缩放实体不会改变刚体尺寸。尺寸来自碰撞形状。盒体、球体、胶囊、圆柱和圆锥应修改半尺寸、半径等属性,刚体会按新尺寸重建并继续运动。网格形状例外,会跟随实体缩放。各类型详情见碰撞形状的缩放。
碰撞组与掩码
每个刚体属于一个碰撞组,并通过掩码指定能与哪些组碰撞。只有双方的组都在对方掩码中才会交互。引擎设置类型时自动分配:动态与全部类型碰撞,静态和运动学彼此不碰撞。可通过代码进一步限制,例如让投射物互相忽略:
// Put the body in a user group and stop it colliding with other members of that group.
// Set these after the type, because changing the type resets them.
entity.rigidbody.group = pc.BODYGROUP_USER_1;
entity.rigidbody.mask = pc.BODYMASK_ALL ^ pc.BODYGROUP_USER_1;
提供 pc.BODYGROUP_USER_1 到 pc.BODYGROUP_USER_8 八个用户组。同样的组和掩码也用于射线筛选。
另请参阅
- 碰撞形状:每个刚体需要的形状。
- 移动刚体:力、冲量、扭矩和速度。
- Rigid Body 组件:编辑器属性参考。
- RigidBodyComponent:API 参考。
- 通过代码创建刚体:通过脚本添加两个组件的教程。