RealityKit中如何让带物理体的子实体带动父实体运动而非自身运动
嘿,这个需求我之前做项目时正好碰到过,琢磨了好一阵才搞定,给你详细捋捋怎么在RealityKit里实现~
首先得明确核心思路:我们要让带动态物理体的子实体,通过物理关节把运动传递给父实体,同时保持子实体相对于父实体的姿态完全固定——而且完全不用给父实体设置复杂的物理形状,完美避开你说的自定义变换转物理形状的麻烦。
具体步骤是这样的:
给父实体加一个运动学(kinematic)类型的物理体
别担心,这个物理体完全不用复杂设置,因为kinematic类型的实体不会被物理力主动推动,只会通过关节被动态实体带着走,所以形状随便设个简单的就行(甚至用默认的.box都没问题,完全不影响效果)。代码大概是这样:parentEntity.physicsBody = PhysicsBodyComponent(massProperties: .default, material: .default, mode: .kinematic)这里重点是把
mode设为.kinematic,其他参数用默认值就够了。给子实体配置好你的动态物理体和自定义变换
这一步就按你原本的需求来:给子实体设置好自定义的位置、缩放、旋转,然后加上动态物理体和对应的物理形状,比如:// 先设置子实体的自定义变换 childEntity.transform = Transform(scale: .init(x: 0.5, y: 0.5, z: 0.5), rotation: .init(angle: .pi/4, axis: .y), translation: .init(x: 1, y: 0, z: 0)) // 动态物理体,让它能被物理力推动 childEntity.physicsBody = PhysicsBodyComponent(massProperties: .default, material: .default, mode: .dynamic) // 子实体的自定义物理形状,按你需求来 childEntity.physicsShape = PhysicsShapeComponent(convexHullOf: childEntity)用固定关节(Fixed Joint)把父子实体绑定起来
这是最关键的一步,要让关节的帧匹配子实体相对于父实体的初始本地变换,这样绑定后子实体相对于父实体的姿态就不会乱变了。代码示例:// 先拿到子实体相对于父实体的本地变换 let childLocalTransform = childEntity.transform(relativeTo: parentEntity) // 创建固定关节:父实体的关节帧是子实体的本地位置,子实体的关节帧用自身原点 let fixedJoint = PhysicsJointFixed(frame: childLocalTransform, from: parentEntity, to: childEntity) // 把关节添加到父实体的物理关节组件里 parentEntity.physicsJoints = PhysicsJointsComponent(joints: [fixedJoint])
这样设置完之后,当子实体被物理力碰撞或者推动时,固定关节会强制父实体跟着子实体的运动轨迹走,而子实体相对于父实体的位置、姿态会完全保持你一开始设置的自定义变换,完全不会偏移~
我之前还试过直接在update方法里同步子实体的世界变换到父实体,结果出现了明显的抖动,因为物理更新和渲染更新的时机不匹配。用物理关节的话是引擎内部处理的,运动平滑得多,完全没有这个问题。
内容来源于stack exchange

