跳到主要内容

刚体

刚体是参与物理模拟的实体,需要两个组件:rigidbody 决定物理引擎如何处理实体,collision 提供形状。只有 rigidbody、没有 collision 时,不会参与碰撞,也不起作用。形状见碰撞形状,本页介绍刚体自身。

刚体类型​

刚体的 type 决定谁控制运动:

  • Static(静态):不移动,用于地面、墙壁和其他环境。引擎只在创建时定位,不再检查实体,开销较低。
  • Dynamic(动态):完整模拟,受重力、碰撞、力和冲量影响,由物理引擎控制位置和旋转。
  • Kinematic(运动学):由你通过实体变换控制,能推动动态刚体,但不受其影响,也不受重力。适用于移动平台、动画门和其他按脚本而非物理规律运动的对象。

下面创建一个一米见方的动态盒体,会落到下方物体上:

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);
下落的形状

质量与材质​

四个属性描述重量和接触时的表面行为:

属性说明
Mass动态刚体质量,单位千克。较重物体需要更大力加速,也更容易推开轻物体。默认为 1,静态和运动学忽略此值
Friction抵抗滑动程度,0 到 1,默认为 0.5
Rolling Friction滚动阻力,避免球体和圆柱永远滚动,默认为 0
Restitution弹性,0 到 1,默认为 0。接触双方的值相乘,因此球设为 1、地板设为 0 时仍不会反弹
entity.rigidbody.mass = 5;
entity.rigidbody.friction = 0.8;
entity.rigidbody.rollingFriction = 0.1;
entity.rigidbody.restitution = 0.6;

阻尼与轴向系数​

两组属性决定动态刚体运动后的行为:

  • 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。
// 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);

重力缩放​

重力缩放为单个动态刚体乘以世界重力。默认 1 正常下落,0 到 1 下落较缓,0 不受重力,负数像气球上升。它作用于当前世界重力,之后世界重力变化也会跟随。静态和运动学刚体不受重力,因此此属性无效。

线性系数为 0 会锁定轴向所有运动,而重力缩放为 0 仅移除重力,仍响应碰撞、力和冲量。若要模拟小行星中心引力等自定义重力,设为 0,再每帧自行施加对应力。

无论通过代码、React prop 还是 Web Components 特性修改,都不会唤醒休眠刚体。静置盒体改为负重力后仍保持原位,直到被扰动。因此修改可能休眠的刚体后,应调用 activate(),参见休眠。

// 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();

休眠​

动态刚体静止后,物理引擎会将其休眠,直到被扰动才恢复模拟。施加力、冲量、扭矩、赋速度、传送或被其他刚体碰撞,都会自动唤醒,也可手动唤醒:

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 八个用户组。同样的组和掩码也用于射线筛选。

另请参阅​