为ModelEntity添加PhysicsBodyComponent后,12面骰子无法正常落地求助
12面骰子ModelEntity无法落地的问题排查与解决
问题描述
替换为12面骰子(d20)模型后,为其添加PhysicsBodyComponent后无法正确落在地面上,但此前使用6面骰子时功能正常。
相关代码
let floor = ModelEntity(mesh: .generatePlane(width: 50, depth: 50), materials: [OcclusionMaterial()]) floor.generateCollisionShapes(recursive: false) floor.components[PhysicsBodyComponent.self] = .init( massProperties: .default, mode: .static ) content.add(floor) if let diceModel = try? await Entity(named: "d20"), let dice = diceModel.children.first?.children.first { dice.scale = [0.1, 0.1, 0.1] dice.position.y = 0.5 dice.position.z = -1 dice.generateCollisionShapes(recursive: true) dice.components.set(InputTargetComponent()) dice.components.set(ImageBasedLightReceiverComponent(imageBasedLight: dice)) dice.components.set(GroundingShadowComponent(castsShadow: true)) dice.components[PhysicsBodyComponent.self] = .init(PhysicsBodyComponent( massProperties: .default, material: .generate(staticFriction: 0.8, dynamicFriction: 0.5, restitution: 0.1), mode: .dynamic )) dice.components[PhysicsBodyComponent] dice.components[PhysicsMotionComponent.self] = .init() content.add(dice) }
问题原因与解决方法
1. 碰撞形状递归生成异常
generateCollisionShapes(recursive: true)会为所有子实体生成碰撞体,多层嵌套的d20模型可能产生多个重叠或偏移的碰撞形状,导致物理引擎计算错误。
- 解决:将
recursive参数改为false,仅为当前骰子实体生成碰撞形状:dice.generateCollisionShapes(recursive: false)
2. 模型嵌套层级导致变换偏差
通过diceModel.children.first?.children.first获取实体,多层嵌套可能让缩放、位置等变换继承出现问题,导致碰撞体位置与视觉模型不匹配。
- 解决:直接使用顶层的
diceModel作为骰子实体,避免多层嵌套:if let dice = try? await Entity(named: "d20") { // 后续操作直接使用dice }
3. 默认质量属性不匹配复杂形状
.default质量属性是针对基础形状设计的,12面骰子的不规则形状需要更贴合的质量参数,否则会导致物理运动异常。
- 解决:手动设置质量属性,比如:
let massProps = MassProperties(mass: 0.1, centerOfMass: .zero, inertiaTensor: .init(diagonal: [0.001, 0.001, 0.001])) dice.components[PhysicsBodyComponent.self] = .init( massProperties: massProps, material: .generate(staticFriction: 0.8, dynamicFriction: 0.5, restitution: 0.1), mode: .dynamic )
4. 自动生成的碰撞形状精度不足
自动生成的碰撞形状可能无法精准贴合12面骰子的曲面,导致碰撞检测失效。
- 解决:手动为模型生成凸包碰撞形状:
if let mesh = dice.model?.mesh { dice.collisionShape = ConvexHullCollisionShape(mesh: mesh) }
5. 清理冗余代码
代码中dice.components[PhysicsBodyComponent]这一行无实际作用,直接删除即可。
修改后的完整代码示例
let floor = ModelEntity(mesh: .generatePlane(width: 50, depth: 50), materials: [OcclusionMaterial()]) floor.generateCollisionShapes(recursive: false) floor.components[PhysicsBodyComponent.self] = .init( massProperties: .default, mode: .static ) content.add(floor) if let dice = try? await Entity(named: "d20") { dice.scale = [0.1, 0.1, 0.1] dice.position.y = 0.5 dice.position.z = -1 dice.generateCollisionShapes(recursive: false) // 手动设置贴合的碰撞形状 if let mesh = dice.model?.mesh { dice.collisionShape = ConvexHullCollisionShape(mesh: mesh) } dice.components.set(InputTargetComponent()) dice.components.set(ImageBasedLightReceiverComponent(imageBasedLight: dice)) dice.components.set(GroundingShadowComponent(castsShadow: true)) let massProps = MassProperties(mass: 0.1, centerOfMass: .zero, inertiaTensor: .init(diagonal: [0.001, 0.001, 0.001])) dice.components[PhysicsBodyComponent.self] = .init( massProperties: massProps, material: .generate(staticFriction: 0.8, dynamicFriction: 0.5, restitution: 0.1), mode: .dynamic ) dice.components.set(PhysicsMotionComponent()) content.add(dice) }
内容的提问来源于stack exchange,提问作者kunj Barvaliya
相关产品推荐
相关产品推荐

