物理

碰撞形状

碰撞形状(ColliderShape)定义了碰撞器的物理外形。Galacean 提供了多种基础碰撞形状,可以通过组合这些形状来构建复杂的碰撞区域。

支持的形状类型

形状类型特点后端支持
BoxColliderShape最基础的碰撞形状
适用于方形、矩形物体
可以通过 size 属性调整三个轴向的大小
所有物理后端
SphereColliderShape用于球形物体的碰撞检测
通过 radius 属性设置半径
所有物理后端
PlaneColliderShape无限大的平面碰撞体
通常用作地面
仅 physics-physx 后端
CapsuleColliderShape由圆柱体和两个半球组成
适用于角色碰撞器
可以设置 radius 和 height
仅 physics-physx 后端

基本属性

变换属性

  • position
    形状相对于碰撞器实体的局部位置偏移。

  • rotation
    形状相对于碰撞器实体的局部旋转。

物理材质

  • material
    定义形状的物理材质属性。每个碰撞形状都需要有一个物理材质,用于定义其物理特性:
属性描述默认值
staticFriction物体静止时的摩擦系数,值越大物体越难开始移动0.6
dynamicFriction物体运动时的摩擦系数,值越大物体移动时受到的阻力越大0.6
bounciness碰撞反弹程度,取值范围 0-1,0 表示完全不反弹,1 表示完全弹性碰撞0
bounceCombine定义两个碰撞物体的弹性系数如何组合:
  • Average: 取两者平均值(默认)
  • Minimum: 取两者中的最小值
  • Maximum: 取两者中的最大值
  • Multiply: 将两者相乘
Average
frictionCombine定义两个碰撞物体的摩擦系数如何组合:
  • Average: 取两者平均值(默认)
  • Minimum: 取两者中的最小值
  • Maximum: 取两者中的最大值
  • Multiply: 将两者相乘
Average

触发器设置

  • isTrigger
    是否作为触发器使用:
    • true:只触发触发器事件,不产生物理反应
    • false:正常的物理碰撞(默认)

有关碰撞和触发器事件的详细信息,请参阅碰撞事件文档。

脚本使用

创建基础形状

// 创建盒形碰撞器
const boxShape = new BoxColliderShape();
boxShape.size = new Vector3(1, 1, 1);
boxShape.position = new Vector3(0, 0.5, 0);
 
// 创建球形碰撞器
const sphereShape = new SphereColliderShape();
sphereShape.radius = 0.5;
sphereShape.position = new Vector3(0, 1, 0);
 
// 创建胶囊体碰撞器
const capsuleShape = new CapsuleColliderShape();
capsuleShape.radius = 0.5;
capsuleShape.height = 2;
 
// 创建平面碰撞器
const planeShape = new PlaneColliderShape();

形状管理

// 获取所有形状
const shapes = staticCollider.shapes;
 
// 增加形状
const boxShape = new BoxColliderShape();
staticCollider.addShape(boxShape);
 
// 移除特定形状
staticCollider.removeShape(boxShape);
 
// 清空所有形状
staticCollider.clearShapes();

设置物理材质

// 创建物理材质并配置属性
const material = new PhysicsMaterial();
material.staticFriction = 0.6;    // 静摩擦系数
material.dynamicFriction = 0.4;   // 动摩擦系数
material.bounciness = 0.5;        // 弹性系数
 
// 设置材质的组合模式
material.frictionCombine = PhysicsMaterialCombineMode.Average;  // 摩擦力组合方式
material.bounceCombine = PhysicsMaterialCombineMode.Maximum;    // 弹性组合方式
 
// 将材质应用到碰撞形状
const shape = new BoxColliderShape();
shape.material = material;
 
// 为不同的形状设置不同的材质
const iceShape = new BoxColliderShape();
const iceMaterial = new PhysicsMaterial();
iceMaterial.staticFriction = 0.1;
iceMaterial.dynamicFriction = 0.05;
iceMaterial.bounciness = 0;
iceShape.material = iceMaterial;
 
const bounceShape = new SphereColliderShape();
const bounceMaterial = new PhysicsMaterial();
bounceMaterial.bounciness = 0.8;
bounceMaterial.bounceCombine = PhysicsMaterialCombineMode.Maximum;
bounceShape.material = bounceMaterial;
 
// 不再使用时记得销毁材质
material.destroy();
iceMaterial.destroy();
bounceMaterial.destroy();

创建复合形状

// 创建带有多个碰撞形状的物体
function createCompoundCollider(entity: Entity) {
    const collider = entity.addComponent(DynamicCollider);
    
    // 主体形状
    const mainShape = new BoxColliderShape();
    mainShape.size = new Vector3(2, 1, 1);
    collider.addShape(mainShape);
    
    // 顶部形状
    const topShape = new BoxColliderShape();
    topShape.size = new Vector3(1, 1, 1);
    topShape.position = new Vector3(0, 1, 0);
    collider.addShape(topShape);
    
    return collider;
}

示例参考

常用场景示例

  1. 创建地面
// 创建一个简单的地面
function createGround(width: number, length: number): Entity {
    const entity = new Entity();
    const collider = entity.addComponent(StaticCollider);
    
    const groundShape = new BoxColliderShape();
    groundShape.size = new Vector3(width, 0.1, length);
    
    // 设置地面的物理材质
    const material = new PhysicsMaterial();
    material.staticFriction = 0.6;
    material.dynamicFriction = 0.6;
    material.bounciness = 0.0;
    groundShape.material = material;
    
    collider.addShape(groundShape);
    return entity;
}
 
// 创建一个无限平面地面
function createInfinitePlane(): Entity {
    const entity = new Entity();
    const collider = entity.addComponent(StaticCollider);
    
    const planeShape = new PlaneColliderShape();
    // 设置地面材质
    const material = new PhysicsMaterial();
    material.staticFriction = 0.6;
    material.dynamicFriction = 0.6;
    planeShape.material = material;
    
    collider.addShape(planeShape);
    return entity;
}
  1. 创建墙壁
// 创建一个可配置的墙壁
function createWall(width: number, height: number, depth: number, friction: number = 0.6): Entity {
    const entity = new Entity();
    const collider = entity.addComponent(StaticCollider);
    
    const wallShape = new BoxColliderShape();
    wallShape.size = new Vector3(width, height, depth);
    
    // 设置墙壁的物理材质
    const material = new PhysicsMaterial();
    material.staticFriction = friction;
    material.dynamicFriction = friction;
    material.bounciness = 0.0;
    wallShape.material = material;
    
    collider.addShape(wallShape);
    return entity;
}
  1. 创建斜坡
// 创建一个带摩擦力的斜坡
function createSlope(width: number, height: number, angle: number): Entity {
    const entity = new Entity();
    const collider = entity.addComponent(StaticCollider);
    
    const slopeShape = new BoxColliderShape();
    slopeShape.size = new Vector3(width, 0.1, height);
    slopeShape.rotation = new Vector3(0, 0, angle);
    
    // 设置斜坡的物理材质
    const material = new PhysicsMaterial();
    material.staticFriction = 0.8;  // 较大的摩擦力防止物体滑落
    material.dynamicFriction = 0.8;
    material.bounciness = 0.0;
    slopeShape.material = material;
    
    collider.addShape(slopeShape);
    return entity;
}
  1. 创建不同材质的复合形状
// 创建一个混合材质的平台
function createMixedPlatform(): Entity {
    const entity = new Entity();
    const collider = entity.addComponent(StaticCollider);
    
    // 创建主平台(普通摩擦力)
    const platformShape = new BoxColliderShape();
    platformShape.size = new Vector3(10, 0.5, 10);
    const normalMaterial = new PhysicsMaterial();
    normalMaterial.staticFriction = 0.6;
    normalMaterial.dynamicFriction = 0.6;
    platformShape.material = normalMaterial;
    collider.addShape(platformShape);
    
    // 添加冰面区域(低摩擦力)
    const iceShape = new BoxColliderShape();
    iceShape.size = new Vector3(3, 0.51, 3);
    iceShape.position = new Vector3(3, 0, 0);
    const iceMaterial = new PhysicsMaterial();
    iceMaterial.staticFriction = 0.1;
    iceMaterial.dynamicFriction = 0.05;
    iceShape.material = iceMaterial;
    collider.addShape(iceShape);
    
    // 添加弹性区域
    const bounceShape = new BoxColliderShape();
    bounceShape.size = new Vector3(3, 0.51, 3);
    bounceShape.position = new Vector3(-3, 0, 0);
    const bounceMaterial = new PhysicsMaterial();
    bounceMaterial.bounciness = 0.8;
    bounceMaterial.bounceCombine = PhysicsMaterialCombineMode.Maximum;
    bounceShape.material = bounceMaterial;
    collider.addShape(bounceShape);
    
    return entity;
}

最佳实践

  1. 形状选择

    • 复杂物体使用多个基础形状组合
    • 避免使用过多的碰撞形状(影响性能)
    • 为角色控制器选择胶囊体形状
  2. 性能优化

    • 使用尽可能简单的碰撞形状
    • 合理设置局部偏移,避免碰撞形状过度重叠
    • 适当使用触发器代替实际的物理碰撞
    • 及时销毁不再使用的碰撞形状及物理材质

这篇文档对您有帮助吗?