物理
动态碰撞器
动态碰撞器(DynamicCollider)用于模拟可以自由运动并受物理影响的物体。它可以响应重力、受力、碰撞等物理作用,适用于需要真实物理模拟的游戏物体。
- 选中目标实体,并在检查器中点击添加组件按钮,添加 DynamicCollider 组件。
- 为碰撞器添加碰撞形状。动态碰撞器支持添加多个碰撞形状,关于碰撞形状的详细说明请参考碰撞形状文档。目前支持以下类型:
- 调整碰撞形状的位置、大小等属性,使其与场景元素匹配。
- 根据需要设置碰撞器的属性调整物体的物理行为,各属性的含义和作用请参考下文。
约束求解是物理引擎用来解决物体之间碰撞和约束的计算过程。每次迭代都会尝试调整物体的位置和速度,使其满足所有的物理约束(如碰撞、关节等)。
- 迭代次数越多,物理表现越准确,但计算开销也越大
- 迭代次数过少可能导致物体出现抖动或穿透
- 建议根据实际需求平衡精度和性能:
- 一般物体:使用默认值 4
- 精确物理:可以增加到 6-8
- 性能优先:可以降低到 2-3
- constraints
用于限制物体在特定轴向上的运动。可以分别锁定位置和旋转的X、Y、Z轴向运动。
// 限制Y轴位置和所有旋转
collider.constraints =
DynamicColliderConstraints.FreezePositionY |
DynamicColliderConstraints.FreezeRotationX |
DynamicColliderConstraints.FreezeRotationY |
DynamicColliderConstraints.FreezeRotationZ;
模式 | 描述 | 适用场景 | 性能消耗 |
---|
Discrete | 最基础的检测模式,按固定的时间步长检测碰撞,可能在高速运动时发生穿透 | 低速物体 | 最低 |
Continuous | 对静态碰撞体使用连续碰撞检测,可以防止高速物体穿透静态物体 | 高速投射物 | 中等 |
ContinuousDynamic | 对所有碰撞体使用连续碰撞检测,可以防止高速物体之间的相互穿透 | 精确物理模拟 | 较高 |
ContinuousSpeculative | 使用推测算法进行连续碰撞检测,性能消耗介于 Discrete 和 Continuous 之间 | 一般游戏场景 | 中等 |
// 1. 普通物体使用离散检测
normalObject.collisionDetectionMode = CollisionDetectionMode.Discrete;
// 2. 投射物使用连续检测防止穿墙
projectile.collisionDetectionMode = CollisionDetectionMode.Continuous;
// 3. 重要物理交互使用完全连续检测
importantPhysicsObject.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
// 4. 一般游戏物体使用推测性检测
gameObject.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
-
基于物体速度选择
- 低速物体:使用 Discrete
- 中速物体:使用 ContinuousSpeculative
- 高速物体:使用 Continuous 或 ContinuousDynamic
-
基于重要性选择
- 普通场景物体:使用 Discrete
- 游戏关键物体:使用 ContinuousSpeculative
- 必须精确的物理交互:使用 ContinuousDynamic
-
基于性能选择
- 性能优先:使用 Discrete
- 性能与精度平衡:使用 ContinuousSpeculative
- 精度优先:使用 ContinuousDynamic
// 创建动态碰撞器
const dynamicCollider = entity.addComponent(DynamicCollider);
// 添加碰撞形状
const boxShape = new BoxColliderShape();
boxShape.size = new Vector3(1, 1, 1);
dynamicCollider.addShape(boxShape);
// 配置基本物理属性
dynamicCollider.mass = 1.0; // 设置质量
dynamicCollider.useGravity = true; // 启用重力
dynamicCollider.isKinematic = false; // 设置为动力学模式
class PhysicsController extends Script {
private _collider: DynamicCollider;
onAwake() {
// 获取动态碰撞器引用
this._collider = this.entity.getComponent(DynamicCollider);
// 配置运动阻尼
this._collider.linearDamping = 0.1; // 设置线性阻尼
this._collider.angularDamping = 0.1; // 设置角速度阻尼
// 设置运动约束
this._collider.constraints =
DynamicColliderConstraints.FreezeRotationX | // 锁定X轴旋转
DynamicColliderConstraints.FreezeRotationZ; // 锁定Z轴旋转
}
onUpdate() {
// 获取当前速度
const velocity = this._collider.linearVelocity;
// 设置速度
this._collider.linearVelocity = new Vector3(5, velocity.y, 0);
// 施加持续力(如推力)
if (this.engine.inputManager.isKeyHeldDown(Keys.W)) {
this._collider.applyForce(new Vector3(0, 0, 10));
}
// 施加瞬时力(如跳跃)
if (this.engine.inputManager.isKeyDown(Keys.Space)) {
this._collider.applyForce(new Vector3(0, 500, 0));
}
// 施加扭矩(使物体旋转)
if (this.engine.inputManager.isKeyHeldDown(Keys.R)) {
this._collider.applyTorque(new Vector3(0, 10, 0));
}
}
}
class KinematicController extends Script {
private _collider: DynamicCollider;
onAwake() {
this._collider = this.entity.getComponent(DynamicCollider);
this._collider.isKinematic = true; // 设置为运动学模式
}
// 实现电梯运动
onUpdate() {
const time = this.engine.time.elapsedTime;
const position = new Vector3(0, Math.sin(time) * 2, 0);
this._collider.move(position);
}
}
class SleepController extends Script {
private _collider: DynamicCollider;
onAwake() {
this._collider = this.entity.getComponent(DynamicCollider);
// 配置休眠参数
this._collider.sleepThreshold = 0.005; // 设置休眠阈值
}
onUpdate() {
// 检查是否处于休眠状态
if (this._collider.isSleeping()) {
console.log("物体已休眠");
}
// 手动控制休眠
if (this.engine.inputManager.isKeyDown(Keys.S)) {
this._collider.sleep(); // 强制休眠
}
if (this.engine.inputManager.isKeyDown(Keys.W)) {
this._collider.wakeUp(); // 唤醒物体
}
}
}
// 自动计算
const collider = entity.addComponent(DynamicCollider);
collider.mass = 1.0;
collider.automaticCenterOfMass = true; // 自动计算质心
collider.automaticInertiaTensor = true; // 自动计算惯性张量
// 手动设置
const customCollider = entity.addComponent(DynamicCollider);
customCollider.automaticCenterOfMass = false;
customCollider.automaticInertiaTensor = false;
customCollider.centerOfMass = new Vector3(0, 0.5, 0); // 手动设置质心
customCollider.inertiaTensor = new Vector3(1, 1, 1); // 手动设置惯性张量