.....small restructure....

This commit is contained in:
Diren D Bharwani 2022-11-12 16:56:58 +08:00
parent c40992b48c
commit 45e549f9f1
42 changed files with 2259 additions and 1486 deletions

View File

@ -30,8 +30,8 @@
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" #include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
#include "Input/SHInputManager.h" #include "Input/SHInputManager.h"
#include "Math/Transform/SHTransformSystem.h" #include "Math/Transform/SHTransformSystem.h"
#include "Physics/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
#include "Physics/SHPhysicsDebugDrawSystem.h" #include "Physics/System/SHPhysicsDebugDrawSystem.h"
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
// Components // Components

View File

@ -10,8 +10,8 @@
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Assets/SHAssetManager.h" #include "Assets/SHAssetManager.h"

View File

@ -10,8 +10,8 @@
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Assets/SHAssetManager.h" #include "Assets/SHAssetManager.h"

View File

@ -15,7 +15,7 @@
#include "Editor/SHEditorWidgets.hpp" #include "Editor/SHEditorWidgets.hpp"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Reflection/SHReflectionMetadata.h" #include "Reflection/SHReflectionMetadata.h"
#include "Resource/SHResourceManager.h" #include "Resource/SHResourceManager.h"

View File

@ -14,8 +14,8 @@
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Camera/SHCameraComponent.h" #include "Camera/SHCameraComponent.h"
#include "Camera/SHCameraArmComponent.h" #include "Camera/SHCameraArmComponent.h"
#include "SHEditorComponentView.h" #include "SHEditorComponentView.h"

View File

@ -1,7 +1,7 @@
/**************************************************************************************** /****************************************************************************************
* \file SHPhysicsUtils.cpp * \file SHCollisionInfo.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520 * \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for some Physics Utilities * \brief Implementation for Collision Info.
* *
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent * disclosure of this file or its contents without the prior written consent
@ -11,7 +11,7 @@
#include <SHpch.h> #include <SHpch.h>
// Primary Header // Primary Header
#include "SHPhysicsUtils.h" #include "SHCollisionInfo.h"
namespace SHADE namespace SHADE
{ {
@ -19,7 +19,7 @@ namespace SHADE
/* Constructors & Destructor Definitions */ /* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHCollisionEvent::SHCollisionEvent() noexcept SHCollisionInfo::SHCollisionInfo() noexcept
: collisionState { State::INVALID } : collisionState { State::INVALID }
{ {
ids[ENTITY_A] = MAX_EID; ids[ENTITY_A] = MAX_EID;
@ -28,7 +28,7 @@ namespace SHADE
ids[COLLIDER_B] = std::numeric_limits<uint32_t>::max(); ids[COLLIDER_B] = std::numeric_limits<uint32_t>::max();
} }
SHCollisionEvent::SHCollisionEvent(EntityID entityA, EntityID entityB) noexcept SHCollisionInfo::SHCollisionInfo(EntityID entityA, EntityID entityB) noexcept
: collisionState { State::INVALID } : collisionState { State::INVALID }
{ {
ids[ENTITY_A] = entityA; ids[ENTITY_A] = entityA;
@ -41,12 +41,12 @@ namespace SHADE
/* Operator Overload Definitions */ /* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
bool SHCollisionEvent::operator==(const SHCollisionEvent& rhs) const noexcept bool SHCollisionInfo::operator==(const SHCollisionInfo& rhs) const noexcept
{ {
return value[0] == rhs.value[0] && value[1] == rhs.value[1]; return value[0] == rhs.value[0] && value[1] == rhs.value[1];
} }
bool SHCollisionEvent::operator!=(const SHCollisionEvent& rhs) const noexcept bool SHCollisionInfo::operator!=(const SHCollisionInfo& rhs) const noexcept
{ {
return value[0] != rhs.value[0] || value[1] != rhs.value[1]; return value[0] != rhs.value[0] || value[1] != rhs.value[1];
} }
@ -55,37 +55,37 @@ namespace SHADE
/* Getter Function Definitions */ /* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
EntityID SHCollisionEvent::GetEntityA() const noexcept EntityID SHCollisionInfo::GetEntityA() const noexcept
{ {
return ids[ENTITY_A]; return ids[ENTITY_A];
} }
EntityID SHCollisionEvent::GetEntityB() const noexcept EntityID SHCollisionInfo::GetEntityB() const noexcept
{ {
return ids[ENTITY_B]; return ids[ENTITY_B];
} }
const SHRigidBodyComponent* SHCollisionEvent::GetRigidBodyA() const noexcept const SHRigidBodyComponent* SHCollisionInfo::GetRigidBodyA() const noexcept
{ {
return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_A]); return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_A]);
} }
const SHRigidBodyComponent* SHCollisionEvent::GetRigidBodyB() const noexcept const SHRigidBodyComponent* SHCollisionInfo::GetRigidBodyB() const noexcept
{ {
return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_B]); return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_B]);
} }
const SHCollisionShape* SHCollisionEvent::GetColliderA() const noexcept const SHCollisionShape* SHCollisionInfo::GetColliderA() const noexcept
{ {
return &SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_A])->GetCollisionShape(ids[COLLIDER_A]); return &SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_A])->GetCollisionShape(ids[COLLIDER_A]);
} }
const SHCollisionShape* SHCollisionEvent::GetColliderB() const noexcept const SHCollisionShape* SHCollisionInfo::GetColliderB() const noexcept
{ {
return &SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_B])->GetCollisionShape(ids[COLLIDER_B]); return &SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_B])->GetCollisionShape(ids[COLLIDER_B]);
} }
SHCollisionEvent::State SHCollisionEvent::GetCollisionState() const noexcept SHCollisionInfo::State SHCollisionInfo::GetCollisionState() const noexcept
{ {
return collisionState; return collisionState;
} }

View File

@ -1,7 +1,7 @@
/**************************************************************************************** /****************************************************************************************
* \file SHPhysicsUtils.h * \file SHCollisionInfo.h
* \author Diren D Bharwani, diren.dbharwani, 390002520 * \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for some Physics Utilities * \brief Interface for Collision Information for Collision & Triggers.
* *
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or * \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
* disclosure of this file or its contents without the prior written consent * disclosure of this file or its contents without the prior written consent
@ -11,8 +11,8 @@
#pragma once #pragma once
// Project Headers // Project Headers
#include "Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
namespace SHADE namespace SHADE
@ -21,27 +21,14 @@ namespace SHADE
/* Type Definitions */ /* Type Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
struct SHPhysicsColliderAddedEvent class SH_API SHCollisionInfo
{
EntityID entityID;
SHCollisionShape::Type colliderType;
int colliderIndex;
};
struct SHPhysicsColliderRemovedEvent
{
EntityID entityID;
int colliderIndex;
};
class SH_API SHCollisionEvent
{ {
private: private:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Friends */ /* Friends */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem; friend class SHCollisionListener;
public: public:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -62,23 +49,23 @@ namespace SHADE
/* Constructors & Destructor */ /* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHCollisionEvent () noexcept; SHCollisionInfo () noexcept;
SHCollisionEvent (EntityID entityA, EntityID entityB) noexcept; SHCollisionInfo (EntityID entityA, EntityID entityB) noexcept;
SHCollisionEvent (const SHCollisionEvent& rhs) = default; SHCollisionInfo (const SHCollisionInfo& rhs) = default;
SHCollisionEvent (SHCollisionEvent&& rhs) = default; SHCollisionInfo (SHCollisionInfo&& rhs) = default;
~SHCollisionEvent () = default; ~SHCollisionInfo () = default;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Operator Overloads */ /* Operator Overloads */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
bool operator== (const SHCollisionEvent& rhs) const noexcept; bool operator== (const SHCollisionInfo& rhs) const noexcept;
bool operator!= (const SHCollisionEvent& rhs) const noexcept; bool operator!= (const SHCollisionInfo& rhs) const noexcept;
SHCollisionEvent& operator= (const SHCollisionEvent& rhs) = default; SHCollisionInfo& operator= (const SHCollisionInfo& rhs) = default;
SHCollisionEvent& operator= (SHCollisionEvent&& rhs) = default; SHCollisionInfo& operator= (SHCollisionInfo&& rhs) = default;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */
@ -88,8 +75,8 @@ namespace SHADE
[[nodiscard]] EntityID GetEntityB () const noexcept; [[nodiscard]] EntityID GetEntityB () const noexcept;
[[nodiscard]] const SHRigidBodyComponent* GetRigidBodyA () const noexcept; [[nodiscard]] const SHRigidBodyComponent* GetRigidBodyA () const noexcept;
[[nodiscard]] const SHRigidBodyComponent* GetRigidBodyB () const noexcept; [[nodiscard]] const SHRigidBodyComponent* GetRigidBodyB () const noexcept;
[[nodiscard]] const SHCollisionShape* GetColliderA () const noexcept; [[nodiscard]] const SHCollisionShape* GetColliderA () const noexcept;
[[nodiscard]] const SHCollisionShape* GetColliderB () const noexcept; [[nodiscard]] const SHCollisionShape* GetColliderB () const noexcept;
[[nodiscard]] State GetCollisionState () const noexcept; [[nodiscard]] State GetCollisionState () const noexcept;
private: private:
@ -112,5 +99,4 @@ namespace SHADE
State collisionState; State collisionState;
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -0,0 +1,236 @@
/****************************************************************************************
* \file SHCollisionListener.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Collision Listener.
*
* \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.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHCollisionListener.h"
// Project Headers
#include "Physics/PhysicsObject/SHPhysicsObject.h"
#include "Physics/System/SHPhysicsSystem.h"
/*-------------------------------------------------------------------------------------*/
/* Local Helper Functions */
/*-------------------------------------------------------------------------------------*/
uint32_t matchColliders(const SHADE::SHPhysicsObject&physicsObject, const rp3d::Entity colliderID)
{
for (uint32_t i = 0; i < physicsObject.GetCollisionBody()->getNbColliders(); ++i)
{
const auto* collider = physicsObject.GetCollisionBody()->getCollider(i);
if (collider->getEntity() == colliderID)
return i;
}
return std::numeric_limits<uint32_t>::max();
}
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHCollisionListener::SHCollisionListener() noexcept
: system { nullptr }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
const std::vector<SHCollisionInfo>& SHCollisionListener::GetCollisionInfoContainer() const noexcept
{
return collisionInfoContainer;
}
const std::vector<SHCollisionInfo>& SHCollisionListener::GetTriggerInfoContainer() const noexcept
{
return triggerInfoContainer;
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionListener::BindToSystem(SHPhysicsSystem* physicsSystem) noexcept
{
system = physicsSystem;
}
void SHCollisionListener::BindToWorld(rp3d::PhysicsWorld* world) noexcept
{
if (!world)
return;
world->setEventListener(this);
}
void SHCollisionListener::CleanContainers() noexcept
{
static const auto CLEAR = [](std::vector<SHCollisionInfo>& container)
{
for (auto eventIter = container.begin(); eventIter != container.end();)
{
const bool CLEAR_EVENT = eventIter->GetCollisionState() == SHCollisionInfo::State::EXIT
|| eventIter->GetCollisionState() == SHCollisionInfo::State::INVALID;
if (CLEAR_EVENT)
eventIter = container.erase(eventIter);
else
++eventIter;
}
};
CLEAR(collisionInfoContainer);
CLEAR(triggerInfoContainer);
}
void SHCollisionListener::ClearContainers() noexcept
{
collisionInfoContainer.clear();
triggerInfoContainer.clear();
}
void SHCollisionListener::onContact(const rp3d::CollisionCallback::CallbackData& callbackData)
{
for (uint32_t i = 0; i < callbackData.getNbContactPairs(); ++i)
{
const auto CONTACT_PAIR = callbackData.getContactPair(i);
const SHCollisionInfo NEW_INFO = generateCollisionInfo(CONTACT_PAIR);
updateInfoContainers(NEW_INFO, collisionInfoContainer);
}
}
void SHCollisionListener::onTrigger(const rp3d::OverlapCallback::CallbackData& callbackData)
{
for (uint32_t i = 0; i < callbackData.getNbOverlappingPairs(); ++i)
{
const auto OVERLAP_PAIR = callbackData.getOverlappingPair(i);
const SHCollisionInfo NEW_INFO = generateTriggerInfo(OVERLAP_PAIR);
updateInfoContainers(NEW_INFO, triggerInfoContainer);
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionListener::updateInfoContainers(const SHCollisionInfo& collisionEvent, std::vector<SHCollisionInfo>& container) noexcept
{
const auto IT = std::ranges::find_if(container.begin(), container.end(), [&](const SHCollisionInfo& info)
{
const bool ENTITY_MATCH = (info.ids[0] == collisionEvent.ids[0] && info.ids[1] == collisionEvent.ids[1])
|| (info.ids[0] == collisionEvent.ids[1] && info.ids[1] == collisionEvent.ids[0]);
const bool COLLIDERS_MATCH = (info.ids[2] == collisionEvent.ids[2] && info.ids[3] == collisionEvent.ids[3])
|| (info.ids[2] == collisionEvent.ids[3] && info.ids[3] == collisionEvent.ids[2]);
return ENTITY_MATCH && COLLIDERS_MATCH;
});
if (IT == container.end())
container.emplace_back(collisionEvent);
else
IT->collisionState = collisionEvent.collisionState;
}
SHCollisionInfo SHCollisionListener::generateCollisionInfo(const rp3d::CollisionCallback::ContactPair& cp) const noexcept
{
SHCollisionInfo cInfo;
// Update collision state
cInfo.collisionState = static_cast<SHCollisionInfo::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] : system->GetPhysicsObjects())
{
// Match body 1
if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.GetCollisionBody()->getEntity() == body1)
{
cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1);
matched[SHCollisionInfo::ENTITY_A] = true;
}
// Match body 2
if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.GetCollisionBody()->getEntity() == body2)
{
cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2);
matched[SHCollisionInfo::ENTITY_B] = true;
}
if (matched[SHCollisionInfo::ENTITY_A] == true && matched[SHCollisionInfo::ENTITY_B] == true)
return cInfo;
}
return cInfo;
}
SHCollisionInfo SHCollisionListener::generateTriggerInfo(const rp3d::OverlapCallback::OverlapPair& cp) const noexcept
{
SHCollisionInfo cInfo;
// Update collision state
cInfo.collisionState = static_cast<SHCollisionInfo::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] : system->GetPhysicsObjects())
{
// Match body 1
if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.GetCollisionBody()->getEntity() == body1)
{
cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1);
matched[SHCollisionInfo::ENTITY_A] = true;
}
// Match body 2
if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.GetCollisionBody()->getEntity() == body2)
{
cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2);
matched[SHCollisionInfo::ENTITY_B] = true;
}
if (matched[SHCollisionInfo::ENTITY_A] == true && matched[SHCollisionInfo::ENTITY_B] == true)
return cInfo;
}
return cInfo;
}
} // namespace SHADE

View File

@ -0,0 +1,81 @@
/****************************************************************************************
* \file SHCollisionListener.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Collision Listener.
*
* \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
// External Dependencies
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "SH_API.h"
#include "SHCollisionInfo.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHPhysicsSystem;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHCollisionListener final : public rp3d::EventListener
{
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHCollisionListener() noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] const std::vector<SHCollisionInfo>& GetCollisionInfoContainer () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetTriggerInfoContainer () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void BindToSystem (SHPhysicsSystem* physicsSystem) noexcept;
void BindToWorld (rp3d::PhysicsWorld* world) noexcept;
void CleanContainers () noexcept;
void ClearContainers () noexcept;
void onContact (const rp3d::CollisionCallback::CallbackData& callbackData) override;
void onTrigger (const rp3d::OverlapCallback::CallbackData& callbackData) override;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsSystem* system;
std::vector<SHCollisionInfo> collisionInfoContainer;
std::vector<SHCollisionInfo> triggerInfoContainer;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
static void updateInfoContainers (const SHCollisionInfo& collisionEvent, std::vector<SHCollisionInfo>& container) noexcept;
SHCollisionInfo generateCollisionInfo (const rp3d::CollisionCallback::ContactPair& cp) const noexcept;
SHCollisionInfo generateTriggerInfo (const rp3d::OverlapCallback::OverlapPair& cp) const noexcept;
};
} // namespace SHADE

View File

@ -16,7 +16,7 @@
// Project Headers // Project Headers
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Math/SHMathHelpers.h" #include "Math/SHMathHelpers.h"
#include "Physics/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
namespace SHADE namespace SHADE
{ {
@ -72,7 +72,14 @@ namespace SHADE
void SHColliderComponent::OnCreate() void SHColliderComponent::OnCreate()
{ {
system = SHSystemManager::GetSystem<SHPhysicsSystem>(); auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!physicsSystem)
{
SHLOG_ERROR("Physics System does not exist to link with Physics Components!")
return;
}
system = physicsSystem;
} }
void SHColliderComponent::OnDestroy() void SHColliderComponent::OnDestroy()
@ -132,9 +139,10 @@ namespace SHADE
collider.SetBoundingBox(halfExtents); collider.SetBoundingBox(halfExtents);
// Notify Physics System // Notify Physics System
system->AddCollisionShape(GetEID(), &collider); const int NEW_SHAPE_INDEX = static_cast<int>(collisionShapes.size()) - 1;
return static_cast<int>(collisionShapes.size()) - 1; system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX);
return NEW_SHAPE_INDEX;
} }
int SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept int SHColliderComponent::AddBoundingSphere(float radius, const SHVec3& posOffset) noexcept
@ -154,9 +162,10 @@ namespace SHADE
collider.SetBoundingSphere(radius); collider.SetBoundingSphere(radius);
// Notify Physics System // Notify Physics System
system->AddCollisionShape(GetEID(), &collider); const int NEW_SHAPE_INDEX = static_cast<int>(collisionShapes.size()) - 1;
return static_cast<int>(collisionShapes.size()) - 1; system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX);
return NEW_SHAPE_INDEX;
} }
void SHColliderComponent::RemoveCollider(int index) void SHColliderComponent::RemoveCollider(int index)

View File

@ -14,9 +14,9 @@
// Project Headers // Project Headers
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "Physics/SHCollisionShape.h"
#include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingBox.h"
#include "Math/Geometry/SHBoundingSphere.h" #include "Math/Geometry/SHBoundingSphere.h"
#include "SHCollisionShape.h"
//namespace SHADE //namespace SHADE
//{ //{

View File

@ -16,8 +16,8 @@
#include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingBox.h"
#include "Math/Geometry/SHBoundingSphere.h" #include "Math/Geometry/SHBoundingSphere.h"
#include "Math/SHMathHelpers.h" #include "Math/SHMathHelpers.h"
#include "Physics/Components/SHColliderComponent.h"
#include "Reflection/SHReflectionMetadata.h" #include "Reflection/SHReflectionMetadata.h"
#include "SHColliderComponent.h"
namespace SHADE namespace SHADE
{ {

View File

@ -19,7 +19,7 @@
// Project Headers // Project Headers
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Math/SHMathHelpers.h" #include "Math/SHMathHelpers.h"
#include "Physics/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
namespace SHADE namespace SHADE
{ {
@ -30,8 +30,17 @@ namespace SHADE
SHRigidBodyComponent::SHRigidBodyComponent() noexcept SHRigidBodyComponent::SHRigidBodyComponent() noexcept
: type { Type::DYNAMIC } : type { Type::DYNAMIC }
, interpolate { true } , interpolate { true }
, rp3dBody { nullptr } , flags { 0 }
{} , dirtyFlags { std::numeric_limits<uint16_t>::max() }
, mass { 1.0f }
, drag { 0.01f }
, angularDrag { 0.01f }
, system { nullptr }
{
// Initialise default flags
flags |= 1U << 0; // Gravity set to true
flags |= 1U << 1; // Sleeping allowed
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */ /* Getter Function Definitions */
@ -39,24 +48,14 @@ namespace SHADE
bool SHRigidBodyComponent::IsGravityEnabled() const noexcept bool SHRigidBodyComponent::IsGravityEnabled() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 0;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
return rp3dBody->isGravityEnabled();
} }
bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 1;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
return rp3dBody->isAllowedToSleep();
} }
bool SHRigidBodyComponent::IsInterpolating() const noexcept bool SHRigidBodyComponent::IsInterpolating() const noexcept
@ -71,151 +70,85 @@ namespace SHADE
float SHRigidBodyComponent::GetMass() const noexcept float SHRigidBodyComponent::GetMass() const noexcept
{ {
if (rp3dBody == nullptr) return mass;
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return 0.0f;
}
return rp3dBody->getMass();
} }
float SHRigidBodyComponent::GetDrag() const noexcept float SHRigidBodyComponent::GetDrag() const noexcept
{ {
if (rp3dBody == nullptr) return drag;
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return 0.0f;
}
return rp3dBody->getLinearDamping();
} }
float SHRigidBodyComponent::GetAngularDrag() const noexcept float SHRigidBodyComponent::GetAngularDrag() const noexcept
{ {
if (rp3dBody == nullptr) return angularDrag;
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return 0.0f;
}
return rp3dBody->getAngularDamping();
} }
bool SHRigidBodyComponent::GetFreezePositionX() const noexcept bool SHRigidBodyComponent::GetFreezePositionX() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 2;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& LINEAR_CONSTRAINTS = rp3dBody->getLinearLockAxisFactor();
return SHMath::CompareFloat(LINEAR_CONSTRAINTS.x, 0.0f);
} }
bool SHRigidBodyComponent::GetFreezePositionY() const noexcept bool SHRigidBodyComponent::GetFreezePositionY() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 3;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& LINEAR_CONSTRAINTS = rp3dBody->getLinearLockAxisFactor();
return SHMath::CompareFloat(LINEAR_CONSTRAINTS.y, 0.0f);
} }
bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 4;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& LINEAR_CONSTRAINTS = rp3dBody->getLinearLockAxisFactor();
return SHMath::CompareFloat(LINEAR_CONSTRAINTS.z, 0.0f);
} }
bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 5;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& ANGULAR_CONSTRAINTS = rp3dBody->getAngularLockAxisFactor();
return SHMath::CompareFloat(ANGULAR_CONSTRAINTS.x, 0.0f);
} }
bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 6;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& ANGULAR_CONSTRAINTS = rp3dBody->getAngularLockAxisFactor();
return SHMath::CompareFloat(ANGULAR_CONSTRAINTS.y, 0.0f);
} }
bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept
{ {
if (rp3dBody == nullptr) static constexpr int FLAG_POS = 7;
{ return flags & (1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& ANGULAR_CONSTRAINTS = rp3dBody->getAngularLockAxisFactor();
return SHMath::CompareFloat(ANGULAR_CONSTRAINTS.z, 0.0f);
} }
SHVec3 SHRigidBodyComponent::GetForce() const noexcept SHVec3 SHRigidBodyComponent::GetForce() const noexcept
{ {
if (rp3dBody == nullptr) if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
{ return physicsObject->GetRigidBody()->getForce();
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
return rp3dBody->getForce(); return SHVec3::Zero;
} }
SHVec3 SHRigidBodyComponent::GetTorque() const noexcept SHVec3 SHRigidBodyComponent::GetTorque() const noexcept
{ {
if (rp3dBody == nullptr) if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
{ return physicsObject->GetRigidBody()->getTorque();
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return SHVec3::Zero;
}
return rp3dBody->getTorque(); return SHVec3::Zero;
} }
SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept
{ {
if (rp3dBody == nullptr) if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
{ return physicsObject->GetRigidBody()->getLinearVelocity();
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return SHVec3::Zero;
}
return rp3dBody->getLinearVelocity(); return SHVec3::Zero;
} }
SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept
{ {
if (rp3dBody == nullptr) if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
{ return physicsObject->GetRigidBody()->getAngularVelocity();
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return SHVec3::Zero;
}
return rp3dBody->getAngularVelocity(); return SHVec3::Zero;
} }
const SHVec3& SHRigidBodyComponent::GetPosition() const noexcept const SHVec3& SHRigidBodyComponent::GetPosition() const noexcept
@ -239,18 +172,13 @@ namespace SHADE
void SHRigidBodyComponent::SetType(Type newType) noexcept void SHRigidBodyComponent::SetType(Type newType) noexcept
{ {
static constexpr int FLAG_POS = 8;
if (type == newType) if (type == newType)
return; return;
type = newType; type = newType;
dirtyFlags |= 1U << FLAG_POS;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setType(static_cast<rp3d::BodyType>(type));
} }
void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept
@ -263,13 +191,8 @@ namespace SHADE
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ enableGravity ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->enableGravity(enableGravity);
} }
void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept
@ -282,127 +205,92 @@ namespace SHADE
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ isAllowedToSleep ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setIsAllowedToSleep(isAllowedToSleep);
} }
void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept
{ {
static constexpr int FLAG_POS = 2;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ freezePositionX ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto linearConstraints = rp3dBody->getLinearLockAxisFactor();
linearConstraints.x = freezePositionX ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(linearConstraints);
} }
void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept
{ {
static constexpr int FLAG_POS = 3;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ freezePositionY ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto linearConstraints = rp3dBody->getLinearLockAxisFactor();
linearConstraints.y = freezePositionY ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(linearConstraints);
} }
void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept
{ {
static constexpr int FLAG_POS = 4;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ freezePositionZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto linearConstraints = rp3dBody->getLinearLockAxisFactor();
linearConstraints.z = freezePositionZ ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(linearConstraints);
} }
void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept
{ {
static constexpr int FLAG_POS = 5;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ freezeRotationX ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto angularConstraints = rp3dBody->getAngularLockAxisFactor();
angularConstraints.x = freezeRotationX ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(angularConstraints);
} }
void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept
{ {
static constexpr int FLAG_POS = 6;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ freezeRotationY ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto angularConstraints = rp3dBody->getAngularLockAxisFactor();
angularConstraints.y = freezeRotationY ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(angularConstraints);
} }
void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept
{ {
static constexpr int FLAG_POS = 7;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ freezeRotationZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto angularConstraints = rp3dBody->getAngularLockAxisFactor();
angularConstraints.z = freezeRotationZ ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(angularConstraints);
} }
void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept
@ -412,179 +300,127 @@ namespace SHADE
void SHRigidBodyComponent::SetMass(float newMass) noexcept void SHRigidBodyComponent::SetMass(float newMass) noexcept
{ {
static constexpr int FLAG_POS = 9;
if (type != Type::DYNAMIC) if (type != Type::DYNAMIC)
{ {
SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID()) SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ mass = newMass;
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setMass(newMass);
} }
void SHRigidBodyComponent::SetDrag(float newDrag) noexcept void SHRigidBodyComponent::SetDrag(float newDrag) noexcept
{ {
static constexpr int FLAG_POS = 10;
if (type != Type::DYNAMIC) if (type != Type::DYNAMIC)
{ {
SHLOG_WARNING("Cannot set drag of a non-dynamic object {}", GetEID()) SHLOG_WARNING("Cannot set drag of a non-dynamic object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ drag = newDrag;
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setLinearDamping(newDrag);
} }
void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept
{ {
static constexpr int FLAG_POS = 11;
if (type != Type::DYNAMIC) if (type != Type::DYNAMIC)
{ {
SHLOG_WARNING("Cannot set angular drag of a non-dynamic object {}", GetEID()) SHLOG_WARNING("Cannot set angular drag of a non-dynamic object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) dirtyFlags |= 1U << FLAG_POS;
{ angularDrag = newAngularDrag;
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setLinearDamping(newAngularDrag);
} }
void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept
{ {
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set linear velocity of a static object {}", GetEID()) SHLOG_WARNING("Cannot set linear velocity of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) auto* physicsObject = system->GetPhysicsObject(GetEID());
{ physicsObject->GetRigidBody()->setLinearVelocity(newLinearVelocity);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setLinearVelocity(newLinearVelocity);
} }
void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept
{ {
static constexpr int FLAG_POS = 13;
if (type == Type::STATIC) if (type == Type::STATIC)
{ {
SHLOG_WARNING("Cannot set angular velocity of a static object {}", GetEID()) SHLOG_WARNING("Cannot set angular velocity of a static object {}", GetEID())
return; return;
} }
if (rp3dBody == nullptr) auto* physicsObject = system->GetPhysicsObject(GetEID());
{ physicsObject->GetRigidBody()->setAngularVelocity(newAngularVelocity);
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setAngularVelocity(newAngularVelocity);
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */ /* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept void SHRigidBodyComponent::OnCreate()
{ {
if (rp3dBody == nullptr) auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!physicsSystem)
{ {
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID()) SHLOG_ERROR("Physics System does not exist to link with Physics Components!")
return; return;
} }
rp3dBody->applyWorldForceAtCenterOfMass(force); system = physicsSystem;
}
void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept
{
system->AddForce(GetEID(), force);
} }
void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept
{ {
if (rp3dBody == nullptr) system->AddForceAtLocalPos(GetEID(), force, localPos);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyWorldForceAtLocalPosition(force, localPos);
} }
void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept void SHRigidBodyComponent::AddForceAtWorldPos(const SHVec3& force, const SHVec3& worldPos) const noexcept
{ {
if (rp3dBody == nullptr) system->AddForceAtWorldPos(GetEID(), force, worldPos);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyWorldForceAtWorldPosition(force, worldPos);
} }
void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept
{ {
if (rp3dBody == nullptr) system->AddRelativeForce(GetEID(), relativeForce);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyLocalForceAtCenterOfMass(relativeForce);
} }
void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept void SHRigidBodyComponent::AddRelativeForceAtLocalPos(const SHVec3& relativeForce, const SHVec3& localPos) const noexcept
{ {
if (rp3dBody == nullptr) system->AddRelativeForceAtLocalPos(GetEID(), relativeForce, localPos);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyLocalForceAtLocalPosition(relativeForce, localPos);
} }
void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept void SHRigidBodyComponent::AddRelativeForceAtWorldPos(const SHVec3& relativeForce, const SHVec3& worldPos) const noexcept
{ {
if (rp3dBody == nullptr) system->AddRelativeForceAtWorldPos(GetEID(), relativeForce, worldPos);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyLocalForceAtWorldPosition(relativeForce, worldPos);
} }
void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept
{ {
if (rp3dBody == nullptr) system->AddTorque(GetEID(), torque);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyWorldTorque(torque);
} }
void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept
{ {
if (rp3dBody == nullptr) system->AddRelativeTorque(GetEID(), relativeTorque);
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->applyLocalTorque(relativeTorque);
} }
} // namespace SHADE } // namespace SHADE

View File

@ -17,16 +17,6 @@
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
#include "Math/SHQuaternion.h" #include "Math/SHQuaternion.h"
//namespace SHADE
//{
// class SHPhysicsSystem;
//}
namespace reactphysics3d
{
class RigidBody;
}
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -107,29 +97,31 @@ namespace SHADE
/* Setter Functions */ /* Setter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SetType (Type newType) noexcept; void SetType (Type newType) noexcept;
void SetGravityEnabled (bool enableGravity) noexcept; void SetGravityEnabled (bool enableGravity) noexcept;
void SetIsAllowedToSleep(bool isAllowedToSleep) noexcept; void SetIsAllowedToSleep (bool isAllowedToSleep) noexcept;
void SetFreezePositionX (bool freezePositionX) noexcept; void SetFreezePositionX (bool freezePositionX) noexcept;
void SetFreezePositionY (bool freezePositionY) noexcept; void SetFreezePositionY (bool freezePositionY) noexcept;
void SetFreezePositionZ (bool freezePositionZ) noexcept; void SetFreezePositionZ (bool freezePositionZ) noexcept;
void SetFreezeRotationX (bool freezeRotationX) noexcept; void SetFreezeRotationX (bool freezeRotationX) noexcept;
void SetFreezeRotationY (bool freezeRotationY) noexcept; void SetFreezeRotationY (bool freezeRotationY) noexcept;
void SetFreezeRotationZ (bool freezeRotationZ) noexcept; void SetFreezeRotationZ (bool freezeRotationZ) noexcept;
void SetInterpolate (bool allowInterpolation) noexcept; void SetInterpolate (bool allowInterpolation) noexcept;
void SetMass (float newMass) noexcept; void SetMass (float newMass) noexcept;
void SetDrag (float newDrag) noexcept; void SetDrag (float newDrag) noexcept;
void SetAngularDrag (float newAngularDrag) noexcept; void SetAngularDrag (float newAngularDrag) noexcept;
void SetLinearVelocity (const SHVec3& newLinearVelocity) noexcept; void SetLinearVelocity (const SHVec3& newLinearVelocity) noexcept;
void SetAngularVelocity (const SHVec3& newAngularVelocity) noexcept; void SetAngularVelocity (const SHVec3& newAngularVelocity) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void OnCreate () override;
void AddForce (const SHVec3& force) const noexcept; void AddForce (const SHVec3& force) const noexcept;
void AddForceAtLocalPos (const SHVec3& force, const SHVec3& localPos) const noexcept; void AddForceAtLocalPos (const SHVec3& force, const SHVec3& localPos) const noexcept;
void AddForceAtWorldPos (const SHVec3& force, const SHVec3& worldPos) const noexcept; void AddForceAtWorldPos (const SHVec3& force, const SHVec3& worldPos) const noexcept;
@ -147,15 +139,25 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
static constexpr size_t NUM_FLAGS = 8; static constexpr size_t NUM_FLAGS = 8;
static constexpr size_t NUM_DIRTY_FLAGS = 16; static constexpr size_t NUM_DIRTY_FLAGS = 12;
Type type; Type type;
bool interpolate;
reactphysics3d::RigidBody* rp3dBody; bool interpolate;
uint8_t flags; // aZ aY aX lZ lY lX slp g
uint16_t dirtyFlags; // 0 0 0 0 aD d m t aZ aY aX lZ lY lX slp g
SHVec3 position; float mass;
SHQuaternion orientation; float drag;
float angularDrag;
SHVec3 linearVelocity;
SHVec3 angularVelocity;
SHPhysicsSystem* system;
SHVec3 position;
SHQuaternion orientation;
RTTR_ENABLE() RTTR_ENABLE()
}; };

View File

@ -0,0 +1,361 @@
/****************************************************************************************
* \file SHPhysicsObject.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics Object.
*
* \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.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHPhysicsObject.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "ECS_Base/Managers/SHComponentManager.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept
: entityID { eid }
, factory { physicsFactory }
, world { physicsWorld }
, rp3dBody { nullptr }
{
// Implicitly create a static body.
const auto* TRANSFORM = SHComponentManager::GetComponent<SHTransformComponent>(eid);
const rp3d::Transform RP3D_TRANSFORM { TRANSFORM->GetWorldPosition(), TRANSFORM->GetWorldOrientation() };
rp3dBody = world->createRigidBody(RP3D_TRANSFORM);
rp3dBody->setType(rp3d::BodyType::STATIC);
}
SHPhysicsObject::~SHPhysicsObject() noexcept
{
factory = nullptr;
world = nullptr;
rp3dBody = nullptr;
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHVec3 SHPhysicsObject::GetPosition() const noexcept
{
return rp3dBody->getTransform().getPosition();
}
SHQuaternion SHPhysicsObject::GetOrientation() const noexcept
{
return rp3dBody->getTransform().getOrientation();
}
SHVec3 SHPhysicsObject::GetRotation() const noexcept
{
return SHQuaternion{ rp3dBody->getTransform().getOrientation() }.ToEuler();
}
rp3d::CollisionBody* SHPhysicsObject::GetCollisionBody() const noexcept
{
return rp3dBody;
}
rp3d::RigidBody* SHPhysicsObject::GetRigidBody() const noexcept
{
return rp3dBody;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObject::SetStaticBody() const noexcept
{
if (!rp3dBody)
return;
rp3dBody->setType(rp3d::BodyType::STATIC);
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
int SHPhysicsObject::AddCollisionShape(int index) const
{
// Get collider component
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
if (!colliderComponent)
{
SHLOGV_ERROR("Unable to add Collision Shape to Entity {} due to Missing Collider Component!", entityID)
return -1;
}
auto& collisionShape = colliderComponent->GetCollisionShape(index);
switch (collisionShape.GetType())
{
// TODO(Diren): Add more collider shapes
case SHCollisionShape::Type::BOX: addBoxShape(collisionShape); break;
case SHCollisionShape::Type::SPHERE: addSphereShape(collisionShape); break;
default: break;
}
return index;
}
void SHPhysicsObject::RemoveCollisionShape(int index) const
{
const int NUM_COLLIDERS = static_cast<int>(rp3dBody->getNbColliders());
if (NUM_COLLIDERS == 0)
return;
if (index < 0 || index >= NUM_COLLIDERS)
throw std::invalid_argument("Index out of range!");
auto* collider = rp3dBody->getCollider(index);
rp3dBody->removeCollider(collider);
}
void SHPhysicsObject::RemoveAllCollisionShapes() const noexcept
{
int numColliders = static_cast<int>(rp3dBody->getNbColliders());
if (numColliders == 0)
return;
while (numColliders >= 0)
{
auto* collider = rp3dBody->getCollider(numColliders);
rp3dBody->removeCollider(collider);
--numColliders;
}
}
void SHPhysicsObject::SyncRigidBody(SHRigidBodyComponent& component) const noexcept
{
if (component.dirtyFlags == 0)
return;
for (size_t i = 0; i < SHRigidBodyComponent::NUM_DIRTY_FLAGS; ++i)
{
if (const bool IS_DIRTY = component.dirtyFlags & (1U << i); IS_DIRTY)
{
switch (i)
{
case 0: // Gravity
{
const bool IS_ENABLED = component.flags & (1U << i);
rp3dBody->enableGravity(IS_ENABLED);
break;
}
case 1: // Sleeping
{
const bool IS_ENABLED = component.flags & (1U << i);
rp3dBody->setIsAllowedToSleep(IS_ENABLED);
break;
}
case 2: // Lock Position X
{
const bool IS_ENABLED = component.flags & (1U << i);
auto positionLock = rp3dBody->getLinearLockAxisFactor();
positionLock.x = IS_ENABLED ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(positionLock);
break;
}
case 3: // Lock Position Y
{
const bool IS_ENABLED = component.flags & (1U << i);
auto positionLock = rp3dBody->getLinearLockAxisFactor();
positionLock.y = IS_ENABLED ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(positionLock);
break;
}
case 4: // Lock Position Z
{
const bool IS_ENABLED = component.flags & (1U << i);
auto positionLock = rp3dBody->getLinearLockAxisFactor();
positionLock.z = IS_ENABLED ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(positionLock);
break;
}
case 5: // Lock Rotation X
{
const bool IS_ENABLED = component.flags & (1U << i);
auto rotationLock = rp3dBody->getAngularLockAxisFactor();
rotationLock.x = IS_ENABLED ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(rotationLock);
break;
}
case 6: // Lock Rotation Y
{
const bool IS_ENABLED = component.flags & (1U << i);
auto rotationLock = rp3dBody->getAngularLockAxisFactor();
rotationLock.y = IS_ENABLED ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(rotationLock);
break;
}
case 7: // Lock Rotation Z
{
const bool IS_ENABLED = component.flags & (1U << i);
auto rotationLock = rp3dBody->getAngularLockAxisFactor();
rotationLock.z = IS_ENABLED ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(rotationLock);
break;
}
case 8: // Type
{
rp3dBody->setType(static_cast<rp3d::BodyType>(component.type));
break;
}
case 9: // Mass
{
rp3dBody->setMass(component.mass);
rp3dBody->updateLocalInertiaTensorFromColliders();
break;
}
case 10: // Drag
{
rp3dBody->setLinearDamping(component.drag);
break;
}
case 11: // Angular Drag
{
rp3dBody->setAngularDamping(component.angularDrag);
break;
}
default: break;
}
}
}
component.dirtyFlags = 0;
}
void SHPhysicsObject::SyncColliders(SHColliderComponent& component) const noexcept
{
int index = 0;
for (auto& collisionShape : component.collisionShapes)
{
if (!collisionShape.dirty)
continue;
switch (collisionShape.GetType())
{
case SHCollisionShape::Type::BOX: syncBoxShape(index, collisionShape); break;
case SHCollisionShape::Type::SPHERE: syncSphereShape(index, collisionShape); break;
default: break;
}
// TODO(Diren): Update Material
collisionShape.dirty = false;
++index;
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObject::addBoxShape(SHCollisionShape& boxShape) const noexcept
{
const rp3d::Transform OFFSETS
{
boxShape.GetPositionOffset()
, boxShape.GetRotationOffset()
};
const auto* BOX = reinterpret_cast<const SHBoundingBox*>(boxShape.GetShape());
rp3d::BoxShape* newBox = factory->createBoxShape(BOX->GetWorldExtents());
rp3dBody->addCollider(newBox, OFFSETS);
rp3dBody->updateLocalCenterOfMassFromColliders();
rp3dBody->updateLocalInertiaTensorFromColliders();
}
void SHPhysicsObject::syncBoxShape(int index, SHCollisionShape& boxShape) const noexcept
{
const auto* BOX = reinterpret_cast<const SHBoundingBox*>(boxShape.GetShape());
auto* rp3dCollider = rp3dBody->getCollider(index);
auto* rp3dBox = reinterpret_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape());
const rp3d::Transform OFFSETS
{
boxShape.GetPositionOffset()
, boxShape.GetRotationOffset()
};
rp3dCollider->setIsTrigger(boxShape.IsTrigger());
rp3dCollider->setLocalToBodyTransform(OFFSETS);
rp3dBox->setHalfExtents(BOX->GetWorldExtents());
}
void SHPhysicsObject::addSphereShape(SHCollisionShape& sphereShape) const noexcept
{
const rp3d::Transform OFFSETS
{
sphereShape.GetPositionOffset()
, sphereShape.GetRotationOffset()
};
const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(sphereShape.GetShape());
rp3d::SphereShape* newSphere = factory->createSphereShape(SPHERE->GetWorldRadius());
rp3dBody->addCollider(newSphere, OFFSETS);
rp3dBody->updateLocalCenterOfMassFromColliders();
rp3dBody->updateLocalInertiaTensorFromColliders();
}
void SHPhysicsObject::syncSphereShape(int index, SHCollisionShape& sphereShape) const noexcept
{
const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(sphereShape.GetShape());
auto* rp3dCollider = rp3dBody->getCollider(index);
auto* rp3dSphere = reinterpret_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape());
const rp3d::Transform OFFSETS
{
sphereShape.GetPositionOffset()
, sphereShape.GetRotationOffset()
};
rp3dCollider->setIsTrigger(sphereShape.IsTrigger());
rp3dCollider->setLocalToBodyTransform(OFFSETS);
rp3dSphere->setRadius(SPHERE->GetWorldRadius());
}
} // namespace SHADE

View File

@ -14,8 +14,8 @@
// Project Headers // Project Headers
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
namespace SHADE namespace SHADE
{ {
@ -31,6 +31,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem; friend class SHPhysicsSystem;
friend class SHPhysicsObjectManager;
public: public:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -53,26 +54,29 @@ namespace SHADE
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] SHVec3 GetPosition () const noexcept; [[nodiscard]] SHVec3 GetPosition () const noexcept;
[[nodiscard]] SHQuaternion GetOrientation () const noexcept; [[nodiscard]] SHQuaternion GetOrientation () const noexcept;
[[nodiscard]] SHVec3 GetRotation () const noexcept; [[nodiscard]] SHVec3 GetRotation () const noexcept;
[[nodiscard]] rp3d::CollisionBody* GetCollisionBody () const noexcept;
[[nodiscard]] rp3d::RigidBody* GetRigidBody () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SetPosition (const SHVec3& position) noexcept; void SetStaticBody () const noexcept;
void SetOrientation (const SHQuaternion& orientation) noexcept;
void SetRotation (const SHVec3& rotation) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
int AddCollider (SHCollisionShape* collider); int AddCollisionShape (int index) const;
void RemoveCollider (int index); void RemoveCollisionShape (int index) const;
void RemoveAllCollisionShapes () const noexcept;
void SyncColliders (SHColliderComponent* c) const noexcept; void SyncRigidBody (SHRigidBodyComponent& component) const noexcept;
void SyncColliders (SHColliderComponent& component) const noexcept;
private: private:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -83,7 +87,22 @@ namespace SHADE
rp3d::PhysicsCommon* factory; rp3d::PhysicsCommon* factory;
rp3d::PhysicsWorld* world; rp3d::PhysicsWorld* world;
rp3d::CollisionBody* rp3dBody; // Can be either a collision body or a rigid body
rp3d::RigidBody* rp3dBody;
rp3d::Transform prevTransform; // Cached transform for interpolation rp3d::Transform prevTransform; // Cached transform for interpolation
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
// Box Shapes
void addBoxShape (SHCollisionShape& boxShape) const noexcept;
void syncBoxShape (int index, SHCollisionShape& boxShape) const noexcept;
// Sphere Shapes
void addSphereShape (SHCollisionShape& sphereShape) const noexcept;
void syncSphereShape (int index, SHCollisionShape& sphereShape) const noexcept;
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -0,0 +1,266 @@
/****************************************************************************************
* \file SHPhysicsObjectManager.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics Object Manager.
*
* \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.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHPhysicsObjectManager.h"
// Project Headers
#include "Tools/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Data Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObjectManager::CommandFunctionPtr SHPhysicsObjectManager::componentFunc[2][2]
{
addRigidBody , addCollider
, removeRigidBody , removeCollider
};
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObjectManager::SetFactory(rp3d::PhysicsCommon& physicsFactory) noexcept
{
factory = &physicsFactory;
}
void SHPhysicsObjectManager::SetWorld(rp3d::PhysicsWorld& physicsWorld) noexcept
{
world = &physicsWorld;
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject* SHPhysicsObjectManager::GetPhysicsObject(EntityID eid) noexcept
{
const auto it = physicsObjects.find(eid);
if (it == physicsObjects.end())
return nullptr;
return &it->second;
}
const SHPhysicsObjectManager::PhysicsObjectEntityMap SHPhysicsObjectManager::GetPhysicsObjects() const noexcept
{
return physicsObjects;
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObjectManager::AddRigidBody(EntityID eid) noexcept
{
const QueueCommand NEW_QUEUE_COMMAND
{
.eid = eid
, .command = QueueCommand::Command::ADD
, .component = PhysicsComponents::RIGID_BODY
};
commandQueue.push(NEW_QUEUE_COMMAND);
}
void SHPhysicsObjectManager::AddCollider(EntityID eid) noexcept
{
const QueueCommand NEW_QUEUE_COMMAND
{
.eid = eid
, .command = QueueCommand::Command::ADD
, .component = PhysicsComponents::COLLIDER
};
commandQueue.push(NEW_QUEUE_COMMAND);
}
void SHPhysicsObjectManager::AddCollisionShape(EntityID eid, int shapeIndex) noexcept
{
const QueueCommand NEW_QUEUE_COMMAND
{
.eid = eid
, .command = QueueCommand::Command::ADD
, .component = PhysicsComponents::COLLISION_SHAPE
, .shapeIndex = shapeIndex
};
commandQueue.push(NEW_QUEUE_COMMAND);
}
void SHPhysicsObjectManager::RemoveRigidBody(EntityID eid) noexcept
{
const QueueCommand NEW_QUEUE_COMMAND
{
.eid = eid
, .command = QueueCommand::Command::REMOVE
, .component = PhysicsComponents::RIGID_BODY
};
commandQueue.push(NEW_QUEUE_COMMAND);
}
void SHPhysicsObjectManager::RemoveCollider(EntityID eid) noexcept
{
const QueueCommand NEW_QUEUE_COMMAND
{
.eid = eid
, .command = QueueCommand::Command::REMOVE
, .component = PhysicsComponents::COLLIDER
};
commandQueue.push(NEW_QUEUE_COMMAND);
}
void SHPhysicsObjectManager::RemoveCollisionShape(EntityID eid, int shapeIndex) noexcept
{
const QueueCommand NEW_QUEUE_COMMAND
{
.eid = eid
, .command = QueueCommand::Command::REMOVE
, .component = PhysicsComponents::COLLISION_SHAPE
, .shapeIndex = shapeIndex
};
commandQueue.push(NEW_QUEUE_COMMAND);
}
void SHPhysicsObjectManager::UpdateCommands()
{
if (commandQueue.empty())
return;
while (!commandQueue.empty())
{
const QueueCommand COMMAND = commandQueue.front();
commandQueue.pop();
// Check validity of command
if (COMMAND.command == QueueCommand::Command::INVALID || COMMAND.component == PhysicsComponents::INVALID)
continue;
// Find the physics Object & retrieve components. Create an object if none exists.
SHPhysicsObject* physicsObject = GetPhysicsObject(COMMAND.eid);
if (!physicsObject)
physicsObject = createPhysicsObject(COMMAND.eid);
const PhysicsComponentGroup COMPONENT_GROUP
{
.eid = COMMAND.eid
, .rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(COMMAND.eid)
, .colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(COMMAND.eid)
};
if (COMMAND.component == PhysicsComponents::COLLISION_SHAPE)
{
if (COMMAND.command == QueueCommand::Command::ADD)
addCollisionShape(physicsObject, COMMAND.shapeIndex);
if (COMMAND.command == QueueCommand::Command::REMOVE)
removeCollisionShape(physicsObject, COMMAND.shapeIndex);
}
else // Rigid Body or Collider
{
componentFunc[SHUtilities::ConvertEnum(COMMAND.command)][SHUtilities::ConvertEnum(COMMAND.component)](physicsObject, COMPONENT_GROUP);
}
// If main components are missing, destroy object
if (!COMPONENT_GROUP.rigidBodyComponent && !COMPONENT_GROUP.colliderComponent)
destroyPhysicsObject(COMMAND.eid);
}
}
void SHPhysicsObjectManager::RemoveAllObjects()
{
physicsObjects.clear();
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject* SHPhysicsObjectManager::createPhysicsObject(EntityID eid) noexcept
{
auto newObjIter = physicsObjects.emplace(eid, SHPhysicsObject{ eid, factory, world });
return &(newObjIter.first->second);
}
void SHPhysicsObjectManager::destroyPhysicsObject(EntityID eid) noexcept
{
physicsObjects.erase(eid);
}
void SHPhysicsObjectManager::addRigidBody(SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to add body!")
if (!componentGroup.rigidBodyComponent)
{
SHLOG_ERROR("Entity {} is missing a Rigidbody Component. Unable to update physics object!", componentGroup.eid)
return;
}
// A static rigid body is implicitly created on creation of a physics object.
// We only need to sync rigid bodies here in the event it is non-static.
physicsObject->SyncRigidBody(*componentGroup.rigidBodyComponent);
}
void SHPhysicsObjectManager::addCollider(SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to add collider!")
if (!componentGroup.colliderComponent)
{
SHLOG_ERROR("Entity {} is missing a Rigidbody Component. Unable to update physics object!", componentGroup.eid)
return;
}
physicsObject->SyncColliders(*componentGroup.colliderComponent);
}
void SHPhysicsObjectManager::removeRigidBody(SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to remove body!")
if (componentGroup.colliderComponent)
physicsObject->SetStaticBody();
}
void SHPhysicsObjectManager::removeCollider(SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to remove collider!")
physicsObject->RemoveAllCollisionShapes();
}
void SHPhysicsObjectManager::addCollisionShape(SHPhysicsObject* physicsObject, int shapeIndex)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to add collision shape!")
physicsObject->AddCollisionShape(shapeIndex);
}
void SHPhysicsObjectManager::removeCollisionShape(SHPhysicsObject* physicsObject, int shapeIndex)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to remove collision shape!")
physicsObject->RemoveCollisionShape(shapeIndex);
}
} // namespace SHADE

View File

@ -0,0 +1,178 @@
/****************************************************************************************
* \file SHPhysicsObjectManager.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Physics Object Manager.
*
* \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 <unordered_map>
#include <queue>
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "SHPhysicsObject.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsObjectManager
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using PhysicsObjectEntityMap = std::unordered_map<EntityID, SHPhysicsObject>;
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class PhysicsComponents
{
RIGID_BODY
, COLLIDER
, COLLISION_SHAPE
, TOTAL
, INVALID = -1
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsObjectManager () = default;
~SHPhysicsObjectManager () = default;
SHPhysicsObjectManager (const SHPhysicsObjectManager&) = delete;
SHPhysicsObjectManager (SHPhysicsObjectManager&&) = delete;
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
SHPhysicsObjectManager& operator=(const SHPhysicsObjectManager&) = delete;
SHPhysicsObjectManager& operator=(SHPhysicsObjectManager&&) = delete;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] SHPhysicsObject* GetPhysicsObject (EntityID eid) noexcept;
[[nodiscard]] const PhysicsObjectEntityMap GetPhysicsObjects () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetFactory (rp3d::PhysicsCommon& physicsFactory) noexcept;
void SetWorld (rp3d::PhysicsWorld& physicsWorld) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void AddRigidBody (EntityID eid) noexcept;
void AddCollider (EntityID eid) noexcept;
void AddCollisionShape (EntityID eid, int shapeIndex) noexcept;
void RemoveRigidBody (EntityID eid) noexcept;
void RemoveCollider (EntityID eid) noexcept;
void RemoveCollisionShape (EntityID eid, int shapeIndex) noexcept;
void UpdateCommands ();
void RemoveAllObjects ();
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
struct QueueCommand
{
/*-------------------------------------------------------------------------------*/
/* Type Definitions */
/*-------------------------------------------------------------------------------*/
enum class Command
{
ADD
, REMOVE
, INVALID = -1
};
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
EntityID eid = MAX_EID;
Command command = Command::INVALID;
PhysicsComponents component = PhysicsComponents::INVALID;
int shapeIndex = -1; // Only used when adding & removing collision shapes
};
struct PhysicsComponentGroup
{
public:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
EntityID eid = MAX_EID;
SHRigidBodyComponent* rigidBodyComponent = nullptr;
SHColliderComponent* colliderComponent = nullptr;
};
using CommandFunctionPtr = void(*)(SHPhysicsObject*, const PhysicsComponentGroup&);
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
static CommandFunctionPtr componentFunc[2][2]; // Used only for rigid body & collider components. Collision shapes are handled separately.
rp3d::PhysicsCommon* factory = nullptr;
rp3d::PhysicsWorld* world = nullptr;
PhysicsObjectEntityMap physicsObjects;
std::queue<QueueCommand> commandQueue;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsObject* createPhysicsObject (EntityID eid) noexcept;
void destroyPhysicsObject (EntityID eid) noexcept;
static void addRigidBody (SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void addCollider (SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void removeRigidBody (SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void removeCollider (SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void addCollisionShape (SHPhysicsObject* physicsObject, int shapeIndex);
static void removeCollisionShape (SHPhysicsObject* physicsObject, int shapeIndex);
};
} // namespace SHADE

View File

@ -0,0 +1,37 @@
/****************************************************************************************
* \file SHPhysicsUtils.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for some Physics Utilities
*
* \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
// Project Headers
#include "Interface/SHCollisionShape.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
struct SHPhysicsColliderAddedEvent
{
EntityID entityID;
SHCollisionShape::Type colliderType;
int colliderIndex;
};
struct SHPhysicsColliderRemovedEvent
{
EntityID entityID;
int colliderIndex;
};
} // namespace SHADE

View File

@ -1,219 +0,0 @@
/****************************************************************************************
* \file SHPhysicsObject.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics Object.
*
* \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.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHPhysicsObject.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "ECS_Base/Managers/SHComponentManager.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept
: entityID { eid }
, factory { physicsFactory }
, world { physicsWorld }
, rp3dBody { nullptr }
{}
SHPhysicsObject::~SHPhysicsObject() noexcept
{
factory = nullptr;
world = nullptr;
rp3dBody = nullptr;
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHVec3 SHPhysicsObject::GetPosition() const noexcept
{
SHVec3 result;
if (rp3dBody)
result = SHVec3{ rp3dBody->getTransform().getPosition() };
return result;
}
SHQuaternion SHPhysicsObject::GetOrientation() const noexcept
{
SHQuaternion result;
if (rp3dBody)
result = SHQuaternion{ rp3dBody->getTransform().getOrientation() };
return result;
}
SHVec3 SHPhysicsObject::GetRotation() const noexcept
{
SHVec3 result;
if (rp3dBody)
result = SHQuaternion{ rp3dBody->getTransform().getOrientation() }.ToEuler();
return result;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObject::SetPosition(const SHVec3& position) noexcept
{
if (!rp3dBody)
{
SHLOG_ERROR("Cannot set position of a non-existent physics body for Entity {}", entityID)
return;
}
rp3d::Transform rp3dTF;
rp3dTF.setPosition(position);
rp3dTF.setOrientation(rp3dBody->getTransform().getOrientation());
rp3dBody->setTransform(rp3dTF);
prevTransform = rp3dTF;
}
void SHPhysicsObject::SetOrientation(const SHQuaternion& orientation) noexcept
{
if (!rp3dBody)
{
SHLOG_ERROR("Cannot set orientation of a non-existent physics body for Entity {}", entityID)
return;
}
rp3d::Transform rp3dTF;
rp3dTF.setPosition(rp3dBody->getTransform().getPosition());
rp3dTF.setOrientation(orientation);
rp3dBody->setTransform(rp3dTF);
prevTransform = rp3dTF;
}
void SHPhysicsObject::SetRotation(const SHVec3& rotation) noexcept
{
if (!rp3dBody)
{
SHLOG_ERROR("Cannot set rotation of a non-existent physics body for Entity {}", entityID)
return;
}
rp3d::Transform rp3dTF;
rp3dTF.setPosition(rp3dBody->getTransform().getPosition());
rp3dTF.setOrientation(rotation);
rp3dBody->setTransform(rp3dTF);
prevTransform = rp3dTF;
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
int SHPhysicsObject::AddCollider(SHCollisionShape* collider)
{
const rp3d::Transform OFFSETS{ collider->GetPositionOffset(), collider->GetRotationOffset() };
switch (collider->GetType())
{
case SHCollisionShape::Type::BOX:
{
const auto* BOX = reinterpret_cast<const SHBoundingBox*>(collider->GetShape());
rp3d::BoxShape* newBox = factory->createBoxShape(BOX->GetWorldExtents());
rp3dBody->addCollider(newBox, OFFSETS);
break;
}
case SHCollisionShape::Type::SPHERE:
{
const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(collider->GetShape());
rp3d::SphereShape* newSphere = factory->createSphereShape(SPHERE->GetWorldRadius());
rp3dBody->addCollider(newSphere, OFFSETS);
break;
}
// TODO(Diren): Add more collider shapes
default: break;
}
return static_cast<int>(rp3dBody->getNbColliders()) - 1;
}
void SHPhysicsObject::RemoveCollider(int index)
{
const int NUM_COLLIDERS = static_cast<int>(rp3dBody->getNbColliders());
if (NUM_COLLIDERS == 0)
return;
if (index < 0 || index >= NUM_COLLIDERS)
throw std::invalid_argument("Index out of range!");
auto* collider = rp3dBody->getCollider(index);
rp3dBody->removeCollider(collider);
}
void SHPhysicsObject::SyncColliders(SHColliderComponent* c) const noexcept
{
int index = 0;
for (auto& collider : c->collisionShapes)
{
if (!collider.dirty)
continue;
auto* rp3dCollider = rp3dBody->getCollider(index);
// Update trigger flag
rp3dCollider->setIsTrigger(collider.IsTrigger());
// Update offsets
rp3dCollider->setLocalToBodyTransform(rp3d::Transform(collider.GetPositionOffset(), collider.GetRotationOffset()));
switch (collider.GetType())
{
case SHCollisionShape::Type::BOX:
{
const auto* BOX = reinterpret_cast<const SHBoundingBox*>(collider.GetShape());
auto* rp3dBoxShape = reinterpret_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape());
rp3dBoxShape->setHalfExtents(BOX->GetWorldExtents());
break;
}
case SHCollisionShape::Type::SPHERE:
{
const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(collider.GetShape());
auto* rp3dSphereShape = reinterpret_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape());
rp3dSphereShape->setRadius(SPHERE->GetWorldRadius());
break;
}
default: break;
}
// TODO(Diren): Update Material
collider.dirty = false;
++index;
}
}
} // namespace SHADE

View File

@ -1,706 +0,0 @@
/****************************************************************************************
* \file SHPhysicsSystem.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for 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.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHPhysicsSystem.h"
// Project Headers
#include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
#include "Math/SHMathHelpers.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneManager.h"
#include "Scripting/SHScriptEngine.h"
#include "Tools/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsSystem::SHPhysicsSystem()
: worldUpdated { false }
, interpolationFactor { 0.0 }
, fixedDT { 60.0 }
, world { nullptr }
{}
SHPhysicsSystem::PhysicsPreUpdate::PhysicsPreUpdate()
: SHSystemRoutine { "Physics PreUpdate", true }
{}
SHPhysicsSystem::PhysicsFixedUpdate::PhysicsFixedUpdate()
: SHFixedSystemRoutine { DEFAULT_FIXED_STEP, "Physics FixedUpdate", false }
{}
SHPhysicsSystem::PhysicsPostUpdate::PhysicsPostUpdate()
: SHSystemRoutine { "Physics PostUpdate", false }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
double SHPhysicsSystem::GetFixedDT() const noexcept
{
return fixedDT;
}
bool SHPhysicsSystem::IsSleepingEnabled() const noexcept
{
if (world)
return world->isSleepingEnabled();
SHLOGV_WARNING("No physics world has been initialised!")
return false;
}
SHVec3 SHPhysicsSystem::GetWorldGravity() const noexcept
{
SHVec3 result;
if (world)
{
result = world->getGravity();
}
else
{
SHLOGV_WARNING("No physics world has been initialised!")
}
return result;
}
uint16_t SHPhysicsSystem::GetNumberVelocityIterations() const noexcept
{
if (world)
return world->getNbIterationsVelocitySolver();
SHLOGV_WARNING("No physics world has been initialised!")
return 0;
}
uint16_t SHPhysicsSystem::GetNumberPositionIterations() const noexcept
{
if (world)
return world->getNbIterationsPositionSolver();
SHLOGV_WARNING("No physics world has been initialised!")
return 0;
}
const SHPhysicsSystem::EntityObjectMap& SHPhysicsSystem::GetPhysicsObjects() const noexcept
{
return map;
}
const SHPhysicsSystem::CollisionEvents& SHPhysicsSystem::GetCollisionInfo() const noexcept
{
return collisionInfo;
}
const SHPhysicsSystem::CollisionEvents& SHPhysicsSystem::GetTriggerInfo() const noexcept
{
return triggerInfo;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::SetFixedDT(double fixedUpdateRate) noexcept
{
fixedDT = fixedUpdateRate;
}
void SHPhysicsSystem::SetWorldGravity(const SHVec3& gravity) const noexcept
{
if (world)
{
world->setGravity(gravity);
}
else
{
SHLOGV_WARNING("No physics world has been initialised!")
}
}
void SHPhysicsSystem::SetNumberVelocityIterations(uint16_t numVelIterations) const noexcept
{
if (world)
{
world->setNbIterationsVelocitySolver(numVelIterations);
}
else
{
SHLOGV_WARNING("No physics world has been initialised!")
}
}
void SHPhysicsSystem::SetNumberPositionIterations(uint16_t numPosIterations) const noexcept
{
if (world)
{
world->setNbIterationsPositionSolver(numPosIterations);
}
else
{
SHLOGV_WARNING("No physics world has been initialised!")
}
}
void SHPhysicsSystem::SetSleepingEnabled(bool enableSleeping) const noexcept
{
if (world)
{
world->enableSleeping(enableSleeping);
}
else
{
SHLOGV_WARNING("No physics world has been initialised!")
}
}
void SHPhysicsSystem::SetWorldSettings(const WorldSettings& settings) const noexcept
{
if (world)
{
world->setGravity(settings.gravity);
world->setNbIterationsVelocitySolver(settings.numVelocitySolverIterations);
world->setNbIterationsPositionSolver(settings.numPositionSolverIterations);
world->enableSleeping(settings.sleepingEnabled);
}
else
{
SHLOGV_WARNING("No physics world has been initialised!")
}
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::Init()
{
// Create a physics world with the default settings
rp3d::PhysicsWorld::WorldSettings settings;
settings.gravity = SHVec3{ 0.0f, -9.81f, 0.0f };
settings.isSleepingEnabled = true;
settings.defaultVelocitySolverNbIterations = 8;
settings.defaultPositionSolverNbIterations = 3;
settings.defaultFrictionCoefficient = 0.4f;
settings.defaultBounciness = 0.0f;
world = factory.createPhysicsWorld(settings);
world->setEventListener(this);
world->setIsDebugRenderingEnabled(true);
// Set up solvers
world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES);
// Subscribe to component events
const std::shared_ptr ADD_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::AddPhysicsComponent) };
const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ADD_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_ADDED_EVENT, ADD_COMPONENT_RECEIVER_PTR);
const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::RemovePhysicsComponent) };
const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(REMOVE_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, REMOVE_COMPONENT_RECEIVER_PTR);
#ifdef SHEDITOR
const std::shared_ptr EDITOR_STOP_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::ResetWorld) };
const ReceiverPtr EDITOR_STOP_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(EDITOR_STOP_RECEIVER);
SHEventManager::SubscribeTo(SH_EDITOR_ON_STOP_EVENT, EDITOR_STOP_RECEIVER_PTR);
#endif
}
void SHPhysicsSystem::Exit()
{
factory.destroyPhysicsWorld(world);
}
void SHPhysicsSystem::AddCollisionShape(EntityID entityID, SHCollisionShape* collider)
{
auto* physicsObject = GetPhysicsObject(entityID);
const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA
{
.entityID = entityID
, .colliderType = collider->GetType()
, .colliderIndex = physicsObject->AddCollider(collider)
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
}
void SHPhysicsSystem::RemoveCollisionShape(EntityID entityID, int index)
{
auto* physicsObject = GetPhysicsObject(entityID);
physicsObject->RemoveCollider(index);
const SHPhysicsColliderRemovedEvent COLLIDER_REMOVED_EVENT_DATA
{
.entityID = entityID
, .colliderIndex = index
};
SHEventManager::BroadcastEvent<SHPhysicsColliderRemovedEvent>(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT);
}
void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept
{
auto* system = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
// Sync transforms
for (auto& [entityID, physicsObject] : system->map)
{
// Ensure a valid physics Object
if (physicsObject.rp3dBody == nullptr)
continue;
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())
{
const auto WORLD_POS = transformComponent->GetWorldPosition();
const auto WORLD_ROT = transformComponent->GetWorldOrientation();
const auto WORLD_SCL = transformComponent->GetWorldScale();
physicsObject.SetPosition(WORLD_POS);
physicsObject.SetOrientation(WORLD_ROT);
// Sync physics component transforms
if (rigidBodyComponent)
{
rigidBodyComponent->position = WORLD_POS;
rigidBodyComponent->orientation = WORLD_ROT;
}
if (colliderComponent)
{
colliderComponent->position = WORLD_POS;
colliderComponent->orientation = WORLD_ROT;
colliderComponent->scale = WORLD_SCL;
colliderComponent->RecomputeCollisionShapes();
}
}
// Sync rigid bodies
if (rigidBodyComponent)
{
// Sync active states
const bool COMPONENT_ACTIVE = rigidBodyComponent->isActive;
SyncActiveStates(physicsObject, COMPONENT_ACTIVE);
if (!COMPONENT_ACTIVE)
continue;
}
// Sync colliders
if (colliderComponent)
{
const bool COMPONENT_ACTIVE = colliderComponent->isActive;
SyncActiveStates(physicsObject, colliderComponent->isActive);
if (!COMPONENT_ACTIVE)
continue;
physicsObject.SyncColliders(colliderComponent);
}
}
}
void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!");
}
fixedTimeStep = 1.0 / physicsSystem->fixedDT;
accumulatedTime += dt;
int count = 0;
while (accumulatedTime > fixedTimeStep)
{
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteFixedUpdates();
physicsSystem->world->update(static_cast<rp3d::decimal>(fixedTimeStep));
accumulatedTime -= fixedTimeStep;
++count;
}
stats.numSteps = count;
physicsSystem->worldUpdated = count > 0;
physicsSystem->interpolationFactor = accumulatedTime / fixedTimeStep;
}
void SHPhysicsSystem::PhysicsPostUpdate::Execute(double) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!");
}
// Interpolate transforms for rendering
if (physicsSystem->worldUpdated)
{
physicsSystem->SyncTransforms();
// Collision & Trigger messages
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteCollisionFunctions();
physicsSystem->ClearInvalidCollisions();
}
}
void SHPhysicsSystem::onContact(const CallbackData& callbackData)
{
for (uint32_t i = 0; i < callbackData.getNbContactPairs(); ++i)
{
const auto CONTACT_PAIR = callbackData.getContactPair(i);
const SHCollisionEvent NEW_EVENT = GenerateCollisionEvent(CONTACT_PAIR);
UpdateEventContainers(NEW_EVENT, collisionInfo);
}
}
void SHPhysicsSystem::onTrigger(const rp3d::OverlapCallback::CallbackData& callbackData)
{
for (uint32_t i = 0; i < callbackData.getNbOverlappingPairs(); ++i)
{
const auto& OVERLAP_PAIR = callbackData.getOverlappingPair(i);
const SHCollisionEvent NEW_EVENT = GenerateCollisionEvent(OVERLAP_PAIR);
UpdateEventContainers(NEW_EVENT, triggerInfo);
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject* SHPhysicsSystem::EnsurePhysicsObject(EntityID entityID) noexcept
{
const auto it = map.find(entityID);
if (it == map.end())
{
auto* newPhysicsObject = &map.emplace(entityID, SHPhysicsObject{entityID, &factory, world}).first->second;
return newPhysicsObject;
}
return &(it->second);
}
SHPhysicsObject* SHPhysicsSystem::GetPhysicsObject(EntityID entityID) noexcept
{
const auto it = map.find(entityID);
if (it == map.end())
{
//SHLOG_ERROR("Entity {} is not in the physics system!", entityID)
return nullptr;
}
return &(it->second);
}
void SHPhysicsSystem::DestroyPhysicsObject(EntityID entityID) noexcept
{
map.erase(entityID);
}
void SHPhysicsSystem::SyncActiveStates(SHPhysicsObject& physicsObject, bool componentActive) noexcept
{
const bool RP3D_ACTIVE = physicsObject.rp3dBody->isActive();
if (RP3D_ACTIVE != componentActive)
physicsObject.rp3dBody->setIsActive(componentActive);
}
void SHPhysicsSystem::SyncTransforms() noexcept
{
for (auto& [entityID, physicsObject] : map)
{
rp3d::Vector3 rp3dPos;
rp3d::Quaternion rp3dRot;
const rp3d::Transform CURRENT_TF = physicsObject.rp3dBody->getTransform();
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
// Check if transform should be interpolated
if (rigidBodyComponent != nullptr)
{
if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
continue;
if (rigidBodyComponent->IsInterpolating())
{
const rp3d::Transform PREV_TF = physicsObject.prevTransform;
const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast<rp3d::decimal>(interpolationFactor));
rp3dPos = INTERPOLATED_TF.getPosition();
rp3dRot = INTERPOLATED_TF.getOrientation();
}
else
{
rp3dPos = CURRENT_TF.getPosition();
rp3dRot = CURRENT_TF.getOrientation();
}
rigidBodyComponent->position = CURRENT_TF.getPosition();
rigidBodyComponent->orientation = CURRENT_TF.getOrientation();
if (colliderComponent != nullptr)
{
colliderComponent->position = CURRENT_TF.getPosition();
colliderComponent->orientation = CURRENT_TF.getOrientation();
}
}
else
{
rp3dPos = CURRENT_TF.getPosition();
rp3dRot = CURRENT_TF.getOrientation();
}
// Convert RP3D Transform to SHADE
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (transformComponent != nullptr)
{
transformComponent->SetWorldPosition(rp3dPos);
transformComponent->SetWorldOrientation(rp3dRot);
}
// Cache transforms
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.ids[0] == collisionEvent.ids[0] && e.ids[1] == collisionEvent.ids[1])
|| (e.ids[0] == collisionEvent.ids[1] && e.ids[1] == collisionEvent.ids[0]);
const bool COLLIDERS_MATCH = (e.ids[2] == collisionEvent.ids[2] && e.ids[3] == collisionEvent.ids[3])
|| (e.ids[2] == collisionEvent.ids[3] && e.ids[3] == collisionEvent.ids[2]);
return ENTITY_MATCH && COLLIDERS_MATCH;
});
if (IT == container.end())
container.emplace_back(collisionEvent);
else
IT->collisionState = collisionEvent.collisionState;
}
void SHPhysicsSystem::ClearInvalidCollisions() noexcept
{
static const auto CLEAR = [](CollisionEvents& container)
{
for (auto eventIter = container.begin(); eventIter != container.end();)
{
const bool CLEAR_EVENT = eventIter->GetCollisionState() == SHCollisionEvent::State::EXIT
|| eventIter->GetCollisionState() == SHCollisionEvent::State::INVALID;
if (CLEAR_EVENT)
eventIter = container.erase(eventIter);
else
++eventIter;
}
};
CLEAR(collisionInfo);
CLEAR(triggerInfo);
}
SHEventHandle SHPhysicsSystem::AddPhysicsComponent(SHEventPtr addComponentEvent)
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(addComponentEvent.get());
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto ADDED_ID = EVENT_DATA->data->addedComponentType;
const bool IS_PHYSICS_COMPONENT = ADDED_ID == RIGID_BODY_ID || ADDED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{
const EntityID ENTITY_ID = EVENT_DATA->data->eid;
auto* physicsObject = EnsurePhysicsObject(ENTITY_ID);
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(ENTITY_ID);
if (transformComponent == nullptr)
{
SHLOG_ERROR("Entity {} cannot add a Physics Component without a Transform! Component not created!", ENTITY_ID)
return EVENT_DATA->handle;
}
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ENTITY_ID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
if (ADDED_ID == RIGID_BODY_ID)
{
if (colliderComponent != nullptr)
{
world->destroyCollisionBody(physicsObject->rp3dBody);
physicsObject->rp3dBody = nullptr;
}
rigidBodyComponent->position = transformComponent->GetWorldPosition();
rigidBodyComponent->orientation = transformComponent->GetWorldOrientation();
physicsObject->rp3dBody = world->createRigidBody
(
rp3d::Transform{ rigidBodyComponent->position, rigidBodyComponent->orientation }
);
rigidBodyComponent->rp3dBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody);
// Add collision shapes back into the body
if (colliderComponent != nullptr)
{
for (auto& collider : colliderComponent->collisionShapes)
physicsObject->AddCollider(&collider);
}
}
if (ADDED_ID == COLLIDER_ID)
{
SHASSERT(colliderComponent != nullptr, "Collider Component was not added to Entity " + std::to_string(ENTITY_ID) + "!");
colliderComponent->position = transformComponent->GetWorldPosition();
colliderComponent->orientation = transformComponent->GetWorldOrientation();
colliderComponent->scale = transformComponent->GetWorldScale();
if (physicsObject->rp3dBody == nullptr)
{
physicsObject->rp3dBody = world->createCollisionBody
(
rp3d::Transform{ colliderComponent->position, colliderComponent->orientation }
);
}
// Add Collision Shapes
for (auto& collider : colliderComponent->collisionShapes)
physicsObject->AddCollider(&collider);
}
}
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::RemovePhysicsComponent(SHEventPtr removeComponentEvent)
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(removeComponentEvent.get());
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto REMOVED_ID = EVENT_DATA->data->removedComponentType;
const bool IS_PHYSICS_COMPONENT = REMOVED_ID == RIGID_BODY_ID || REMOVED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{
const EntityID ENTITY_ID = EVENT_DATA->data->eid;
auto* physicsObject = GetPhysicsObject(ENTITY_ID);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ENTITY_ID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
// Wake up all physics objects
for (auto& [entityID, object] : map)
{
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(entityID))
reinterpret_cast<rp3d::RigidBody*>(object.rp3dBody)->setIsSleeping(false);
}
if (REMOVED_ID == RIGID_BODY_ID && physicsObject != nullptr)
{
world->destroyRigidBody(reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody));
physicsObject->rp3dBody = nullptr;
if (colliderComponent != nullptr)
{
// Preserve colliders as a collision body
physicsObject->rp3dBody = world->createCollisionBody
(
rp3d::Transform{ colliderComponent->position, colliderComponent->orientation }
);
for (auto& collider : colliderComponent->collisionShapes)
physicsObject->AddCollider(&collider);
}
}
if (REMOVED_ID == COLLIDER_ID && physicsObject != nullptr)
{
// Remove all colliders
const int NUM_COLLIDERS = static_cast<int>(physicsObject->rp3dBody->getNbColliders());
for (int i = NUM_COLLIDERS - 1; i >= 0; --i)
{
auto* collider = physicsObject->rp3dBody->getCollider(i);
physicsObject->rp3dBody->removeCollider(collider);
}
// Check for a rigidbody component
if (rigidBodyComponent == nullptr)
physicsObject->rp3dBody = nullptr;
}
if (physicsObject != nullptr && physicsObject->rp3dBody == nullptr)
DestroyPhysicsObject(ENTITY_ID);
}
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::ResetWorld(SHEventPtr editorStopEvent)
{
// TODO(Diren): Rebuild world based on how scene reloading is done
for (auto& [entityID, physicsObject] : map)
{
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(entityID))
{
auto* rp3dRigidBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject.rp3dBody);
rp3dRigidBody->resetForce();
rp3dRigidBody->resetTorque();
rp3dRigidBody->setLinearVelocity(SHVec3::Zero);
rp3dRigidBody->setAngularVelocity(SHVec3::Zero);
}
}
return editorStopEvent->handle;
}
} // namespace SHADE

View File

@ -1,84 +0,0 @@
/****************************************************************************************
* \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;
// Update collision state
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;
}
} // namespace SHADE

View File

@ -0,0 +1,66 @@
/****************************************************************************************
* \file SHPhysicsWorld.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics World.
*
* \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.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHPhysicsWorld.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsWorldState::SHPhysicsWorldState() noexcept
: world { nullptr }
{}
/*-----------------------------------------------------------------------------------*/
/* Public Function Members Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsWorldState::CreateWorld(rp3d::PhysicsCommon& factory)
{
rp3d::PhysicsWorld::WorldSettings rp3dWorldSettings;
rp3dWorldSettings.gravity = settings.gravity;
rp3dWorldSettings.defaultVelocitySolverNbIterations = settings.numVelocitySolverIterations;
rp3dWorldSettings.defaultPositionSolverNbIterations = settings.numPositionSolverIterations;
rp3dWorldSettings.isSleepingEnabled = settings.sleepingEnabled;
world = factory.createPhysicsWorld(rp3dWorldSettings);
}
void SHPhysicsWorldState::DestroyWorld(rp3d::PhysicsCommon& factory)
{
if (!world)
return;
factory.destroyPhysicsWorld(world);
world = nullptr;
}
void SHPhysicsWorldState::UpdateSettings() const noexcept
{
if (!world)
{
SHLOGV_ERROR("Unable to update Physics World settings without creating a world!")
return;
}
world->setGravity(settings.gravity);
world->setNbIterationsVelocitySolver(settings.numVelocitySolverIterations);
world->setNbIterationsPositionSolver(settings.numPositionSolverIterations);
world->enableSleeping(settings.sleepingEnabled);
}
} // namespace SHADE

View File

@ -0,0 +1,74 @@
/****************************************************************************************
* \file SHPhysicsWorld.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Physics World.
*
* \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 <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "Math/SHMath.h"
#include "SH_API.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
struct SH_API SHPhysicsWorldState
{
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
struct WorldSettings
{
public:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
SHVec3 gravity = SHVec3{ 0.0f, -9.81f, 0.0f };
uint16_t numVelocitySolverIterations = 8;
uint16_t numPositionSolverIterations = 3;
bool sleepingEnabled = true;
};
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
rp3d::PhysicsWorld* world;
WorldSettings settings;
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsWorldState() noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void CreateWorld (rp3d::PhysicsCommon& factory);
void DestroyWorld (rp3d::PhysicsCommon& factory);
/**
* @brief Applies the current settings to the physics world. The world must be created
* before this is called.
*/
void UpdateSettings () const noexcept;
};
} // namespace SHADE

View File

@ -0,0 +1,307 @@
/****************************************************************************************
* \file SHPhysicsSystem.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for 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.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHPhysicsSystem.h"
// Project Headers
#include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Physics/SHPhysicsEvents.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsSystem::SHPhysicsSystem()
: worldUpdated { false }
, interpolationFactor { 0.0 }
, fixedDT { 60.0 }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
double SHPhysicsSystem::GetFixedDT() const noexcept
{
return fixedDT;
}
const SHPhysicsWorldState::WorldSettings& SHPhysicsSystem::GetWorldSettings() const noexcept
{
return worldState.settings;
}
const std::vector<SHCollisionInfo>& SHPhysicsSystem::GetAllCollisionInfo() const noexcept
{
return collisionListener.GetCollisionInfoContainer();
}
const std::vector<SHCollisionInfo>& SHPhysicsSystem::GetAllTriggerInfo() const noexcept
{
return collisionListener.GetTriggerInfoContainer();
}
const SHPhysicsObject* const SHPhysicsSystem::GetPhysicsObject(EntityID eid) noexcept
{
return objectManager.GetPhysicsObject(eid);
}
const SHPhysicsObjectManager::PhysicsObjectEntityMap& SHPhysicsSystem::GetPhysicsObjects() const noexcept
{
return objectManager.physicsObjects;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::SetFixedDT(double fixedUpdateRate) noexcept
{
fixedDT = fixedUpdateRate;
}
void SHPhysicsSystem::SetWorldSettings(const SHPhysicsWorldState::WorldSettings& settings) noexcept
{
worldState.settings = settings;
worldState.UpdateSettings();
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::Init()
{
// Subscribe to component events
const std::shared_ptr ADD_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::addPhysicsComponent) };
const ReceiverPtr ADD_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ADD_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_ADDED_EVENT, ADD_COMPONENT_RECEIVER_PTR);
const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::removePhysicsComponent) };
const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(REMOVE_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, REMOVE_COMPONENT_RECEIVER_PTR);
#ifdef SHEDITOR
// Subscribe to Editor State Change Events
const std::shared_ptr ON_PLAY_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::onPlay) };
const ReceiverPtr ON_PLAY_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ON_PLAY_RECEIVER);
SHEventManager::SubscribeTo(SH_EDITOR_ON_PLAY_EVENT, ON_PLAY_RECEIVER_PTR);
const std::shared_ptr ON_STOP_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::onStop) };
const ReceiverPtr ON_STOP_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(ON_STOP_RECEIVER);
SHEventManager::SubscribeTo(SH_EDITOR_ON_STOP_EVENT, ON_STOP_RECEIVER_PTR);
#endif
// Link Physics Object Manager with System
objectManager.SetFactory(factory);
// Link Collision Listener with System
collisionListener.BindToSystem(this);
}
void SHPhysicsSystem::Exit()
{
worldState.DestroyWorld(factory);
}
void SHPhysicsSystem::AddCollisionShape(EntityID eid, int shapeIndex)
{
objectManager.AddCollisionShape(eid, shapeIndex);
const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA
{
.entityID = eid
, .colliderType = SHComponentManager::GetComponent<SHColliderComponent>(eid)->GetCollisionShape(shapeIndex).GetType()
, .colliderIndex = shapeIndex
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
}
void SHPhysicsSystem::RemoveCollisionShape(EntityID eid, int shapeIndex)
{
objectManager.RemoveCollisionShape(eid, shapeIndex);
const SHPhysicsColliderRemovedEvent COLLIDER_REMOVED_EVENT_DATA
{
.entityID = eid
, .colliderIndex = shapeIndex
};
SHEventManager::BroadcastEvent<SHPhysicsColliderRemovedEvent>(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT);
}
void SHPhysicsSystem::AddForce(EntityID eid, const SHVec3& force) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddForceAtLocalPos(EntityID eid, const SHVec3& force, const SHVec3& localPos) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddForceAtWorldPos(EntityID eid, const SHVec3& force, const SHVec3& worldPos) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddRelativeForce(EntityID eid, const SHVec3& relativeForce) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddRelativeForceAtLocalPos(EntityID eid, const SHVec3& relativeForce, const SHVec3& localPos) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddRelativeForceAtWorldPos(EntityID eid, const SHVec3& relativeForce, const SHVec3& worldPos) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddTorque(EntityID eid, const SHVec3& torque) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
void SHPhysicsSystem::AddRelativeTorque(EntityID eid, const SHVec3& relativeTorque) noexcept
{
auto* physicsObject = objectManager.GetPhysicsObject(eid);
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHEventHandle SHPhysicsSystem::addPhysicsComponent(SHEventPtr addComponentEvent) noexcept
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(addComponentEvent.get());
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto ADDED_ID = EVENT_DATA->data->addedComponentType;
const bool IS_PHYSICS_COMPONENT = ADDED_ID == RIGID_BODY_ID || ADDED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{
const EntityID EID = EVENT_DATA->data->eid;
// We only add tell the physics object manager to add a component if the scene is played
#ifdef _PUBLISH
ADDED_ID == RIGID_BODY_ID ? objectManager.AddRigidBody(EID) : objectManager.AddCollider(EID);
#elif SHEDITOR
auto* editor = SHSystemManager::GetSystem<SHEditor>();
if (editor)
{
if (editor->editorState != SHEditor::State::STOP)
ADDED_ID == RIGID_BODY_ID ? objectManager.AddRigidBody(EID) : objectManager.AddCollider(EID);
}
#endif
}
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::removePhysicsComponent(SHEventPtr removeComponentEvent) noexcept
{
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(removeComponentEvent.get());
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto REMOVED_ID = EVENT_DATA->data->removedComponentType;
const bool IS_PHYSICS_COMPONENT = REMOVED_ID == RIGID_BODY_ID || REMOVED_ID == COLLIDER_ID;
if (IS_PHYSICS_COMPONENT)
{
const EntityID EID = EVENT_DATA->data->eid;
// We only add tell the physics object manager to remove a component if the scene is played
#ifdef _PUBLISH
REMOVED_ID == RIGID_BODY_ID ? objectManager.RemoveRigidBody(EID) : objectManager.RemoveCollider(EID);
#elif SHEDITOR
auto* editor = SHSystemManager::GetSystem<SHEditor>();
if (editor)
{
if (editor->editorState != SHEditor::State::STOP)
REMOVED_ID == RIGID_BODY_ID ? objectManager.RemoveRigidBody(EID) : objectManager.RemoveCollider(EID);
}
#endif
}
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::onPlay(SHEventPtr onPlayEvent)
{
// Create physics world
worldState.CreateWorld(factory);
// Link Collision Listener
collisionListener.BindToWorld(worldState.world);
// Link with object manager & create all physics objects
objectManager.SetWorld(*worldState.world);
const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense<SHRigidBodyComponent>();
const auto& COLLIDER_DENSE = SHComponentManager::GetDense<SHColliderComponent>();
for (auto& rigidBodyComponent : RIGIDBODY_DENSE)
objectManager.AddRigidBody(rigidBodyComponent.GetEID());
for (auto& colliderComponent : COLLIDER_DENSE)
objectManager.AddCollider(colliderComponent.GetEID());
return onPlayEvent->handle;
}
SHEventHandle SHPhysicsSystem::onStop(SHEventPtr onStopEvent)
{
// Remove all physics objects
objectManager.RemoveAllObjects();
// Clear all collision info
// Collision listener is automatically unbound when world is destroyed
collisionListener.ClearContainers();
// Destroy the world
worldState.DestroyWorld(factory);
return onStopEvent->handle;
}
} // namespace SHADE

View File

@ -13,28 +13,29 @@
#include <queue> #include <queue>
#include <unordered_map> #include <unordered_map>
// External Dependencies
#include <reactphysics3d/reactphysics3d.h> #include <reactphysics3d/reactphysics3d.h>
// Project Headers // Project Headers
#include "Components/SHRigidBodyComponent.h"
#include "Components/SHColliderComponent.h"
#include "ECS_Base/System/SHSystemRoutine.h" #include "ECS_Base/System/SHSystemRoutine.h"
#include "ECS_Base/System/SHFixedSystemRoutine.h" #include "ECS_Base/System/SHFixedSystemRoutine.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneGraph.h"
#include "SHPhysicsObject.h" #include "Physics/Collision/SHCollisionListener.h"
#include "SHPhysicsUtils.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Physics/PhysicsObject//SHPhysicsObjectManager.h"
#include "Physics/SHPhysicsWorld.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsSystem final : public SHSystem class SH_API SHPhysicsSystem final : public SHSystem
, public rp3d::EventListener
{ {
private: private:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -44,21 +45,6 @@ namespace SHADE
friend class SHPhysicsDebugDrawSystem; friend class SHPhysicsDebugDrawSystem;
public: public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using CollisionEvents = std::vector<SHCollisionEvent>;
using EntityObjectMap = std::unordered_map<EntityID, SHPhysicsObject>;
struct WorldSettings
{
SHVec3 gravity;
uint16_t numVelocitySolverIterations;
uint16_t numPositionSolverIterations;
bool sleepingEnabled;
};
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */ /* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -69,29 +55,20 @@ namespace SHADE
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] double GetFixedDT () const noexcept; [[nodiscard]] double GetFixedDT () const noexcept;
[[nodiscard]] const SHPhysicsWorldState::WorldSettings& GetWorldSettings () const noexcept;
[[nodiscard]] bool IsSleepingEnabled () const noexcept; [[nodiscard]] const std::vector<SHCollisionInfo>& GetAllCollisionInfo () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllTriggerInfo () const noexcept;
[[nodiscard]] SHVec3 GetWorldGravity () const noexcept;
[[nodiscard]] uint16_t GetNumberVelocityIterations () const noexcept;
[[nodiscard]] uint16_t GetNumberPositionIterations () const noexcept;
[[nodiscard]] const EntityObjectMap& GetPhysicsObjects () const noexcept;
[[nodiscard]] const CollisionEvents& GetCollisionInfo () const noexcept;
[[nodiscard]] const CollisionEvents& GetTriggerInfo () const noexcept;
[[nodiscard]] const SHPhysicsObject* const GetPhysicsObject (EntityID eid) noexcept;
[[nodiscard]] const SHPhysicsObjectManager::PhysicsObjectEntityMap& GetPhysicsObjects () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SetFixedDT (double fixedUpdateRate) noexcept; void SetFixedDT (double fixedUpdateRate) noexcept;
void SetWorldGravity (const SHVec3& gravity) const noexcept; void SetWorldSettings (const SHPhysicsWorldState::WorldSettings& settings) noexcept;
void SetNumberVelocityIterations (uint16_t numVelIterations) const noexcept;
void SetNumberPositionIterations (uint16_t numPosIterations) const noexcept;
void SetSleepingEnabled (bool enableSleeping) const noexcept;
void SetWorldSettings (const WorldSettings& settings) const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
@ -100,11 +77,24 @@ namespace SHADE
void Init () override; void Init () override;
void Exit () override; void Exit () override;
void AddCollisionShape (EntityID entityID, SHCollisionShape* collider); // Specific Handling for Collision Shapes as they are not under the Component System
void RemoveCollisionShape (EntityID entityID, int index);
void onContact (const rp3d::CollisionCallback::CallbackData& callbackData) override; void AddCollisionShape (EntityID eid, int shapeIndex);
void onTrigger (const rp3d::OverlapCallback::CallbackData& callbackData) override; void RemoveCollisionShape (EntityID eid, int shapeIndex);
// Forces are applied from components here. These functions should only be invoked during play (through scripts)
// Thus there is no need to check for an editor.
void AddForce (EntityID eid, const SHVec3& force) noexcept;
void AddForceAtLocalPos (EntityID eid, const SHVec3& force, const SHVec3& localPos) noexcept;
void AddForceAtWorldPos (EntityID eid, const SHVec3& force, const SHVec3& worldPos) noexcept;
void AddRelativeForce (EntityID eid, const SHVec3& relativeForce) noexcept;
void AddRelativeForceAtLocalPos (EntityID eid, const SHVec3& relativeForce, const SHVec3& localPos) noexcept;
void AddRelativeForceAtWorldPos (EntityID eid, const SHVec3& relativeForce, const SHVec3& worldPos) noexcept;
void AddTorque (EntityID eid, const SHVec3& torque) noexcept;
void AddRelativeTorque (EntityID eid, const SHVec3& relativeTorque) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* System Routines */ /* System Routines */
@ -124,6 +114,21 @@ namespace SHADE
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override; void Execute(double dt) noexcept override;
private:
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
static void syncOnPlay(EntityID eid, SHPhysicsObject& physicsObject) noexcept;
static void preUpdateSyncTransform
(
SHPhysicsObject& physicsObject
, SHTransformComponent& transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
) noexcept;
}; };
class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine
@ -156,6 +161,20 @@ namespace SHADE
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override; void Execute(double dt) noexcept override;
private:
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
static void postUpdateSyncTransforms
(
SHPhysicsObject& physicsObject
, SHTransformComponent& transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
, double interpolationFactor
) noexcept;
}; };
private: private:
@ -163,41 +182,31 @@ namespace SHADE
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
bool worldUpdated; // System data
double interpolationFactor; bool worldUpdated;
double fixedDT; double interpolationFactor;
double fixedDT;
rp3d::PhysicsWorld* world; // rp3d
rp3d::PhysicsCommon factory;
EntityObjectMap map; rp3d::PhysicsCommon factory;
CollisionEvents collisionInfo;
CollisionEvents triggerInfo; // Interface objects
SHPhysicsWorldState worldState;
SHPhysicsObjectManager objectManager;
SHCollisionListener collisionListener;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHPhysicsObject* EnsurePhysicsObject (EntityID entityID) noexcept; SHEventHandle addPhysicsComponent (SHEventPtr addComponentEvent) noexcept;
SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept; SHEventHandle removePhysicsComponent (SHEventPtr removeComponentEvent) noexcept;
void DestroyPhysicsObject (EntityID entityID) noexcept;
static void SyncActiveStates (SHPhysicsObject& physicsObject, bool componentActive) noexcept; SHEventHandle onPlay (SHEventPtr onPlayEvent);
void SyncTransforms () noexcept; SHEventHandle onStop (SHEventPtr onStopEvent);
static void UpdateEventContainers (const SHCollisionEvent& collisionEvent, CollisionEvents& container) noexcept;
void ClearInvalidCollisions () noexcept;
SHEventHandle AddPhysicsComponent (SHEventPtr addComponentEvent);
SHEventHandle RemovePhysicsComponent (SHEventPtr removeComponentEvent);
SHEventHandle ResetWorld (SHEventPtr editorStopEvent);
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

@ -16,35 +16,34 @@ of DigiPen Institute of Technology is prohibited.
#include "SHPhysicsSystemInterface.h" #include "SHPhysicsSystemInterface.h"
// Project Includes // Project Includes
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Physics/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
#include "Physics/SHPhysicsUtils.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Static Usage Functions */ /* Static Usage Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
const std::vector<SHCollisionEvent>& SHPhysicsSystemInterface::GetCollisionInfo() noexcept const std::vector<SHCollisionInfo>& SHPhysicsSystemInterface::GetCollisionInfo() noexcept
{ {
static std::vector<SHCollisionEvent> emptyVec; static std::vector<SHCollisionInfo> emptyVec;
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>(); auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (phySystem) if (phySystem)
{ {
return phySystem->GetCollisionInfo(); return phySystem->GetAllCollisionInfo();
} }
SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get collision events. Empty vector returned instead."); SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get collision events. Empty vector returned instead.");
return emptyVec; return emptyVec;
} }
const std::vector<SHCollisionEvent>& SHPhysicsSystemInterface::GetTriggerInfo() noexcept const std::vector<SHCollisionInfo>& SHPhysicsSystemInterface::GetTriggerInfo() noexcept
{ {
static std::vector<SHCollisionEvent> emptyVec; static std::vector<SHCollisionInfo> emptyVec;
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>(); auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (phySystem) if (phySystem)
{ {
return phySystem->GetTriggerInfo(); return phySystem->GetAllTriggerInfo();
} }
SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get trigger events. Empty vector returned instead."); SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get trigger events. Empty vector returned instead.");

View File

@ -19,7 +19,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Forward Declarations */ /* Forward Declarations */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
class SHCollisionEvent; class SHCollisionInfo;
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
@ -39,8 +39,8 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Static Usage Functions */ /* Static Usage Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] static const std::vector<SHCollisionEvent>& GetCollisionInfo() noexcept; [[nodiscard]] static const std::vector<SHCollisionInfo>& GetCollisionInfo() noexcept;
[[nodiscard]] static const std::vector<SHCollisionEvent>& GetTriggerInfo() noexcept; [[nodiscard]] static const std::vector<SHCollisionInfo>& GetTriggerInfo() noexcept;
[[nodiscard]] static double GetFixedDT() noexcept; [[nodiscard]] static double GetFixedDT() noexcept;
}; };
} }

View File

@ -0,0 +1,314 @@
/****************************************************************************************
* \file SHPhysicsSystemRoutines.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for the Physics System Routines
*
* \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.
****************************************************************************************/
#include <SHpch.h>
// Primary Header
#include "SHPhysicsSystem.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h"
#include "Scripting/SHScriptEngine.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsSystem::PhysicsPreUpdate::PhysicsPreUpdate()
: SHSystemRoutine { "Physics PreUpdate", true }
{}
SHPhysicsSystem::PhysicsFixedUpdate::PhysicsFixedUpdate()
: SHFixedSystemRoutine { DEFAULT_FIXED_STEP, "Physics FixedUpdate", false }
{}
SHPhysicsSystem::PhysicsPostUpdate::PhysicsPostUpdate()
: SHSystemRoutine { "Physics PostUpdate", false }
{}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
#ifdef SHEDITOR
auto* editor = SHSystemManager::GetSystem<SHEditor>();
// Only Sync on Play.
// Otherwise, Components are only holding data until the world is built on play.
if (editor)
{
if (editor->editorState != SHEditor::State::STOP)
{
physicsSystem->objectManager.UpdateCommands();
for (auto& [entityID, physicsObject] : physicsSystem->objectManager.physicsObjects)
{
// Ensure a valid physics Object
if (physicsObject.rp3dBody == nullptr)
continue;
syncOnPlay(entityID, physicsObject);
}
}
else
{
auto& rigidBodyDense = SHComponentManager::GetDense<SHRigidBodyComponent>();
auto& colliderDense = SHComponentManager::GetDense<SHColliderComponent>();
for (auto& rigidBodyComponent : rigidBodyDense)
{
const auto* TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(rigidBodyComponent.GetEID());
if (TRANSFORM && TRANSFORM->HasChanged())
{
rigidBodyComponent.position = TRANSFORM->GetWorldPosition();
rigidBodyComponent.orientation = TRANSFORM->GetWorldOrientation();
}
}
for (auto& colliderComponent : colliderDense)
{
const auto* TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(colliderComponent.GetEID());
if (TRANSFORM && TRANSFORM->HasChanged())
{
colliderComponent.position = TRANSFORM->GetWorldPosition();
colliderComponent.orientation = TRANSFORM->GetWorldOrientation();
colliderComponent.scale = TRANSFORM->GetWorldScale();
colliderComponent.RecomputeCollisionShapes();
}
}
}
}
#else
// Always sync Rigid Body & Collider Components with Physics Objects
// Do not check for an editor here
physicsSystem->objectManager.UpdateCommands();
for (auto& [entityID, physicsObject] : physicsSystem->objectManager.physicsObjects)
{
// Ensure a valid physics Object
if (physicsObject.rp3dBody == nullptr)
continue;
syncOnPlay(entityID, physicsObject);
}
#endif
}
void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!");
}
fixedTimeStep = 1.0 / physicsSystem->fixedDT;
accumulatedTime += dt;
int count = 0;
while (accumulatedTime > fixedTimeStep)
{
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteFixedUpdates();
physicsSystem->worldState.world->update(static_cast<rp3d::decimal>(fixedTimeStep));
accumulatedTime -= fixedTimeStep;
++count;
}
stats.numSteps = count;
physicsSystem->worldUpdated = count > 0;
physicsSystem->interpolationFactor = accumulatedTime / fixedTimeStep;
}
void SHPhysicsSystem::PhysicsPostUpdate::Execute(double) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!");
}
// Interpolate transforms for rendering
if (physicsSystem->worldUpdated)
{
for (auto& [entityID, physicsObject] : physicsSystem->objectManager.physicsObjects)
{
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
if (transformComponent)
{
postUpdateSyncTransforms
(
physicsObject
, *transformComponent
, rigidBodyComponent
, colliderComponent
, physicsSystem->interpolationFactor
);
}
}
// Collision & Trigger messages
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteCollisionFunctions();
// Since this function never runs when editor in not in play, execute the function anyway
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::PhysicsPreUpdate::syncOnPlay(EntityID eid, SHPhysicsObject& physicsObject) noexcept
{
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(eid);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(eid);
// Sync transforms & physics components transforms
if (transformComponent && transformComponent->HasChanged())
{
preUpdateSyncTransform
(
physicsObject
, *transformComponent
, rigidBodyComponent
, colliderComponent
);
}
// Sync Rigid Bodies
if (rigidBodyComponent)
physicsObject.SyncRigidBody(*rigidBodyComponent);
// Sync Colliders
if (colliderComponent)
physicsObject.SyncColliders(*colliderComponent);
}
void SHPhysicsSystem::PhysicsPreUpdate::preUpdateSyncTransform
(
SHPhysicsObject& physicsObject
, SHTransformComponent& transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
) noexcept
{
const SHVec3& WORLD_POS = transformComponent.GetWorldPosition();
const SHQuaternion& WORLD_ROT = transformComponent.GetWorldOrientation();
const SHVec3& WORLD_SCL = transformComponent.GetWorldScale();
const rp3d::Transform RP3D_TRANSFORM { WORLD_POS, WORLD_ROT };
physicsObject.GetRigidBody()->setTransform(RP3D_TRANSFORM);
if (rigidBodyComponent)
{
rigidBodyComponent->position = WORLD_POS;
rigidBodyComponent->orientation = WORLD_ROT;
}
if (colliderComponent)
{
colliderComponent->position = WORLD_POS;
colliderComponent->orientation = WORLD_ROT;
colliderComponent->scale = WORLD_SCL;
colliderComponent->RecomputeCollisionShapes();
}
}
void SHPhysicsSystem::PhysicsPostUpdate::postUpdateSyncTransforms
(
SHPhysicsObject& physicsObject
, SHTransformComponent& transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
, double interpolationFactor
) noexcept
{
rp3d::Vector3 rp3dPos;
rp3d::Quaternion rp3dRot;
const rp3d::Transform CURRENT_TF = physicsObject.rp3dBody->getTransform();
// Check if transform should be interpolated
if (rigidBodyComponent)
{
// Skip static bodies
if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
return;
if (rigidBodyComponent->IsInterpolating())
{
// Interpolate transforms between current and predicted next transform
const rp3d::Transform PREV_TF = physicsObject.prevTransform;
const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast<rp3d::decimal>(interpolationFactor));
rp3dPos = INTERPOLATED_TF.getPosition();
rp3dRot = INTERPOLATED_TF.getOrientation();
}
else
{
rp3dPos = CURRENT_TF.getPosition();
rp3dRot = CURRENT_TF.getOrientation();
}
rigidBodyComponent->position = CURRENT_TF.getPosition();
rigidBodyComponent->orientation = CURRENT_TF.getOrientation();
if (colliderComponent)
{
// Sync with colliders
colliderComponent->position = CURRENT_TF.getPosition();
colliderComponent->orientation = CURRENT_TF.getOrientation();
}
}
else
{
rp3dPos = CURRENT_TF.getPosition();
rp3dRot = CURRENT_TF.getOrientation();
}
// Convert RP3D Transform to SHADE
transformComponent.SetWorldPosition(rp3dPos);
transformComponent.SetWorldOrientation(rp3dRot);
// Cache transforms
physicsObject.prevTransform = CURRENT_TF;
}
} // namespace SHADE

View File

@ -24,7 +24,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Events/SHEvent.h" #include "Events/SHEvent.h"
#include "Events/SHEventReceiver.h" #include "Events/SHEventReceiver.h"
#include "Events/SHEventManager.hpp" #include "Events/SHEventManager.hpp"
#include "Physics/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
#include "Physics/SHPhysicsEvents.h"
#include "Assets/SHAssetMacros.h" #include "Assets/SHAssetMacros.h"

View File

@ -14,7 +14,7 @@
#include "Camera/SHCameraComponent.h" #include "Camera/SHCameraComponent.h"
#include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"

View File

@ -3,7 +3,7 @@
#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h"
#include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingBox.h"
#include "Math/Geometry/SHBoundingSphere.h" #include "Math/Geometry/SHBoundingSphere.h"
#include "Physics/SHCollisionShape.h" #include "Physics/Interface/SHCollisionShape.h"
#include "Resource/SHResourceManager.h" #include "Resource/SHResourceManager.h"
#include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec2.h"
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
@ -11,7 +11,7 @@
#include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "Graphics/MiddleEnd/Interface/SHMaterial.h"
#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" #include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h"
#include "SHSerializationTools.h" #include "SHSerializationTools.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
namespace YAML namespace YAML
{ {
using namespace SHADE; using namespace SHADE;

View File

@ -15,7 +15,7 @@ of DigiPen Institute of Technology is prohibited.
#pragma once #pragma once
// External Dependencies // External Dependencies
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
// Project Includes // Project Includes
#include "Components/Component.hxx" #include "Components/Component.hxx"
#include "Math/Vector3.hxx" #include "Math/Vector3.hxx"

View File

@ -15,7 +15,7 @@ of DigiPen Institute of Technology is prohibited.
#pragma once #pragma once
// External Dependencies // External Dependencies
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
// Project Includes // Project Includes
#include "Components/Component.hxx" #include "Components/Component.hxx"

View File

@ -22,8 +22,8 @@ of DigiPen Institute of Technology is prohibited.
// External Dependencies // External Dependencies
#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHEntityManager.h"
#include "Math/Transform/SHTransformComponent.h" #include "Math/Transform/SHTransformComponent.h"
#include "Physics/Components/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Physics/Components/SHRigidBodyComponent.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "Scene/SHSceneGraph.h" #include "Scene/SHSceneGraph.h"
#include "Tools/SHLog.h" #include "Tools/SHLog.h"

View File

@ -16,7 +16,7 @@ of DigiPen Institute of Technology is prohibited.
#include "SHpch.h" #include "SHpch.h"
// External Dependencies // External Dependencies
#include "FRC/SHFramerateController.h" #include "FRC/SHFramerateController.h"
#include "Physics/SHPhysicsSystemInterface.h" #include "Physics/System/SHPhysicsSystemInterface.h"
// Primary Header // Primary Header
#include "Time.hxx" #include "Time.hxx"

View File

@ -28,8 +28,9 @@ of DigiPen Institute of Technology is prohibited.
#include "Engine/Entity.hxx" #include "Engine/Entity.hxx"
#include "Serialisation/ReflectionUtilities.hxx" #include "Serialisation/ReflectionUtilities.hxx"
#include "Engine/Application.hxx" #include "Engine/Application.hxx"
#include "Physics/SHPhysicsSystemInterface.h" #include "Physics/System/SHPhysicsSystemInterface.h"
#include "Physics/SHPhysicsUtils.h" #include "Physics/SHPhysicsEvents.h"
#include "Physics/Collision/SHCollisionInfo.h"
namespace SHADE namespace SHADE
{ {
@ -526,13 +527,13 @@ namespace SHADE
{ {
switch (collisionInfo.GetCollisionState()) switch (collisionInfo.GetCollisionState())
{ {
case SHCollisionEvent::State::ENTER: case SHCollisionInfo::State::ENTER:
script->OnCollisionEnter(info); script->OnCollisionEnter(info);
break; break;
case SHCollisionEvent::State::STAY: case SHCollisionInfo::State::STAY:
script->OnCollisionStay(info); script->OnCollisionStay(info);
break; break;
case SHCollisionEvent::State::EXIT: case SHCollisionInfo::State::EXIT:
script->OnCollisionExit(info); script->OnCollisionExit(info);
break; break;
} }
@ -567,13 +568,13 @@ namespace SHADE
{ {
switch (triggerInfo.GetCollisionState()) switch (triggerInfo.GetCollisionState())
{ {
case SHCollisionEvent::State::ENTER: case SHCollisionInfo::State::ENTER:
script->OnTriggerEnter(info); script->OnTriggerEnter(info);
break; break;
case SHCollisionEvent::State::STAY: case SHCollisionInfo::State::STAY:
script->OnTriggerStay(info); script->OnTriggerStay(info);
break; break;
case SHCollisionEvent::State::EXIT: case SHCollisionInfo::State::EXIT:
script->OnTriggerExit(info); script->OnTriggerExit(info);
break; break;
} }