Closed expglsf closed 2 years ago
该问题的具体原因如下:
角色控制器 CharacterController::move()
会直接调用 PhysicsSystem::overlap()
检测下一个位置是否会和任意有 RigidBodyComponent
组件的物体发送碰撞.
PhysicsSystem::overlap()
的具体实现是逐一检测 PhysicsActor
的每个 RigidBodyBoxShape
是否有交集.
此时使用的变换来自 RigidBodyShapeBase::m_global_transform
:
https://github.com/BoomingTech/Pilot/blob/529a140a23931addf593b14cf19cfc051e7e5d0d/engine/source/runtime/resource/res_type/components/rigid_body.h#L21
但是该变量仅在 PhysicsActor::createShapes
中被初始化了一次, 该函数最初被 RigidBodyComponent::RigidBodyComponent()
调用.
综上所述, 在检测中实际使用的变换是在 RigidBodyComponent
创建时 GObject
的 TransformComponent
组件中的值加上包含在参数 RigidBodyActorRes
中的 RigidBodyShapeBase::m_local_transform
的值, 且该变换之后保持不变.
个人觉得可行的解决办法:
在 PhysicsActor
中添加一个脏标记. 在 TransformComponent
中的非 const 成员函数被调用时调用 obj->tryGetComponent(RigidBodyComponent)->getPhysicsActor()
(最后一个 getter 目前不存在) 来获取 PhysicsActor
, 然后设置脏标记.
在以下任意一种情况进行更新:
PhysicsSystem::overlap
等需要使用到 RigidBodyShapeBase::m_global_transform
的地方. 按照现版本引擎的实现, 该方法会被调用的次数更多, 效率可能不佳. 不过调用方不需要专门更新这些数据.PhysicsSystem::integrateVelocity()
之后. 将刚体的变换同步到其碰撞体上. 但目前这样写, 代码甚至不会被执行.检查 PhysicsActor
是否有脏标记, 若有则遍历其 Shapes, 更新它们的 RigidBodyShapeBase::m_global_transform
, 然后清除脏标记.
感谢反馈!此问题在发布时为已知问题,正在修复和测试,会在下一次更新时发出。
在场景中对带有碰撞的物体进行平移、缩放、旋转等变换时,物体的碰撞并未随之改变。例如:将一个带有碰撞的墙平移后,运行游戏角色会穿过该墙壁,而在原来的位置上仍有碰撞阻挡角色