BoomingTech / Piccolo

Piccolo (formerly Pilot) – mini game engine for games104
MIT License
5.9k stars 1.83k forks source link

碰撞体未跟随所附物体的transform进行变换 #17

Closed expglsf closed 2 years ago

expglsf commented 2 years ago

在场景中对带有碰撞的物体进行平移、缩放、旋转等变换时,物体的碰撞并未随之改变。例如:将一个带有碰撞的墙平移后,运行游戏角色会穿过该墙壁,而在原来的位置上仍有碰撞阻挡角色

ShenMian commented 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 创建时 GObjectTransformComponent 组件中的值加上包含在参数 RigidBodyActorRes 中的 RigidBodyShapeBase::m_local_transform 的值, 且该变换之后保持不变.

ShenMian commented 2 years ago

个人觉得可行的解决办法: 在 PhysicsActor 中添加一个脏标记. 在 TransformComponent 中的非 const 成员函数被调用时调用 obj->tryGetComponent(RigidBodyComponent)->getPhysicsActor() (最后一个 getter 目前不存在) 来获取 PhysicsActor, 然后设置脏标记.

在以下任意一种情况进行更新:

检查 PhysicsActor 是否有脏标记, 若有则遍历其 Shapes, 更新它们的 RigidBodyShapeBase::m_global_transform, 然后清除脏标记.

Ol6rin commented 2 years ago

感谢反馈!此问题在发布时为已知问题,正在修复和测试,会在下一次更新时发出。