Merge pull request #140 from SHADE-DP/SP3-2-Physics

SP3-2 Physics Bugfixes
BUGFIXES
Fixed the same velocity bug from before :<
Trigger Info are now stored in the correct container
This commit is contained in:
XiaoQiDigipen 2022-10-31 17:27:40 +08:00 committed by GitHub
commit 13c8928828
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 265 additions and 286 deletions

View File

@ -173,14 +173,8 @@ namespace SHADE
SHASSERT(rp3dBody != nullptr, "ReactPhysics body does not exist!") SHASSERT(rp3dBody != nullptr, "ReactPhysics body does not exist!")
auto* rigidBody = reinterpret_cast<rp3d::RigidBody*>(rp3dBody); auto* rigidBody = reinterpret_cast<rp3d::RigidBody*>(rp3dBody);
if (rb->dirtyFlags != 0)
// Sync velocities {
rb->linearVelocity = rigidBody->getLinearVelocity();
rb->angularVelocity = rigidBody->getAngularVelocity();
if (rb->dirtyFlags == 0)
return;
const uint16_t RB_FLAGS = rb->dirtyFlags; const uint16_t RB_FLAGS = rb->dirtyFlags;
for (size_t i = 0; i < SHRigidBodyComponent::NUM_DIRTY_FLAGS; ++i) for (size_t i = 0; i < SHRigidBodyComponent::NUM_DIRTY_FLAGS; ++i)
{ {
@ -261,6 +255,12 @@ namespace SHADE
rb->dirtyFlags = 0; rb->dirtyFlags = 0;
} }
else
{
rb->linearVelocity = rigidBody->getLinearVelocity();
rb->angularVelocity = rigidBody->getAngularVelocity();
}
}
void SHPhysicsObject::SyncColliders(SHColliderComponent* c) const noexcept void SHPhysicsObject::SyncColliders(SHColliderComponent* c) const noexcept
{ {

View File

@ -258,6 +258,9 @@ namespace SHADE
continue; continue;
const auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID); const auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
if (transformComponent && transformComponent->HasChanged()) if (transformComponent && transformComponent->HasChanged())
{ {
const auto WORLD_POS = transformComponent->GetWorldPosition(); const auto WORLD_POS = transformComponent->GetWorldPosition();
@ -266,12 +269,25 @@ namespace SHADE
physicsObject.SetPosition(WORLD_POS); physicsObject.SetPosition(WORLD_POS);
physicsObject.SetOrientation(WORLD_ROT); physicsObject.SetOrientation(WORLD_ROT);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID); // Sync physics component transforms
if (rigidBodyComponent) if (rigidBodyComponent)
{ {
rigidBodyComponent->position = WORLD_POS; rigidBodyComponent->position = WORLD_POS;
rigidBodyComponent->orientation = WORLD_ROT; rigidBodyComponent->orientation = WORLD_ROT;
}
if (colliderComponent)
{
colliderComponent->position = WORLD_POS;
colliderComponent->orientation = WORLD_ROT;
}
}
// Sync rigid bodies
if (rigidBodyComponent)
{
// Clear all forces and velocities if editor is stopped // Clear all forces and velocities if editor is stopped
if (SHSystemManager::GetSystem<SHEditor>()->editorState == SHEditor::State::STOP) if (SHSystemManager::GetSystem<SHEditor>()->editorState == SHEditor::State::STOP)
{ {
@ -282,8 +298,9 @@ namespace SHADE
rp3dRigidBody->setAngularVelocity(SHVec3::Zero); rp3dRigidBody->setAngularVelocity(SHVec3::Zero);
} }
// Sync active states
const bool COMPONENT_ACTIVE = rigidBodyComponent->isActive; const bool COMPONENT_ACTIVE = rigidBodyComponent->isActive;
system->SyncActiveStates(&physicsObject, COMPONENT_ACTIVE); SyncActiveStates(physicsObject, COMPONENT_ACTIVE);
if (!COMPONENT_ACTIVE) if (!COMPONENT_ACTIVE)
continue; continue;
@ -291,14 +308,12 @@ namespace SHADE
physicsObject.SyncRigidBody(rigidBodyComponent); physicsObject.SyncRigidBody(rigidBodyComponent);
} }
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID); // Sync colliders
if (colliderComponent) if (colliderComponent)
{ {
colliderComponent->position = WORLD_POS;
colliderComponent->orientation = WORLD_ROT;
const bool COMPONENT_ACTIVE = colliderComponent->isActive; const bool COMPONENT_ACTIVE = colliderComponent->isActive;
system->SyncActiveStates(&physicsObject, COMPONENT_ACTIVE); SyncActiveStates(physicsObject, colliderComponent->isActive);
if (!COMPONENT_ACTIVE) if (!COMPONENT_ACTIVE)
continue; continue;
@ -307,7 +322,6 @@ namespace SHADE
} }
} }
} }
}
void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept
{ {
@ -349,26 +363,10 @@ namespace SHADE
{ {
for (uint32_t i = 0; i < callbackData.getNbContactPairs(); ++i) for (uint32_t i = 0; i < callbackData.getNbContactPairs(); ++i)
{ {
auto contactPair = callbackData.getContactPair(i); const auto CONTACT_PAIR = callbackData.getContactPair(i);
SHCollisionEvent newCollisionEvent = GenerateCollisionEvent(contactPair); const SHCollisionEvent NEW_EVENT = GenerateCollisionEvent(CONTACT_PAIR);
// Find contact pair in container UpdateEventContainers(NEW_EVENT, collisionInfo);
auto existingEvent = std::ranges::find_if(collisionInfo.begin(), collisionInfo.end(), [&](const SHCollisionEvent& e)
{
const bool ENTITY_MATCH = e.value[0] == newCollisionEvent.value[0];
const bool COLLIDERS_MATCH = e.value[1] == newCollisionEvent.value[1];
return ENTITY_MATCH && COLLIDERS_MATCH;
});
if (existingEvent == collisionInfo.end())
{
// Add new event
collisionInfo.emplace_back(newCollisionEvent);
}
else
{
existingEvent->collisionState = newCollisionEvent.collisionState;
}
} }
} }
@ -376,26 +374,10 @@ namespace SHADE
{ {
for (uint32_t i = 0; i < callbackData.getNbOverlappingPairs(); ++i) for (uint32_t i = 0; i < callbackData.getNbOverlappingPairs(); ++i)
{ {
auto contactPair = callbackData.getOverlappingPair(i); const auto& OVERLAP_PAIR = callbackData.getOverlappingPair(i);
SHCollisionEvent newTriggerEvent = GenerateCollisionEvent(contactPair); const SHCollisionEvent NEW_EVENT = GenerateCollisionEvent(OVERLAP_PAIR);
// Find contact pair in container UpdateEventContainers(NEW_EVENT, triggerInfo);
auto existingEvent = std::ranges::find_if(collisionInfo.begin(), collisionInfo.end(), [&](const SHCollisionEvent& e)
{
const bool ENTITY_MATCH = e.value[0] == newTriggerEvent.value[0];
const bool COLLIDERS_MATCH = e.value[1] == newTriggerEvent.value[1];
return ENTITY_MATCH && COLLIDERS_MATCH;
});
if (existingEvent == collisionInfo.end())
{
// Add new event
triggerInfo.emplace_back(newTriggerEvent);
}
else
{
existingEvent->collisionState = newTriggerEvent.collisionState;
}
} }
} }
@ -432,11 +414,11 @@ namespace SHADE
map.erase(entityID); map.erase(entityID);
} }
void SHPhysicsSystem::SyncActiveStates(SHPhysicsObject* physicsObject, bool componentActive) noexcept void SHPhysicsSystem::SyncActiveStates(SHPhysicsObject& physicsObject, bool componentActive) noexcept
{ {
const bool RP3D_ACTIVE = physicsObject->rp3dBody->isActive(); const bool RP3D_ACTIVE = physicsObject.rp3dBody->isActive();
if (RP3D_ACTIVE != componentActive) if (RP3D_ACTIVE != componentActive)
physicsObject->rp3dBody->setIsActive(componentActive); physicsObject.rp3dBody->setIsActive(componentActive);
} }
void SHPhysicsSystem::SyncTransforms() noexcept void SHPhysicsSystem::SyncTransforms() noexcept
@ -491,155 +473,54 @@ namespace SHADE
} }
// Convert RP3D Transform to SHADE // Convert RP3D Transform to SHADE
auto* transformComponent = SHComponentManager::GetComponent<SHTransformComponent>(entityID); auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (transformComponent != nullptr)
{
transformComponent->SetWorldPosition(rp3dPos); transformComponent->SetWorldPosition(rp3dPos);
transformComponent->SetWorldOrientation(rp3dRot); transformComponent->SetWorldOrientation(rp3dRot);
}
// Cache transforms // Cache transforms
physicsObject.prevTransform = CURRENT_TF; physicsObject.prevTransform = CURRENT_TF;
} }
} }
void SHPhysicsSystem::UpdateEventContainers(const SHCollisionEvent& collisionEvent, CollisionEvents& container) noexcept
{
const auto IT = std::ranges::find_if(container.begin(), container.end(), [&](const SHCollisionEvent& e)
{
const bool ENTITY_MATCH = e.value[0] == collisionEvent.value[0];
const bool COLLIDERS_MATCH = e.value[1] == collisionEvent.value[1];
return ENTITY_MATCH && COLLIDERS_MATCH;
});
if (IT == container.end())
container.emplace_back(collisionEvent);
else
IT->collisionState = collisionEvent.collisionState;
}
void SHPhysicsSystem::ClearInvalidCollisions() noexcept void SHPhysicsSystem::ClearInvalidCollisions() noexcept
{ {
for (auto collisionInfoIter = collisionInfo.begin(); collisionInfoIter != collisionInfo.end();) static const auto CLEAR = [](CollisionEvents& container)
{ {
if (collisionInfoIter->GetCollisionState() == SHCollisionEvent::State::EXIT for (auto eventIter = container.begin(); eventIter != container.end();)
|| collisionInfoIter->GetCollisionState() == SHCollisionEvent::State::INVALID)
{ {
collisionInfoIter = collisionInfo.erase(collisionInfoIter); const bool CLEAR_EVENT = eventIter->GetCollisionState() == SHCollisionEvent::State::EXIT
} || eventIter->GetCollisionState() == SHCollisionEvent::State::INVALID;
if (CLEAR_EVENT)
eventIter = container.erase(eventIter);
else else
{ ++eventIter;
++collisionInfoIter;
} }
}
for (auto triggerInfoIter = triggerInfo.begin(); triggerInfoIter != triggerInfo.end();)
{
if (triggerInfoIter->GetCollisionState() == SHCollisionEvent::State::EXIT
|| triggerInfoIter->GetCollisionState() == SHCollisionEvent::State::INVALID)
{
triggerInfoIter = triggerInfo.erase(triggerInfoIter);
}
else
{
++triggerInfoIter;
}
}
}
SHCollisionEvent SHPhysicsSystem::GenerateCollisionEvent(const rp3d::CollisionCallback::ContactPair& cp) noexcept
{
static const auto MATCH_COLLIDER = [](const SHPhysicsObject& physicsObject, const rp3d::Entity colliderID)->uint32_t
{
for (uint32_t i = 0; i < physicsObject.rp3dBody->getNbColliders(); ++i)
{
const auto* collider = physicsObject.rp3dBody->getCollider(i);
if (collider->getEntity() == colliderID)
return i;
}
return std::numeric_limits<uint32_t>::max();
}; };
SHCollisionEvent cInfo; CLEAR(collisionInfo);
// Update collision state CLEAR(triggerInfo);
cInfo.collisionState = static_cast<SHCollisionEvent::State>(cp.getEventType());
// Match body and collider for collision event
const rp3d::Entity body1 = cp.getBody1()->getEntity();
const rp3d::Entity body2 = cp.getBody2()->getEntity();
const rp3d::Entity collider1 = cp.getCollider1()->getEntity();
const rp3d::Entity collider2 = cp.getCollider2()->getEntity();
// Find and match both ids
bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : map)
{
// Match body 1
if (matched[SHCollisionEvent::ENTITY_A] == false && physicsObject.rp3dBody->getEntity() == body1)
{
cInfo.ids[SHCollisionEvent::ENTITY_A] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_A] = MATCH_COLLIDER(physicsObject, collider1);
matched[SHCollisionEvent::ENTITY_A] = true;
} }
// Match body 2
if (matched[SHCollisionEvent::ENTITY_B] == false && physicsObject.rp3dBody->getEntity() == body2)
{
cInfo.ids[SHCollisionEvent::ENTITY_B] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_B] = MATCH_COLLIDER(physicsObject, collider2);
matched[SHCollisionEvent::ENTITY_B] = true;
}
if (matched[SHCollisionEvent::ENTITY_A] == true && matched[SHCollisionEvent::ENTITY_B] == true)
return cInfo;
}
return cInfo;
}
SHCollisionEvent SHPhysicsSystem::GenerateCollisionEvent(const rp3d::OverlapCallback::OverlapPair& cp) noexcept
{
static const auto MATCH_COLLIDER = [](const SHPhysicsObject& physicsObject, const rp3d::Entity colliderID)->uint32_t
{
for (uint32_t i = 0; i < physicsObject.rp3dBody->getNbColliders(); ++i)
{
const auto* collider = physicsObject.rp3dBody->getCollider(i);
if (collider->getEntity() == colliderID)
return i;
}
return std::numeric_limits<uint32_t>::max();
};
SHCollisionEvent cInfo;
// Match body and collider for collision event
const rp3d::Entity body1 = cp.getBody1()->getEntity();
const rp3d::Entity body2 = cp.getBody2()->getEntity();
const rp3d::Entity collider1 = cp.getCollider1()->getEntity();
const rp3d::Entity collider2 = cp.getCollider2()->getEntity();
// Find and match both ids
bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : map)
{
// Match body 1
if (matched[SHCollisionEvent::ENTITY_A] == false && physicsObject.rp3dBody->getEntity() == body1)
{
cInfo.ids[SHCollisionEvent::ENTITY_A] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_A] = MATCH_COLLIDER(physicsObject, collider1);
matched[SHCollisionEvent::ENTITY_A] = true;
}
// Match body 2
if (matched[SHCollisionEvent::ENTITY_B] == false && physicsObject.rp3dBody->getEntity() == body2)
{
cInfo.ids[SHCollisionEvent::ENTITY_B] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_B] = MATCH_COLLIDER(physicsObject, collider2);
matched[SHCollisionEvent::ENTITY_B] = true;
}
if (matched[SHCollisionEvent::ENTITY_A] == true && matched[SHCollisionEvent::ENTITY_B] == true)
return cInfo;
}
// Update collision state
cInfo.collisionState = static_cast<SHCollisionEvent::State>(cp.getEventType());
return cInfo;
}
SHEventHandle SHPhysicsSystem::AddPhysicsComponent(SHEventPtr addComponentEvent) SHEventHandle SHPhysicsSystem::AddPhysicsComponent(SHEventPtr addComponentEvent)
{ {
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(addComponentEvent.get()); const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(addComponentEvent.get());
@ -728,6 +609,9 @@ namespace SHADE
const EntityID ENTITY_ID = EVENT_DATA->data->eid; const EntityID ENTITY_ID = EVENT_DATA->data->eid;
auto* physicsObject = GetPhysicsObject(ENTITY_ID); auto* physicsObject = GetPhysicsObject(ENTITY_ID);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ENTITY_ID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
SHASSERT(physicsObject != nullptr, "Physics object has been lost from the world!") SHASSERT(physicsObject != nullptr, "Physics object has been lost from the world!")
if (REMOVED_ID == RIGID_BODY_ID) if (REMOVED_ID == RIGID_BODY_ID)
@ -735,7 +619,6 @@ namespace SHADE
world->destroyRigidBody(reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody)); world->destroyRigidBody(reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody));
physicsObject->rp3dBody = nullptr; physicsObject->rp3dBody = nullptr;
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
if (colliderComponent != nullptr) if (colliderComponent != nullptr)
{ {
// Preserve colliders as a collision body // Preserve colliders as a collision body
@ -766,6 +649,10 @@ namespace SHADE
auto* collider = physicsObject->rp3dBody->getCollider(i); auto* collider = physicsObject->rp3dBody->getCollider(i);
physicsObject->rp3dBody->removeCollider(collider); physicsObject->rp3dBody->removeCollider(collider);
} }
// Check for a rigidbody component
if (rigidBodyComponent == nullptr)
physicsObject->rp3dBody = nullptr;
} }
if (physicsObject->rp3dBody == nullptr) if (physicsObject->rp3dBody == nullptr)

View File

@ -28,6 +28,12 @@
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/
/* Concepts */
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -176,22 +182,24 @@ namespace SHADE
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHPhysicsObject* EnsurePhysicsObject (EntityID entityID) noexcept; SHPhysicsObject* EnsurePhysicsObject (EntityID entityID) noexcept;
SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept; SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept;
void DestroyPhysicsObject (EntityID entityID) noexcept; void DestroyPhysicsObject (EntityID entityID) noexcept;
void SyncActiveStates (SHPhysicsObject* physicsObject, bool componentActive) noexcept; static void SyncActiveStates (SHPhysicsObject& physicsObject, bool componentActive) noexcept;
void SyncTransforms () noexcept; void SyncTransforms () noexcept;
void ClearInvalidCollisions () noexcept;
SHCollisionEvent GenerateCollisionEvent (const rp3d::CollisionCallback::ContactPair& cp) noexcept; static void UpdateEventContainers (const SHCollisionEvent& collisionEvent, CollisionEvents& container) noexcept;
SHCollisionEvent GenerateCollisionEvent (const rp3d::OverlapCallback::OverlapPair& cp) noexcept; void ClearInvalidCollisions () noexcept;
SHEventHandle AddPhysicsComponent (SHEventPtr addComponentEvent); SHEventHandle AddPhysicsComponent (SHEventPtr addComponentEvent);
SHEventHandle RemovePhysicsComponent (SHEventPtr removeComponentEvent); SHEventHandle RemovePhysicsComponent (SHEventPtr removeComponentEvent);
template <typename RP3DCollisionPair, typename = std::enable_if_t
<std::is_same_v<RP3DCollisionPair, rp3d::CollisionCallback::ContactPair>
|| std::is_same_v<RP3DCollisionPair, rp3d::OverlapCallback::OverlapPair>>>
SHCollisionEvent GenerateCollisionEvent (const RP3DCollisionPair& cp) noexcept;
}; };
} // namespace SHADE } // namespace SHADE
#include "SHPhysicsSystem.hpp"

View File

@ -0,0 +1,84 @@
/****************************************************************************************
* \file SHPhysicsSystem.hpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for templated functions the Physics System
*
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited.
****************************************************************************************/
#pragma once
#include <type_traits>
// Primary Header
#include "SHPhysicsSystem.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
template <typename RP3DCollisionPair, typename Condition>
SHCollisionEvent SHPhysicsSystem::GenerateCollisionEvent(const RP3DCollisionPair& cp) noexcept
{
static const auto MATCH_COLLIDER = []
(
const SHPhysicsObject& physicsObject
, const rp3d::Entity colliderID
)->uint32_t
{
for (uint32_t i = 0; i < physicsObject.rp3dBody->getNbColliders(); ++i)
{
const auto* collider = physicsObject.rp3dBody->getCollider(i);
if (collider->getEntity() == colliderID)
return i;
}
return std::numeric_limits<uint32_t>::max();
};
SHCollisionEvent cInfo;
// Match body and collider for collision event
const rp3d::Entity body1 = cp.getBody1()->getEntity();
const rp3d::Entity body2 = cp.getBody2()->getEntity();
const rp3d::Entity collider1 = cp.getCollider1()->getEntity();
const rp3d::Entity collider2 = cp.getCollider2()->getEntity();
// Find and match both ids
bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : map)
{
// Match body 1
if (matched[SHCollisionEvent::ENTITY_A] == false && physicsObject.rp3dBody->getEntity() == body1)
{
cInfo.ids[SHCollisionEvent::ENTITY_A] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_A] = MATCH_COLLIDER(physicsObject, collider1);
matched[SHCollisionEvent::ENTITY_A] = true;
}
// Match body 2
if (matched[SHCollisionEvent::ENTITY_B] == false && physicsObject.rp3dBody->getEntity() == body2)
{
cInfo.ids[SHCollisionEvent::ENTITY_B] = entityID;
cInfo.ids[SHCollisionEvent::COLLIDER_B] = MATCH_COLLIDER(physicsObject, collider2);
matched[SHCollisionEvent::ENTITY_B] = true;
}
if (matched[SHCollisionEvent::ENTITY_A] == true && matched[SHCollisionEvent::ENTITY_B] == true)
return cInfo;
}
// Update collision state
cInfo.collisionState = static_cast<SHCollisionEvent::State>(cp.getEventType());
return cInfo;
}
} // namespace SHADE