SP3-2 Physics System restructure & bugfixes #199

Merged
direnbharwani merged 15 commits from SP3-2-Physics into main 2022-11-13 18:53:45 +08:00
49 changed files with 2866 additions and 1834 deletions

View File

@ -4,7 +4,7 @@
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
Camera Component: Camera Component:
Position: {x: 0, y: 0, z: 0} Position: {x: 0, y: 0, z: 8}
Pitch: 0 Pitch: 0
Yaw: 0 Yaw: 0
Roll: 0 Roll: 0
@ -36,8 +36,8 @@
RigidBody Component: RigidBody Component:
Type: Static Type: Static
Mass: 1 Mass: 1
Drag: 0 Drag: 0.00999999978
Angular Drag: 0 Angular Drag: 0.00999999978
Use Gravity: true Use Gravity: true
Interpolate: true Interpolate: true
Freeze Position X: false Freeze Position X: false
@ -56,18 +56,15 @@
Density: 1 Density: 1
Position Offset: {x: 0, y: 0, z: 0} Position Offset: {x: 0, y: 0, z: 0}
Scripts: ~ Scripts: ~
- EID: 2 - EID: 10
Name: Player Name: Default
IsActive: true IsActive: true
NumberOfChildren: 3 NumberOfChildren: 0
Components: Components:
Transform Component: Transform Component:
Translate: {x: -3.06177855, y: -2, z: -5} Translate: {x: -4.40482807, y: 2.57871056, z: -5.21213436}
Rotate: {x: -0, y: 0, z: -0} Rotate: {x: -0.361265004, y: 1.11661232, z: -0.626627684}
Scale: {x: 2, y: 2, z: 2} Scale: {x: 0.999982238, y: 0.999987125, z: 0.999981165}
Renderable Component:
Mesh: 149697411
Material: 126974645
RigidBody Component: RigidBody Component:
Type: Dynamic Type: Dynamic
Mass: 1 Mass: 1
@ -89,7 +86,7 @@
Friction: 0.400000006 Friction: 0.400000006
Bounciness: 0 Bounciness: 0
Density: 1 Density: 1
Position Offset: {x: 0, y: 0.5, z: 0} Position Offset: {x: 0, y: 0, z: 0}
Scripts: ~ Scripts: ~
- EID: 3 - EID: 3
Name: Empty Name: Empty

View File

@ -24,14 +24,15 @@
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
// Systems // Systems
#include "Scripting/SHScriptEngine.h"
#include "Physics/SHPhysicsSystem.h"
#include "Math/Transform/SHTransformSystem.h"
#include "Input/SHInputManager.h"
#include "FRC/SHFramerateController.h"
#include "AudioSystem/SHAudioSystem.h" #include "AudioSystem/SHAudioSystem.h"
#include "Camera/SHCameraSystem.h" #include "Camera/SHCameraSystem.h"
#include "FRC/SHFramerateController.h"
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" #include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
#include "Input/SHInputManager.h"
#include "Math/Transform/SHTransformSystem.h"
#include "Physics/System/SHPhysicsSystem.h"
#include "Physics/System/SHPhysicsDebugDrawSystem.h"
#include "Scripting/SHScriptEngine.h"
// Components // Components
#include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h"
@ -39,7 +40,6 @@
#include "Scenes/SBTestScene.h" #include "Scenes/SBTestScene.h"
#include "Assets/SHAssetManager.h" #include "Assets/SHAssetManager.h"
#include "Scenes/SBMainScene.h" #include "Scenes/SBMainScene.h"
#include "Serialization/Configurations/SHConfigurationManager.h" #include "Serialization/Configurations/SHConfigurationManager.h"
@ -67,16 +67,21 @@ namespace Sandbox
window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow, wndData); window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow, wndData);
// Create Systems // Create Systems
SHSystemManager::CreateSystem<SHGraphicsSystem>();
SHSystemManager::CreateSystem<SHScriptEngine>(); SHSystemManager::CreateSystem<SHScriptEngine>();
SHSystemManager::CreateSystem<SHPhysicsSystem>();
SHSystemManager::CreateSystem<SHTransformSystem>(); SHSystemManager::CreateSystem<SHTransformSystem>();
SHGraphicsSystem* graphicsSystem = static_cast<SHGraphicsSystem*>(SHSystemManager::GetSystem<SHGraphicsSystem>()); SHSystemManager::CreateSystem<SHPhysicsSystem>();
SHSystemManager::CreateSystem<SHPhysicsDebugDrawSystem>();
SHSystemManager::CreateSystem<SHAudioSystem>(); SHSystemManager::CreateSystem<SHAudioSystem>();
SHSystemManager::CreateSystem<SHCameraSystem>(); SHSystemManager::CreateSystem<SHCameraSystem>();
SHSystemManager::CreateSystem<SHDebugDrawSystem>();
SHSystemManager::CreateSystem<SHGraphicsSystem>();
SHGraphicsSystem* graphicsSystem = static_cast<SHGraphicsSystem*>(SHSystemManager::GetSystem<SHGraphicsSystem>());
// Link up SHDebugDraw // Link up SHDebugDraw
SHSystemManager::CreateSystem<SHDebugDrawSystem>();
SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>()); SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>());
#ifdef SHEDITOR #ifdef SHEDITOR
@ -101,7 +106,8 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsDebugDraw>();
SHSystemManager::RegisterRoutine<SHPhysicsDebugDrawSystem, SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine>();
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>(); SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
SHSystemManager::RegisterRoutine<SHDebugDrawSystem, SHDebugDrawSystem::ProcessPointsRoutine>(); SHSystemManager::RegisterRoutine<SHDebugDrawSystem, SHDebugDrawSystem::ProcessPointsRoutine>();
@ -165,7 +171,7 @@ namespace Sandbox
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F10)) if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F10))
{ {
drawColliders = !drawColliders; drawColliders = !drawColliders;
SHSystemManager::GetSystem<SHPhysicsSystem>()->SetDrawColliders(drawColliders); SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDER, drawColliders);
} }
} }
// Finish all graphics jobs first // Finish all graphics jobs first

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"
@ -246,21 +246,21 @@ namespace SHADE
if (collider->GetType() == SHCollisionShape::Type::BOX) if (collider->GetType() == SHCollisionShape::Type::BOX)
{ {
SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
auto box = reinterpret_cast<SHBoundingBox*>(collider->GetShape()); const auto* BOX = reinterpret_cast<const SHBoundingBox*>(collider->GetShape());
SHEditorWidgets::DragVec3 SHEditorWidgets::DragVec3
( (
"Half Extents", { "X", "Y", "Z" }, "Half Extents", { "X", "Y", "Z" },
[box] { return box->GetRelativeExtents(); }, [BOX] { return BOX->GetRelativeExtents(); },
[collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); });
} }
else if (collider->GetType() == SHCollisionShape::Type::SPHERE) else if (collider->GetType() == SHCollisionShape::Type::SPHERE)
{ {
SHEditorWidgets::BeginPanel(std::format("{} Sphere #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); SHEditorWidgets::BeginPanel(std::format("{} Sphere #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
auto sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape()); const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(collider->GetShape());
SHEditorWidgets::DragFloat SHEditorWidgets::DragFloat
( (
"Radius", "Radius",
[sphere] { return sphere->GetRelativeRadius(); }, [SPHERE] { return SPHERE->GetRelativeRadius(); },
[collider](float const& value) { collider->SetBoundingSphere(value); }); [collider](float const& value) { collider->SetBoundingSphere(value); });
} }
else if (collider->GetType() == SHCollisionShape::Type::CAPSULE) else if (collider->GetType() == SHCollisionShape::Type::CAPSULE)

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

@ -60,7 +60,7 @@ namespace SHADE
}); });
for (uint32_t i = 1; i <= SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); ++i) for (uint32_t i = 1; i <= SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES); ++i)
{ {
lightBindings.push_back (SHVkDescriptorSetLayout::Binding lightBindings.push_back (SHVkDescriptorSetLayout::Binding
{ {

View File

@ -317,13 +317,14 @@ namespace SHADE
void SHDebugDrawSystem::drawSphere(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& pos, double radius) void SHDebugDrawSystem::drawSphere(std::vector<PointVertex>& storage, const SHVec4& color, const SHVec3& pos, double radius)
{ {
if (spherePoints.empty()) //if (spherePoints.empty())
{ {
spherePoints.clear();
// Generate // Generate
static const SHMeshData SPHERE = SHPrimitiveGenerator::Sphere(); static const SHMeshData SPHERE = SHPrimitiveGenerator::Sphere();
for (const auto& idx : SPHERE.Indices) for (const auto& idx : SPHERE.Indices)
{ {
spherePoints.emplace_back(SPHERE.VertexPositions[idx] * radius); spherePoints.emplace_back(SPHERE.VertexPositions[idx] * radius + pos);
} }
} }
drawLineSet(storage, color, spherePoints.begin(), spherePoints.end()); drawLineSet(storage, color, spherePoints.begin(), spherePoints.end());

View File

@ -379,7 +379,7 @@ namespace SHADE
SHComponentManager::CreateComponentSparseSet<SHLightComponent>(); SHComponentManager::CreateComponentSparseSet<SHLightComponent>();
logicalDevice = device; logicalDevice = device;
uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES);
std::vector<uint32_t> variableSizes{ NUM_LIGHT_TYPES }; std::vector<uint32_t> variableSizes{ NUM_LIGHT_TYPES };
std::fill (variableSizes.begin(), variableSizes.end(), 1); std::fill (variableSizes.begin(), variableSizes.end(), 1);
@ -431,7 +431,7 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHLightingSubSystem::Run(SHMatrix const& viewMat, uint32_t frameIndex) noexcept void SHLightingSubSystem::Run(SHMatrix const& viewMat, uint32_t frameIndex) noexcept
{ {
static uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); static uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES);
auto& lightComps = SHComponentManager::GetDense<SHLightComponent>(); auto& lightComps = SHComponentManager::GetDense<SHLightComponent>();
bool expanded = false; bool expanded = false;
@ -451,7 +451,7 @@ namespace SHADE
for (auto& light : lightComps) for (auto& light : lightComps)
{ {
auto enumValue = SHUtilities::ToUnderlying(light.GetLightData().type); auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type);
// First we want to make sure the light is already bound to the system. if it // First we want to make sure the light is already bound to the system. if it
// isn't, we write it to the correct buffer. // isn't, we write it to the correct buffer.
@ -491,7 +491,7 @@ namespace SHADE
// is a new buffer. If some expansion was detected, update descriptor sets. // is a new buffer. If some expansion was detected, update descriptor sets.
if (expanded) if (expanded)
{ {
uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ToUnderlying(SH_LIGHT_TYPE::NUM_TYPES); uint32_t constexpr NUM_LIGHT_TYPES = SHUtilities::ConvertEnum(SH_LIGHT_TYPE::NUM_TYPES);
for (uint32_t i = 0; i < NUM_LIGHT_TYPES; ++i) for (uint32_t i = 0; i < NUM_LIGHT_TYPES; ++i)
{ {
UpdateDescSet(i); UpdateDescSet(i);

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 */
@ -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()
@ -88,7 +95,7 @@ namespace SHADE
{ {
case SHCollisionShape::Type::BOX: case SHCollisionShape::Type::BOX:
{ {
auto* box = reinterpret_cast<SHBoundingBox*>(collisionShape.GetShape()); auto* box = reinterpret_cast<SHBoundingBox*>(collisionShape.shape);
const SHVec3& RELATIVE_EXTENTS = box->GetRelativeExtents(); const SHVec3& RELATIVE_EXTENTS = box->GetRelativeExtents();
// Recompute world extents based on new scale and fixed relative extents // Recompute world extents based on new scale and fixed relative extents
@ -99,7 +106,7 @@ namespace SHADE
} }
case SHCollisionShape::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
{ {
auto* sphere = reinterpret_cast<SHBoundingSphere*>(collisionShape.GetShape()); auto* sphere = reinterpret_cast<SHBoundingSphere*>(collisionShape.shape);
const float RELATIVE_RADIUS = sphere->GetRelativeRadius(); const float RELATIVE_RADIUS = sphere->GetRelativeRadius();
// Recompute world radius based on new scale and fixed radius // Recompute world radius based on new scale and fixed radius
@ -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
{ {
@ -164,9 +164,8 @@ namespace SHADE
return rotationOffset; return rotationOffset;
} }
SHShape* SHCollisionShape::GetShape() noexcept const SHShape* SHCollisionShape::GetShape() const noexcept
{ {
dirty = true;
return shape; return shape;
} }

View File

@ -82,7 +82,7 @@ namespace SHADE
[[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept;
[[nodiscard]] const SHVec3& GetRotationOffset () const noexcept; [[nodiscard]] const SHVec3& GetRotationOffset () const noexcept;
[[nodiscard]] SHShape* GetShape () noexcept; [[nodiscard]] const SHShape* GetShape () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */

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
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -110,7 +100,7 @@ namespace SHADE
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;
@ -130,6 +120,8 @@ namespace SHADE
/* 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,12 +139,22 @@ 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
float mass;
float drag;
float angularDrag;
SHVec3 linearVelocity;
SHVec3 angularVelocity;
SHPhysicsSystem* system;
SHVec3 position; SHVec3 position;
SHQuaternion orientation; SHQuaternion orientation;

View File

@ -0,0 +1,359 @@
/****************************************************************************************
* \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;
}
rp3dBody->updateLocalCenterOfMassFromColliders();
rp3dBody->updateLocalInertiaTensorFromColliders();
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 - 1 >= 0)
{
auto* collider = rp3dBody->getCollider(numColliders - 1);
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->updateLocalCenterOfMassFromColliders();
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);
}
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);
}
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:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -57,22 +58,25 @@ namespace SHADE
[[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,301 @@
/****************************************************************************************
* \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 "ECS_Base/Managers/SHEntityManager.h"
#include "Tools/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Data Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObjectManager::CommandFunctionPtr SHPhysicsObjectManager::componentFunc[2][3]
{
addRigidBody , addCollider
, removeRigidBody , removeCollider
, addCollisionShape , removeCollisionShape
};
/*-----------------------------------------------------------------------------------*/
/* 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;
// Get physics components
const PhysicsComponentGroup COMPONENT_GROUP
{
.eid = COMMAND.eid
, .rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(COMMAND.eid)
, .colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(COMMAND.eid)
};
// Delete any object that is missing both components
// We infer that a remove command has been pushed for these, but we will ignore those if both components have already been removed.
if (!COMPONENT_GROUP.rigidBodyComponent && !COMPONENT_GROUP.colliderComponent)
{
destroyPhysicsObject(COMMAND.eid);
continue;
}
// Find the physics Object. If none found and attempting to add, create an object.
SHPhysicsObject* physicsObject = GetPhysicsObject(COMMAND.eid);
if (!physicsObject && COMMAND.command == QueueCommand::Command::ADD)
physicsObject = createPhysicsObject(COMMAND.eid);
componentFunc[SHUtilities::ConvertEnum(COMMAND.command)][SHUtilities::ConvertEnum(COMMAND.component)](COMMAND, physicsObject, COMPONENT_GROUP);
}
}
void SHPhysicsObjectManager::RemoveAllObjects()
{
// Destroy all objects and clear
for (auto& physicsObject : physicsObjects | std::views::values)
{
world->destroyRigidBody(physicsObject.GetRigidBody());
physicsObject.rp3dBody = nullptr;
}
physicsObjects.clear();
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject* SHPhysicsObjectManager::createPhysicsObject(EntityID eid) noexcept
{
// Force transforms to sync
SHVec3 worldPos = SHVec3::Zero;
SHQuaternion worldRot = SHQuaternion::Identity;
const SHTransformComponent* TRANSFORM = nullptr;
if (SHEntityManager::IsValidEID(eid))
TRANSFORM = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
if (TRANSFORM)
{
worldPos = TRANSFORM->GetWorldPosition();
worldRot = TRANSFORM->GetWorldOrientation();
}
const rp3d::Transform RP3D_TRANSFORM{ worldPos, worldRot };
auto& newPhysicsObject = physicsObjects.emplace(eid, SHPhysicsObject{ eid, factory, world }).first->second;
newPhysicsObject.GetRigidBody()->setTransform(RP3D_TRANSFORM);
newPhysicsObject.prevTransform = RP3D_TRANSFORM;
return &newPhysicsObject;
}
void SHPhysicsObjectManager::destroyPhysicsObject(EntityID eid) noexcept
{
const auto ITER = physicsObjects.find(eid);
if (ITER == physicsObjects.end())
{
// Assume the object has already been successfully destroyed
return;
}
world->destroyRigidBody(ITER->second.GetRigidBody());
ITER->second.rp3dBody = nullptr;
physicsObjects.erase(eid);
}
void SHPhysicsObjectManager::addRigidBody(const QueueCommand&, 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(const QueueCommand&, 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;
}
const int NUM_SHAPES = static_cast<int>(componentGroup.colliderComponent->GetCollisionShapes().size());
for (int i = 0; i < NUM_SHAPES; ++i)
physicsObject->AddCollisionShape(i);
physicsObject->SyncColliders(*componentGroup.colliderComponent);
}
void SHPhysicsObjectManager::removeRigidBody(const QueueCommand&, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to remove body!")
if (componentGroup.colliderComponent)
physicsObject->SetStaticBody();
}
void SHPhysicsObjectManager::removeCollider(const QueueCommand&, SHPhysicsObject* physicsObject, const PhysicsComponentGroup&)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to remove collider!")
physicsObject->RemoveAllCollisionShapes();
}
void SHPhysicsObjectManager::addCollisionShape(const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup&)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to add collision shape!")
physicsObject->AddCollisionShape(command.shapeIndex);
}
void SHPhysicsObjectManager::removeCollisionShape(const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup&)
{
SHASSERT(physicsObject != nullptr, "Valid physics object required to remove collision shape!")
physicsObject->RemoveCollisionShape(command.shapeIndex);
}
} // namespace SHADE

View File

@ -0,0 +1,177 @@
/****************************************************************************************
* \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(*)(const QueueCommand&, SHPhysicsObject*, const PhysicsComponentGroup&);
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
static CommandFunctionPtr componentFunc[2][3]; // 2 commands, 3 components
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 (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void addCollider (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void removeRigidBody (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void removeCollider (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void addCollisionShape (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
static void removeCollisionShape (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
};
} // 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<SHBoundingBox*>(collider->GetShape());
rp3d::BoxShape* newBox = factory->createBoxShape(box->GetWorldExtents());
rp3dBody->addCollider(newBox, OFFSETS);
break;
}
case SHCollisionShape::Type::SPHERE:
{
const auto* sphere = reinterpret_cast<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<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<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,856 +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 }
, debugDrawFlags { 0 }
, 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 }
{}
SHPhysicsSystem::PhysicsDebugDraw::PhysicsDebugDraw()
: SHSystemRoutine { "Physics DebugDraw", true }
{}
/*-----------------------------------------------------------------------------------*/
/* 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;
}
bool SHPhysicsSystem::GetDrawColliders() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER);
}
bool SHPhysicsSystem::GetDrawColliderAABBs() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER_AABB);
}
bool SHPhysicsSystem::GetDrawBroadPhase() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::BROAD_PHASE_AABB);
}
bool SHPhysicsSystem::GetDrawContactPoints() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_POINTS);
}
bool SHPhysicsSystem::GetDrawContactNormals() const noexcept
{
return debugDrawFlags & SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_NORMALS);
}
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!")
}
}
void SHPhysicsSystem::SetDrawColliders(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::COLLISION_SHAPE,
shouldDraw
);
}
void SHPhysicsSystem::SetDrawColliderAABBs(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER_AABB);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::COLLIDER_AABB,
shouldDraw
);
}
void SHPhysicsSystem::SetDrawBroadPhase(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::BROAD_PHASE_AABB);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::COLLIDER_BROADPHASE_AABB,
shouldDraw
);
}
void SHPhysicsSystem::SetDrawContactPoints(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_POINTS);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::CONTACT_POINT,
shouldDraw
);
}
void SHPhysicsSystem::SetDrawContactNormals(bool shouldDraw) noexcept
{
static constexpr auto FLAG_VALUE = SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_NORMALS);
shouldDraw ? debugDrawFlags |= FLAG_VALUE : debugDrawFlags &= ~(FLAG_VALUE);
if (world == nullptr)
{
SHLOGV_WARNING("No physics world has been initialised!")
return;
}
world->getDebugRenderer().setIsDebugItemDisplayed
(
rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL,
shouldDraw
);
}
/*-----------------------------------------------------------------------------------*/
/* 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::PhysicsDebugDraw::Execute(double) noexcept
{
const auto* PHYSICS_SYSTEM = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
if (PHYSICS_SYSTEM->debugDrawFlags == 0)
return;
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
if (debugDrawSystem == nullptr)
{
SHLOGV_ERROR("Unable to debug draw physics objects due to missing SHDebugDrawSystem!");
return;
}
const auto& RP3D_DEBUG_RENDERER = PHYSICS_SYSTEM->world->getDebugRenderer();
const auto& LINES = RP3D_DEBUG_RENDERER.getLines();
const auto& TRIANGLES = RP3D_DEBUG_RENDERER.getTriangles();
// Draw all lines
for (uint32_t i = 0; i < RP3D_DEBUG_RENDERER.getNbLines(); ++i)
{
const auto& LINE = LINES[i];
debugDrawSystem->DrawLine(SHColour{ LINE.color1 }, LINE.point1, LINE.point2);
}
for (uint32_t i = 0; i < RP3D_DEBUG_RENDERER.getNbTriangles(); ++i)
{
const auto& TRIANGLE = TRIANGLES[i];
SHColour triColour{ TRIANGLE.color1 };
triColour.a() = 1.0f;
debugDrawSystem->DrawTri(triColour, TRIANGLE.point1, TRIANGLE.point2, TRIANGLE.point3);
}
}
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,207 +0,0 @@
/****************************************************************************************
* \file SHPhysicsSystem.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface 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.
****************************************************************************************/
#pragma once
#include <queue>
#include <unordered_map>
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "Components/SHRigidBodyComponent.h"
#include "Components/SHColliderComponent.h"
#include "ECS_Base/System/SHSystemRoutine.h"
#include "ECS_Base/System/SHFixedSystemRoutine.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneGraph.h"
#include "SHPhysicsObject.h"
#include "SHPhysicsUtils.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsSystem final : public SHSystem
, public rp3d::EventListener
{
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
struct WorldSettings
{
SHVec3 gravity;
uint16_t numVelocitySolverIterations;
uint16_t numPositionSolverIterations;
bool sleepingEnabled;
};
using CollisionEvents = std::vector<SHCollisionEvent>;
enum class DebugDrawFlags : uint8_t
{
COLLIDER = 1
, COLLIDER_AABB = 2
, BROAD_PHASE_AABB = 4
, CONTACT_POINTS = 8
, CONTACT_NORMALS = 16
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsSystem();
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] double GetFixedDT () const noexcept;
[[nodiscard]] bool IsSleepingEnabled () const noexcept;
[[nodiscard]] SHVec3 GetWorldGravity () const noexcept;
[[nodiscard]] uint16_t GetNumberVelocityIterations () const noexcept;
[[nodiscard]] uint16_t GetNumberPositionIterations () const noexcept;
[[nodiscard]] bool GetDrawColliders () const noexcept;
[[nodiscard]] bool GetDrawColliderAABBs () const noexcept;
[[nodiscard]] bool GetDrawBroadPhase () const noexcept;
[[nodiscard]] bool GetDrawContactPoints () const noexcept;
[[nodiscard]] bool GetDrawContactNormals () const noexcept;
[[nodiscard]] const CollisionEvents& GetCollisionInfo () const noexcept;
[[nodiscard]] const CollisionEvents& GetTriggerInfo () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetFixedDT (double fixedUpdateRate) noexcept;
void SetWorldGravity (const SHVec3& gravity) const 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;
// TODO(Diren): Can the debug draw flags be done through an enum?
void SetDrawColliders (bool shouldDraw) noexcept;
void SetDrawColliderAABBs (bool shouldDraw) noexcept;
void SetDrawBroadPhase (bool shouldDraw) noexcept;
void SetDrawContactPoints (bool shouldDraw) noexcept;
void SetDrawContactNormals (bool shouldDraw) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void Init () override;
void Exit () override;
void AddCollisionShape (EntityID entityID, SHCollisionShape* collider);
void RemoveCollisionShape (EntityID entityID, int index);
void onContact (const rp3d::CollisionCallback::CallbackData& callbackData) override;
void onTrigger (const rp3d::OverlapCallback::CallbackData& callbackData) override;
/*---------------------------------------------------------------------------------*/
/* System Routines */
/*---------------------------------------------------------------------------------*/
class SH_API PhysicsPreUpdate final : public SHSystemRoutine
{
public:
PhysicsPreUpdate();
void Execute(double dt) noexcept override;
};
class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine
{
public:
PhysicsFixedUpdate();
void Execute (double dt) noexcept override;
};
class SH_API PhysicsPostUpdate final : public SHSystemRoutine
{
public:
PhysicsPostUpdate();
void Execute(double dt) noexcept override;
};
class SH_API PhysicsDebugDraw final : public SHSystemRoutine
{
public:
PhysicsDebugDraw();
void Execute(double dt) noexcept override;
};
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using EntityObjectMap = std::unordered_map<EntityID, SHPhysicsObject>;
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
bool worldUpdated;
uint8_t debugDrawFlags;
double interpolationFactor;
double fixedDT;
rp3d::PhysicsWorld* world;
rp3d::PhysicsCommon factory;
EntityObjectMap map;
CollisionEvents collisionInfo;
CollisionEvents triggerInfo;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsObject* EnsurePhysicsObject (EntityID entityID) noexcept;
SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept;
void DestroyPhysicsObject (EntityID entityID) noexcept;
static void SyncActiveStates (SHPhysicsObject& physicsObject, bool componentActive) noexcept;
void SyncTransforms () noexcept;
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
#include "SHPhysicsSystem.hpp"

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,71 @@
/****************************************************************************************
* \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;
// These are my preferred default values. QoL for modifying these.
rp3dWorldSettings.defaultBounciness = 0.0f;
rp3dWorldSettings.defaultFrictionCoefficient = 0.4f;
world = factory.createPhysicsWorld(rp3dWorldSettings);
world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::SPLIT_IMPULSES);
}
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 = 15;
uint16_t numPositionSolverIterations = 8;
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,228 @@
/****************************************************************************************
* \file SHPhysicsDebugDrawSystem.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for the Physics Debug Draw 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 "SHPhysicsDebugDrawSystem.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Data Member Definitions */
/*-----------------------------------------------------------------------------------*/
const SHPhysicsDebugDrawSystem::DebugDrawFunction SHPhysicsDebugDrawSystem::drawFunctions[SHPhysicsDebugDrawSystem::NUM_FLAGS] =
{
SHPhysicsDebugDrawSystem::drawColliders
, SHPhysicsDebugDrawSystem::drawColliderAABBs
, SHPhysicsDebugDrawSystem::drawBroadPhaseAABBs
, SHPhysicsDebugDrawSystem::drawContactPoints
, SHPhysicsDebugDrawSystem::drawContactNormals
};
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsDebugDrawSystem::SHPhysicsDebugDrawSystem() noexcept
: debugDrawFlags { 0 }
, physicsSystem { nullptr }
, rp3dDebugRenderer { nullptr }
{
debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER)] =
debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER_AABB)] = SHColour::YELLOW;
debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::BROAD_PHASE_AABB)] = SHColour::CYAN;
debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_POINTS)] = SHColour::RED;
debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::CONTACT_NORMALS)] = SHColour::RED;
}
SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::PhysicsDebugDrawRoutine()
: SHSystemRoutine { "Physics Debug Draw", true }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHPhysicsDebugDrawSystem::GetDebugDrawFlag(DebugDrawFlags flag) const noexcept
{
const auto INT_FLAG = SHUtilities::ConvertEnum(flag);
if (INT_FLAG < 0 || INT_FLAG >= NUM_FLAGS)
{
SHLOG_ERROR("Invalid Debug Draw Flag Passed {} in. Unable to get debug draw state!", INT_FLAG)
return false;
}
return debugDrawFlags & 1U << SHUtilities::ConvertEnum(flag);
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsDebugDrawSystem::SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept
{
const auto INT_FLAG = SHUtilities::ConvertEnum(flag);
if (INT_FLAG < 0 || INT_FLAG >= NUM_FLAGS)
{
SHLOG_ERROR("Invalid Debug Draw Flag Passed {} in. Unable to set debug draw state!", INT_FLAG)
return;
}
value ? (debugDrawFlags |= 1U << INT_FLAG) : (debugDrawFlags &= ~(1U << INT_FLAG));
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsDebugDrawSystem::Init()
{
SystemFamily::GetID<SHPhysicsDebugDrawSystem>();
SHASSERT(physicsSystem == nullptr, "Non-existent physics system attached to the physics debug draw system!")
physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
}
void SHPhysicsDebugDrawSystem::Exit()
{
physicsSystem = nullptr;
}
void SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::Execute(double) noexcept
{
auto* system = reinterpret_cast<SHPhysicsDebugDrawSystem*>(GetSystem());
for (int i = 0; i < SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS); ++i)
{
const bool DRAW = (system->debugDrawFlags & (1U << i)) > 0;
if (DRAW)
drawFunctions[i](system->rp3dDebugRenderer);
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsDebugDrawSystem::drawColliders(rp3d::DebugRenderer* debugRenderer) noexcept
{
const auto& COLLIDER_SET = SHComponentManager::GetDense<SHColliderComponent>();
for (const auto& COLLIDER : COLLIDER_SET)
{
for (auto& collisionShape : COLLIDER.GetCollisionShapes())
{
switch (collisionShape.GetType())
{
case SHCollisionShape::Type::BOX: debugDrawBox(COLLIDER, collisionShape); break;
case SHCollisionShape::Type::SPHERE: debugDrawSphere(COLLIDER, collisionShape); break;
default: break;
}
}
}
}
void SHPhysicsDebugDrawSystem::drawColliderAABBs(rp3d::DebugRenderer* debugRenderer) noexcept
{
}
void SHPhysicsDebugDrawSystem::drawBroadPhaseAABBs(rp3d::DebugRenderer* debugRenderer) noexcept
{
}
void SHPhysicsDebugDrawSystem::drawContactPoints(rp3d::DebugRenderer* debugRenderer) noexcept
{
}
void SHPhysicsDebugDrawSystem::drawContactNormals(rp3d::DebugRenderer* debugRenderer) noexcept
{
}
void SHPhysicsDebugDrawSystem::debugDrawBox(const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept
{
static constexpr uint32_t NUM_BOX_VERTICES = 8;
static const SHVec3 boxVertices[NUM_BOX_VERTICES]
{
{ 0.5f, 0.5f, -0.5f } // TOP_RIGHT_BACK
, { -0.5f, 0.5f, -0.5f } // TOP_LEFT_BACK
, { 0.5f, -0.5f, -0.5f } // BTM_RIGHT_BACK
, { -0.5f, -0.5f, -0.5f } // BTM_LEFT_BACK
, { 0.5f, 0.5f, 0.5f } // TOP_RIGHT_FRONT
, { -0.5f, 0.5f, 0.5f } // TOP_LEFT_FRONT
, { 0.5f, -0.5f, 0.5f } // BTM_RIGHT_FRONT
, { -0.5f, -0.5f, 0.5f } // BTM_LEFT_FRONT
};
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
if (debugDrawSystem == nullptr)
{
SHLOG_ERROR("Unable to get a debug draw system for Physics Debug Drawing!")
return;
}
auto* BOX = reinterpret_cast<const SHBoundingBox*>(collisionShape.GetShape());
// Calculate final position & orientation
const SHVec3 FINAL_POS = colliderComponent.GetPosition() + collisionShape.GetPositionOffset();
const SHQuaternion FINAL_ROT = colliderComponent.GetOrientation() * SHQuaternion::FromEuler(collisionShape.GetRotationOffset());
const SHMatrix BOX_TRS = SHMatrix::Scale(BOX->GetWorldExtents() * 2.0f) * SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(FINAL_POS);
const SHColour COLLIDER_COLOUR = collisionShape.IsTrigger() ? SHColour::PURPLE : SHColour::GREEN;
std::array<SHVec3, NUM_BOX_VERTICES> transformedVertices;
for (uint32_t i = 0; i < NUM_BOX_VERTICES / 2; ++i)
{
const uint32_t IDX1 = i;
const uint32_t IDX2 = i + NUM_BOX_VERTICES / 2;
transformedVertices[IDX1] = SHVec3::Transform(boxVertices[IDX1], BOX_TRS);
transformedVertices[IDX2] = SHVec3::Transform(boxVertices[IDX2], BOX_TRS);
// Draw 4 line to connect the quads
debugDrawSystem->DrawLine(COLLIDER_COLOUR, transformedVertices[IDX1], transformedVertices[IDX2]);
}
// A, B, C, D
std::array backQuad { transformedVertices[0], transformedVertices[1], transformedVertices[3], transformedVertices[2] };
debugDrawSystem->DrawPoly(COLLIDER_COLOUR, backQuad.begin(), backQuad.end());
// E, F, G, H
std::array frontQuad { transformedVertices[4], transformedVertices[5], transformedVertices[7], transformedVertices[6] };
debugDrawSystem->DrawPoly(COLLIDER_COLOUR, frontQuad.begin(), frontQuad.end());
}
void SHPhysicsDebugDrawSystem::debugDrawSphere(const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept
{
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
if (debugDrawSystem == nullptr)
{
SHLOG_ERROR("Unable to get a debug draw system for Physics Debug Drawing!")
return;
}
auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(collisionShape.GetShape());
const SHColour COLLIDER_COLOUR = collisionShape.IsTrigger() ? SHColour::PURPLE : SHColour::GREEN;
// Calculate final position & orientation
const SHVec3 FINAL_POS = colliderComponent.GetPosition() + collisionShape.GetPositionOffset();
debugDrawSystem->DrawSphere(COLLIDER_COLOUR, FINAL_POS, SPHERE->GetWorldRadius());
}
} // namespace SHADE

View File

@ -0,0 +1,123 @@
/****************************************************************************************
* \file SHPhysicsDebugDrawSystem.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for the Physics Debug Draw 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 <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "ECS_Base/System/SHSystemRoutine.h"
#include "Math/SHColour.h"
#include "SHPhysicsSystem.h"
#include "Tools/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsDebugDrawSystem final : public SHSystem
{
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class DebugDrawFlags
{
COLLIDER
, COLLIDER_AABB
, BROAD_PHASE_AABB
, CONTACT_POINTS
, CONTACT_NORMALS
, NUM_FLAGS
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsDebugDrawSystem() noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
bool GetDebugDrawFlag(DebugDrawFlags flag) const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void Init() override;
void Exit() override;
/*---------------------------------------------------------------------------------*/
/* System Routines */
/*---------------------------------------------------------------------------------*/
class SH_API PhysicsDebugDrawRoutine final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsDebugDrawRoutine();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override;
};
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using DebugDrawFunction = void(*)(rp3d::DebugRenderer*) noexcept;
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
static constexpr int NUM_FLAGS = SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS);
static const DebugDrawFunction drawFunctions[NUM_FLAGS];
uint8_t debugDrawFlags;
SHPhysicsSystem* physicsSystem;
rp3d::DebugRenderer* rp3dDebugRenderer;
SHColour debugColours[NUM_FLAGS];
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
static void drawColliders (rp3d::DebugRenderer* debugRenderer) noexcept;
static void drawColliderAABBs (rp3d::DebugRenderer* debugRenderer) noexcept;
static void drawBroadPhaseAABBs (rp3d::DebugRenderer* debugRenderer) noexcept;
static void drawContactPoints (rp3d::DebugRenderer* debugRenderer) noexcept;
static void drawContactNormals (rp3d::DebugRenderer* debugRenderer) noexcept;
static void debugDrawBox (const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept;
static void debugDrawSphere (const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept;
};
} // namespace SHADE

View File

@ -0,0 +1,343 @@
/****************************************************************************************
* \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 "Physics/SHPhysicsEvents.h"
#include "Scene/SHSceneManager.h"
/*-------------------------------------------------------------------------------------*/
/* Local Helper Functions */
/*-------------------------------------------------------------------------------------*/
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)
{
static const auto ADD_SHAPE = [&](EntityID entityID, int index)
{
objectManager.AddCollisionShape(entityID, index);
const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA
{
.entityID = entityID
, .colliderType = SHComponentManager::GetComponent<SHColliderComponent>(entityID)->GetCollisionShape(index).GetType()
, .colliderIndex = index
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
};
#ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
ADD_SHAPE(eid, shapeIndex);
#else
ADD_SHAPE(eid, shapeIndex);
#endif
}
void SHPhysicsSystem::RemoveCollisionShape(EntityID eid, int shapeIndex)
{
static const auto REMOVE_SHAPE = [&](EntityID entityID, int index)
{
objectManager.RemoveCollisionShape(entityID, index);
const SHPhysicsColliderRemovedEvent COLLIDER_REMOVED_EVENT_DATA
{
.entityID = entityID
, .colliderIndex = index
};
SHEventManager::BroadcastEvent<SHPhysicsColliderRemovedEvent>(COLLIDER_REMOVED_EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT);
};
#ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
REMOVE_SHAPE(eid, shapeIndex);
#else
REMOVE_SHAPE(eid, shapeIndex);
#endif
}
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 SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
ADDED_ID == RIGID_BODY_ID ? objectManager.AddRigidBody(EID) : objectManager.AddCollider(EID);
#else
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 SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
REMOVED_ID == RIGID_BODY_ID ? objectManager.RemoveRigidBody(EID) : objectManager.RemoveCollider(EID);
#else
REMOVED_ID == RIGID_BODY_ID ? objectManager.RemoveRigidBody(EID) : objectManager.RemoveCollider(EID);
#endif
}
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::onPlay(SHEventPtr onPlayEvent)
{
static const auto BUILD_PHYSICS_OBJECT = [&](SHSceneNode* node)
{
const EntityID EID = node->GetEntityID();
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(EID))
objectManager.AddRigidBody(EID);
if (SHComponentManager::HasComponent<SHColliderComponent>(EID))
objectManager.AddCollider(EID);
};
////////////////////////////////
// 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& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
SCENE_GRAPH.Traverse(BUILD_PHYSICS_OBJECT);
return onPlayEvent->handle;
}
SHEventHandle SHPhysicsSystem::onStop(SHEventPtr onStopEvent)
{
// Remove all physics objects
objectManager.RemoveAllObjects();
objectManager.SetWorld(nullptr);
// 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

@ -0,0 +1,212 @@
/****************************************************************************************
* \file SHPhysicsSystem.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface 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.
****************************************************************************************/
#pragma once
#include <queue>
#include <unordered_map>
// External Dependencies
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "ECS_Base/System/SHSystemRoutine.h"
#include "ECS_Base/System/SHFixedSystemRoutine.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Physics/Collision/SHCollisionListener.h"
#include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Physics/PhysicsObject//SHPhysicsObjectManager.h"
#include "Physics/SHPhysicsWorld.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsSystem final : public SHSystem
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHPhysicsDebugDrawSystem;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsSystem();
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] double GetFixedDT () const noexcept;
[[nodiscard]] const SHPhysicsWorldState::WorldSettings& GetWorldSettings () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllCollisionInfo () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllTriggerInfo () const noexcept;
[[nodiscard]] const SHPhysicsObject* const GetPhysicsObject (EntityID eid) noexcept;
[[nodiscard]] const SHPhysicsObjectManager::PhysicsObjectEntityMap& GetPhysicsObjects () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetFixedDT (double fixedUpdateRate) noexcept;
void SetWorldSettings (const SHPhysicsWorldState::WorldSettings& settings) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void Init () override;
void Exit () override;
// Specific Handling for Collision Shapes as they are not under the Component System
void AddCollisionShape (EntityID eid, int shapeIndex);
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 */
/*---------------------------------------------------------------------------------*/
class SH_API PhysicsPreUpdate final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsPreUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
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
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsFixedUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute (double dt) noexcept override;
};
class SH_API PhysicsPostUpdate final : public SHSystemRoutine
{
public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsPostUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override;
private:
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
static void postUpdateSyncTransforms
(
SHPhysicsObject& physicsObject
, SHTransformComponent& transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
, double interpolationFactor
) noexcept;
};
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
// System data
bool worldUpdated;
double interpolationFactor;
double fixedDT;
// rp3d
rp3d::PhysicsCommon factory;
// Interface objects
SHPhysicsWorldState worldState;
SHPhysicsObjectManager objectManager;
SHCollisionListener collisionListener;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
SHEventHandle addPhysicsComponent (SHEventPtr addComponentEvent) noexcept;
SHEventHandle removePhysicsComponent (SHEventPtr removeComponentEvent) noexcept;
SHEventHandle onPlay (SHEventPtr onPlayEvent);
SHEventHandle onStop (SHEventPtr onStopEvent);
};
} // namespace SHADE

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,315 @@
/****************************************************************************************
* \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
physicsSystem->collisionListener.CleanContainers();
}
}
/*-----------------------------------------------------------------------------------*/
/* 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

@ -25,7 +25,10 @@ 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 "Scene/SHSceneGraphEvents.h"
#include "Assets/SHAssetMacros.h" #include "Assets/SHAssetMacros.h"
namespace SHADE namespace SHADE

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;
@ -130,14 +130,14 @@ namespace YAML
{ {
case SHCollisionShape::Type::BOX: case SHCollisionShape::Type::BOX:
{ {
auto const bb = reinterpret_cast<SHBoundingBox*>(rhs.GetShape()); const auto* BOX = reinterpret_cast<const SHBoundingBox*>(rhs.GetShape());
node[HalfExtents] = bb->GetRelativeExtents(); node[HalfExtents] = BOX->GetRelativeExtents();
} }
break; break;
case SHCollisionShape::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
{ {
auto const bs = reinterpret_cast<SHBoundingSphere*>(rhs.GetShape()); const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(rhs.GetShape());
node[Radius] = bs->GetRelativeRadius(); node[Radius] = SPHERE->GetRelativeRadius();
} }
break; break;
case SHCollisionShape::Type::CAPSULE: break; case SHCollisionShape::Type::CAPSULE: break;

View File

@ -35,22 +35,12 @@ namespace SHADE
/** /**
* @brief Converts an enum class member from it's type to any other type. * @brief Converts an enum class member from it's type to any other type.
* @tparam InputType Restricted to an enum class * @tparam InputType Restricted to an enum class
* @tparam OutputType The type to convert the enum class member to. Defaults to int. * @tparam OutputType The type to convert the enum class member to. Defaults to the underlying type.
* @param[in] enumClassMember A member of the specified enum class. * @param[in] enumClassMember A member of the specified enum class.
* @returns The value of the enum class member in the output type. * @returns The value of the enum class member in the output type.
*/ */
template <IsEnum InputType, IsIntegral OutputType = std::underlying_type_t<InputType>> template <IsEnum InputType, IsIntegral OutputType = std::underlying_type_t<InputType>>
static constexpr OutputType ConvertEnum(InputType enumClassMember) noexcept; static constexpr OutputType ConvertEnum(InputType enumClassMember) noexcept;
/**
* @brief Converts an enum class member from it's type to the underlying type.
* @tparam Enum Restricted to an enum class
* @param[in] value A member of the specified enum class.
* @returns The value of the enum class member in the output type.
*/
template<typename Enum>
static constexpr typename std::underlying_type_t<Enum> ToUnderlying (Enum value) noexcept;
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -24,11 +24,4 @@ namespace SHADE
{ {
return static_cast<OutputType>(enumClassMember); return static_cast<OutputType>(enumClassMember);
} }
template<typename Enum>
constexpr typename std::underlying_type_t<Enum> SHUtilities::ToUnderlying(Enum value) noexcept
{
return static_cast<typename std::underlying_type_t<Enum>>(value);
}
} // namespace SHADE } // 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/SerialisationUtilities.hxx" #include "Serialisation/SerialisationUtilities.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
{ {
@ -555,13 +556,13 @@ namespace SHADE
Script^ script = entityScripts[i]; Script^ script = entityScripts[i];
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;
} }
@ -597,13 +598,13 @@ namespace SHADE
Script^ script = entityScripts[i]; Script^ script = entityScripts[i];
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;
} }