Refactored Raycasting, Added Layers for Raycasting to C#, Fixed Collision Tag Panel #331

Merged
direnbharwani merged 10 commits from SP3-2-Physics into main 2023-02-03 16:26:07 +08:00
72 changed files with 3691 additions and 4706 deletions
Showing only changes of commit 6a57be2e60 - Show all commits

View File

@ -0,0 +1,210 @@
- EID: 0
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: 7, z: 0}
Rotate: {x: 0, y: 0, z: 0.785398185}
Scale: {x: 0.999999344, y: 0.999999821, z: 0.999999523}
IsActive: true
RigidBody Component:
Type: Dynamic
Drag: 0.00999999978
Angular Drag: 0
Use Gravity: true
Interpolate: true
Sleeping Enabled: true
Freeze Position X: false
Freeze Position Y: false
Freeze Position Z: false
Freeze Rotation X: false
Freeze Rotation Y: false
Freeze Rotation Z: false
IsActive: true
Collider Component:
Colliders:
- Is Trigger: false
Collision Tag: 1
Type: Box
Half Extents: {x: 1, y: 1, z: 1}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true
Scripts:
- Type: PhysicsTestObj
Enabled: true
forceAmount: 200
torqueAmount: 5
- EID: 1
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: 4, z: 0}
Rotate: {x: -0, y: 0, z: -0.436332315}
Scale: {x: 4.5999999, y: 1, z: 1}
IsActive: true
Collider Component:
Colliders:
- Is Trigger: false
Collision Tag: 1
Type: Box
Half Extents: {x: 1, y: 1, z: 1}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true
Scripts: ~
- EID: 2
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Camera Component:
Position: {x: 0, y: 2, z: 7}
Pitch: 0
Yaw: 95
Roll: 0
Width: 1920
Height: 1080
Near: 0.00999999978
Far: 10000
Perspective: true
IsActive: true
Scripts: ~
- EID: 65539
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 2.70000005, y: 0.5, z: 0}
Rotate: {x: -0, y: 0, z: 0.436332315}
Scale: {x: 4.5999999, y: 1, z: 1}
IsActive: true
Collider Component:
Colliders:
- Is Trigger: false
Collision Tag: 1
Type: Box
Half Extents: {x: 1, y: 1, z: 1}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true
Scripts: ~
- EID: 4
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: -1.70000005, z: 0}
Rotate: {x: -0, y: 0, z: 0}
Scale: {x: 10, y: 0.5, z: 10}
IsActive: true
Collider Component:
Colliders:
- Is Trigger: false
Collision Tag: 1
Type: Box
Half Extents: {x: 1, y: 1, z: 1}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true
Scripts: ~
- EID: 5
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: -4.80000019, y: 3, z: 0}
Rotate: {x: -0, y: 0, z: 1.57079637}
Scale: {x: 10, y: 0.5, z: 10}
IsActive: true
Collider Component:
Colliders:
- Is Trigger: false
Collision Tag: 1
Type: Box
Half Extents: {x: 1, y: 1, z: 1}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true
Scripts: ~
- EID: 65542
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 4.80000019, y: 3, z: 0}
Rotate: {x: -0, y: 0, z: 1.57079637}
Scale: {x: 10, y: 0.5, z: 10}
IsActive: true
Collider Component:
Colliders:
- Is Trigger: false
Collision Tag: 1
Type: Box
Half Extents: {x: 1, y: 1, z: 1}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true
Scripts: ~
- EID: 7
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: 0, z: 3}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1}
IsActive: true
RigidBody Component:
Type: Static
Drag: 0.00999999978
Angular Drag: 0.00999999978
Use Gravity: true
Interpolate: true
Sleeping Enabled: true
Freeze Position X: false
Freeze Position Y: false
Freeze Position Z: false
Freeze Rotation X: false
Freeze Rotation Y: false
Freeze Rotation Z: false
IsActive: true
Collider Component:
Colliders:
- Is Trigger: false
Collision Tag: 1
Type: Box
Half Extents: {x: 1, y: 1, z: 1}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true
Scripts: ~

View File

@ -0,0 +1,3 @@
Name: PhysicsTest
ID: 97086054
Type: 5

42
Assets/Scenes/Test.shade Normal file
View File

@ -0,0 +1,42 @@
- EID: 0
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Camera Component:
Position: {x: 0, y: 0, z: 0}
Pitch: 0
Yaw: 0
Roll: 0
Width: 1920
Height: 1080
Near: 0.00999999978
Far: 10000
Perspective: true
IsActive: true
Scripts: ~
- EID: 1
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: 0, z: 0}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1}
IsActive: true
RigidBody Component:
Type: Dynamic
Drag: 0.00999999978
Angular Drag: 0.100000001
Use Gravity: false
Interpolate: true
Sleeping Enabled: true
Freeze Position X: false
Freeze Position Y: false
Freeze Position Z: false
Freeze Rotation X: false
Freeze Rotation Y: false
Freeze Rotation Z: false
IsActive: true
Scripts: ~

View File

@ -0,0 +1,3 @@
Name: Test
ID: 97979840
Type: 5

25
Assets/Scenes/x.shade Normal file
View File

@ -0,0 +1,25 @@
- EID: 65536
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: 0, z: 0}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1}
IsActive: true
RigidBody Component:
Type: Dynamic
Drag: 0.00999999978
Angular Drag: 0.100000001
Use Gravity: false
Interpolate: true
Sleeping Enabled: true
Freeze Position X: false
Freeze Position Y: false
Freeze Position Z: false
Freeze Rotation X: false
Freeze Rotation Y: false
Freeze Rotation Z: false
IsActive: true
Scripts: ~

View File

@ -0,0 +1,3 @@
Name: x
ID: 91446183
Type: 5

View File

@ -119,11 +119,11 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostLogicUpdate>(); SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostLogicUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPreUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
#ifndef _PUBLISH #ifndef _PUBLISH
SHSystemManager::RegisterRoutine<SHPhysicsDebugDrawSystem, SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine>(); SHSystemManager::RegisterRoutine<SHPhysicsDebugDrawSystem, SHPhysicsDebugDrawSystem::PhysicsDebugDraw>();
#endif #endif
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>(); SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
@ -206,27 +206,6 @@ namespace Sandbox
#else #else
SHSystemManager::RunRoutines(false, SHFrameRateController::GetRawDeltaTime()); SHSystemManager::RunRoutines(false, SHFrameRateController::GetRawDeltaTime());
#endif #endif
// TODO: Move into an Editor menu
static bool drawContacts = false;
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F9))
{
drawContacts = !drawContacts;
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_POINTS, drawContacts);
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_NORMALS, drawContacts);
}
static bool drawColliders = false;
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F10))
{
drawColliders = !drawColliders;
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDER, drawColliders);
}
static bool drawRays = false;
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F11))
{
drawRays = !drawRays;
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS, drawRays);
}
} }
// Finish all graphics jobs first // Finish all graphics jobs first
graphicsSystem->AwaitGraphicsExecution(); graphicsSystem->AwaitGraphicsExecution();

View File

@ -44,23 +44,6 @@ namespace Sandbox
{ {
sceneName = SHSerialization::DeserializeSceneFromFile(sceneAssetID); sceneName = SHSerialization::DeserializeSceneFromFile(sceneAssetID);
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!physicsSystem)
{
SHLOGV_CRITICAL("Failed to get the physics system for building the scene!")
return;
}
#ifdef SHEDITOR
physicsSystem->ForceBuild(SHSceneManager::GetCurrentSceneGraph());
#else
physicsSystem->BuildScene(SHSceneManager::GetCurrentSceneGraph());
#endif
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* TESTING CODE */ /* TESTING CODE */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/

View File

@ -92,7 +92,7 @@ namespace Sandbox
floorRigidBody.SetType(SHRigidBodyComponent::Type::STATIC); floorRigidBody.SetType(SHRigidBodyComponent::Type::STATIC);
floorCollider.AddBoundingBox(); //floorCollider.AddBoundingBox();
// Create blank entity with a script // Create blank entity with a script
//testObj = SHADE::SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>(); //testObj = SHADE::SHEntityManager::CreateEntity<SHRenderable, SHTransformComponent>();
@ -113,9 +113,9 @@ namespace Sandbox
racoonTransform.SetWorldScale({ 2.0f, 2.0f, 2.0f }); racoonTransform.SetWorldScale({ 2.0f, 2.0f, 2.0f });
racoonTransform.SetWorldPosition({ -3.0f, -2.0f, -5.0f }); racoonTransform.SetWorldPosition({ -3.0f, -2.0f, -5.0f });
racoonCollider.AddBoundingBox(); //racoonCollider.AddBoundingBox();
racoonCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f,0.5f,0.0f)); racoonCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f,0.5f,0.0f));
racoonCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); //racoonCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f));
auto racoonItemLocation = SHEntityManager::CreateEntity<SHTransformComponent>(); auto racoonItemLocation = SHEntityManager::CreateEntity<SHTransformComponent>();
auto& racoonItemLocationTransform = *SHComponentManager::GetComponent_s<SHTransformComponent>(racoonItemLocation); auto& racoonItemLocationTransform = *SHComponentManager::GetComponent_s<SHTransformComponent>(racoonItemLocation);
@ -138,15 +138,15 @@ namespace Sandbox
itemTransform.SetWorldScale({ 2.0f, 2.0f, 2.0f }); itemTransform.SetWorldScale({ 2.0f, 2.0f, 2.0f });
itemTransform.SetWorldPosition({ 0.0f, -2.0f, -5.0f }); itemTransform.SetWorldPosition({ 0.0f, -2.0f, -5.0f });
itemCollider.AddBoundingBox(); //itemCollider.AddBoundingBox();
itemCollider.AddBoundingBox(SHVec3(2.0f,2.0f,2.0f)); //itemCollider.AddBoundingBox(SHVec3(2.0f,2.0f,2.0f));
itemCollider.GetCollisionShape(1).SetIsTrigger(true); itemCollider.GetCollisionShape(1).SetIsTrigger(true);
itemCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); itemCollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f));
itemCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); //itemCollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f));
itemCollider.GetCollisionShape(1).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); itemCollider.GetCollisionShape(1).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f));
itemCollider.GetCollisionShape(1).SetBoundingBox(SHVec3(1.0f, 1.0f, 1.0f)); //itemCollider.GetCollisionShape(1).SetBoundingBox(SHVec3(1.0f, 1.0f, 1.0f));
itemRigidBody.SetInterpolate(false); itemRigidBody.SetInterpolate(false);
itemRigidBody.SetFreezeRotationX(true); itemRigidBody.SetFreezeRotationX(true);
@ -167,9 +167,9 @@ namespace Sandbox
AITransform.SetWorldScale({ 2.0f, 2.0f, 2.0f }); AITransform.SetWorldScale({ 2.0f, 2.0f, 2.0f });
AITransform.SetWorldPosition({ -8.0f, -2.0f, 2.5f }); AITransform.SetWorldPosition({ -8.0f, -2.0f, 2.5f });
AICollider.AddBoundingBox(); //AICollider.AddBoundingBox();
AICollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f)); AICollider.GetCollisionShape(0).SetPositionOffset(SHVec3(0.0f, 0.5f, 0.0f));
AICollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f)); //AICollider.GetCollisionShape(0).SetBoundingBox(SHVec3(0.5f, 0.5f, 0.5f));
AIRigidBody.SetInterpolate(false); AIRigidBody.SetInterpolate(false);
AIRigidBody.SetFreezeRotationX(true); AIRigidBody.SetFreezeRotationX(true);

View File

@ -10,7 +10,6 @@
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h" #include "Editor/SHEditor.h"
#include "Math/Geometry/SHBox.h"
#include "Math/SHRay.h" #include "Math/SHRay.h"
#include "Physics/System/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
@ -186,25 +185,25 @@ namespace SHADE
//SHLOG_INFO("Ray position: {},{},{} direction:{},{},{}",pivot.ray.position.x, pivot.ray.position.y, pivot.ray.position.z,pivot.ray.direction.x, pivot.ray.direction.y, pivot.ray.direction.z) //SHLOG_INFO("Ray position: {},{},{} direction:{},{},{}",pivot.ray.position.x, pivot.ray.position.y, pivot.ray.position.z,pivot.ray.direction.x, pivot.ray.direction.y, pivot.ray.direction.z)
auto result = physicsSystem->Raycast(pivot.ray ); //auto result = physicsSystem->Raycast(pivot.ray );
if (result && result.distance < pivot.GetArmLength()) //if (result && result.distance < pivot.GetArmLength())
{ //{
//
// SHVec3 newOffset = SHVec3{ 0.0f,0.0f, result.distance * 0.8f };
// newOffset = SHVec3::RotateX(newOffset, -(SHMath::DegreesToRadians(pivot.GetPitch())));
// newOffset = SHVec3::RotateY(newOffset, (SHMath::DegreesToRadians(pivot.GetYaw())));
// pivot.offset = newOffset;
// //SHLOG_INFO("CAMERA COLLISION HIT, {}", result.distance);
//}
//else
//{
// //SHLOG_INFO("CAMERA COLLISION CANT HIT CAMERA");
//}
SHVec3 newOffset = SHVec3{ 0.0f,0.0f, result.distance * 0.8f }; //
newOffset = SHVec3::RotateX(newOffset, -(SHMath::DegreesToRadians(pivot.GetPitch()))); //
newOffset = SHVec3::RotateY(newOffset, (SHMath::DegreesToRadians(pivot.GetYaw())));
pivot.offset = newOffset;
//SHLOG_INFO("CAMERA COLLISION HIT, {}", result.distance);
}
else
{
//SHLOG_INFO("CAMERA COLLISION CANT HIT CAMERA");
}
//// pivot.rtMatrix = SHMatrix::Inverse(pivot.rtMatrix);
// pivot.rtMatrix = SHMatrix::Inverse(pivot.rtMatrix);
} }

View File

@ -1,7 +1,7 @@
#include "SHpch.h" #include "SHpch.h"
#include "SHColliderTagPanel.h" #include "SHColliderTagPanel.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Physics/Collision/SHCollisionTagMatrix.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Editor/SHEditorWidgets.hpp" #include "Editor/SHEditorWidgets.hpp"
namespace SHADE namespace SHADE
@ -15,7 +15,7 @@ namespace SHADE
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::PushID("CollisionTagNames"); ImGui::PushID("CollisionTagNames");
for (int i = SHCollisionTag::NUM_LAYERS; i >= 0; --i) for (int i = SHCollisionTag::NUM_LAYERS; i >= 1; --i)
{ {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if(i == SHCollisionTag::NUM_LAYERS) continue; if(i == SHCollisionTag::NUM_LAYERS) continue;
@ -29,7 +29,7 @@ namespace SHADE
ImGui::PopID(); ImGui::PopID();
} }
ImGui::PopID(); ImGui::PopID();
for (int i = 0; i < SHCollisionTag::NUM_LAYERS; ++i) for (int i = 0; i < SHCollisionTag::NUM_LAYERS - 1; ++i)
{ {
std::string tagName = SHCollisionTagMatrix::GetTagName(i); std::string tagName = SHCollisionTagMatrix::GetTagName(i);
auto tag = SHCollisionTagMatrix::GetTag(i); auto tag = SHCollisionTagMatrix::GetTag(i);
@ -53,8 +53,8 @@ namespace SHADE
tagName2 = std::to_string(idx); tagName2 = std::to_string(idx);
ImGui::TableNextColumn(); ImGui::TableNextColumn();
//if(i == idx) if(i == idx)
// continue; continue;
std::string label = std::format("##{} vs {}", tagName, tagName2); std::string label = std::format("##{} vs {}", tagName, tagName2);
SHEditorWidgets::CheckBox(label, [tag, &idx]{return tag->GetLayerState(idx);}, [tag, i, idx](bool const& value){tag->SetLayerState(idx, value); SHCollisionTagMatrix::GetTag(idx)->SetLayerState(i, value);}, label.substr(2)); SHEditorWidgets::CheckBox(label, [tag, &idx]{return tag->GetLayerState(idx);}, [tag, i, idx](bool const& value){tag->SetLayerState(idx, value); SHCollisionTagMatrix::GetTag(idx)->SetLayerState(i, value);}, label.substr(2));
} }

View File

@ -18,12 +18,13 @@
#include "Physics/Interface/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Reflection/SHReflectionMetadata.h" #include "Reflection/SHReflectionMetadata.h"
#include "Resource/SHResourceManager.h" #include "Resource/SHResourceManager.h"
#include "Physics/Collision/SHCollisionTagMatrix.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Serialization/SHSerializationHelper.hpp" #include "Serialization/SHSerializationHelper.hpp"
#include "Tools/Utilities/SHClipboardUtilities.h" #include "Tools/Utilities/SHClipboardUtilities.h"
#include "SHInspectorCommands.h" #include "SHInspectorCommands.h"
#include "Physics/Collision/SHCollisionTagMatrix.h"
#include "Animation/SHAnimatorComponent.h" #include "Animation/SHAnimatorComponent.h"
#include "Physics/Collision/Shapes/SHBox.h"
#include "Physics/Collision/Shapes/SHSphere.h"
namespace SHADE namespace SHADE
{ {
template<typename T> template<typename T>
@ -302,7 +303,7 @@ namespace SHADE
{ {
SHEditorWidgets::DragVec3("Force", { "X", "Y", "Z" }, [component] {return component->GetForce(); }, [](SHVec3 const& value) {}, false, "Force", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); SHEditorWidgets::DragVec3("Force", { "X", "Y", "Z" }, [component] {return component->GetForce(); }, [](SHVec3 const& value) {}, false, "Force", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly);
SHEditorWidgets::DragVec3("Torque", { "X", "Y", "Z" }, [component] {return component->GetTorque(); }, [](SHVec3 const& value) {}, false, "Torque", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly); SHEditorWidgets::DragVec3("Torque", { "X", "Y", "Z" }, [component] {return component->GetTorque(); }, [](SHVec3 const& value) {}, false, "Torque", 0.1f, "%.3f", 0.0f, 0.0f, ImGuiSliderFlags_ReadOnly);
SHEditorWidgets::CheckBox("Is Asleep", [component] {return component->GetIsSleeping(); }, [](bool value) {}, "If the Rigid Body is asleep"); SHEditorWidgets::CheckBox("Is Asleep", [component] {return component->IsSleeping(); }, [](bool value) {}, "If the Rigid Body is asleep");
} }
} }
@ -334,6 +335,8 @@ namespace SHADE
{ {
DrawContextMenu(component); DrawContextMenu(component);
SHEditorWidgets::CheckBox("Draw Colliders", [component] { return component->GetDebugDrawState(); }, [component](bool value) { component->SetDebugDrawState(value); });
auto& colliders = component->GetCollisionShapes(); auto& colliders = component->GetCollisionShapes();
int const size = static_cast<int>(colliders.size()); int const size = static_cast<int>(colliders.size());
ImGui::BeginChild("Collision Shapes", { 0.0f, colliders.empty() ? 1.0f : 250.0f }, true); ImGui::BeginChild("Collision Shapes", { 0.0f, colliders.empty() ? 1.0f : 250.0f }, true);
@ -341,57 +344,57 @@ namespace SHADE
for (int i{}; i < size; ++i) for (int i{}; i < size; ++i)
{ {
ImGui::PushID(i); ImGui::PushID(i);
SHCollisionShape* collider = &component->GetCollisionShape(i); SHCollisionShape* collisionShape = &component->GetCollisionShape(i);
auto cursorPos = ImGui::GetCursorPos(); auto cursorPos = ImGui::GetCursorPos();
if (collider->GetType() == SHCollisionShape::Type::BOX) if (collisionShape->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 });
const auto* BOX = reinterpret_cast<const SHBox*>(collider->GetShape()); auto* boxShape = dynamic_cast<SHBox*>(collisionShape);
SHEditorWidgets::DragVec3 SHEditorWidgets::DragVec3
( (
"Half Extents", { "X", "Y", "Z" }, "Half Extents", { "X", "Y", "Z" },
[BOX] { return BOX->GetRelativeExtents(); }, [boxShape] { return boxShape->GetRelativeExtents(); },
[collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); [boxShape](SHVec3 const& vec) { boxShape->SetRelativeExtents(vec); });
} }
else if (collider->GetType() == SHCollisionShape::Type::SPHERE) else if (collisionShape->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 });
const auto* SPHERE = reinterpret_cast<const SHSphere*>(collider->GetShape()); auto* sphereShape = dynamic_cast<SHSphere*>(collisionShape);
SHEditorWidgets::DragFloat SHEditorWidgets::DragFloat
( (
"Radius", "Radius",
[SPHERE] { return SPHERE->GetRelativeRadius(); }, [sphereShape] { return sphereShape->GetRelativeRadius(); },
[collider](float const& value) { collider->SetBoundingSphere(value); }); [sphereShape](float const& value) { sphereShape->SetRelativeRadius(value); });
} }
else if (collider->GetType() == SHCollisionShape::Type::CAPSULE) //else if (collisionShape->GetType() == SHCollisionShape::Type::CAPSULE)
{ //{
} //}
{ {
SHEditorWidgets::CheckBox("Is Trigger", [collider] { return collider->IsTrigger(); }, [collider](bool value) { collider->SetIsTrigger(value); }); SHEditorWidgets::CheckBox("Is Trigger", [collisionShape] { return collisionShape->IsTrigger(); }, [collisionShape](bool value) { collisionShape->SetIsTrigger(value); });
SHEditorWidgets::ComboBox("Tag", collisionTagNames, [collider]{return SHCollisionTagMatrix::GetTagIndex(collider->GetCollisionTag().GetName());}, [collider](int const& value){collider->SetCollisionTag(SHCollisionTagMatrix::GetTag(value));}); SHEditorWidgets::ComboBox("Tag", collisionTagNames, [collisionShape]{return SHCollisionTagMatrix::GetTagIndex(collisionShape->GetCollisionTag().GetName());}, [collisionShape](int const& value){collisionShape->SetCollisionTag(SHCollisionTagMatrix::GetTag(value));});
if(ImGui::CollapsingHeader("Physics Material")) if(ImGui::CollapsingHeader("Physics Material"))
{ {
SHEditorWidgets::DragFloat("Friction", [collider] { return collider->GetFriction(); }, [collider](float value) { collider->SetFriction(value); }, "Friction", 0.05f, 0.0f, 1.0f); SHEditorWidgets::DragFloat("Friction", [collisionShape] { return collisionShape->GetFriction(); }, [collisionShape](float value) { collisionShape->SetFriction(value); }, "Friction", 0.05f, 0.0f, 1.0f);
SHEditorWidgets::DragFloat("Bounciness", [collider] { return collider->GetBounciness(); }, [collider](float value) { collider->SetBounciness(value); }, "Bounciness", 0.05f, 0.0f, 1.0f); SHEditorWidgets::DragFloat("Bounciness", [collisionShape] { return collisionShape->GetBounciness(); }, [collisionShape](float value) { collisionShape->SetBounciness(value); }, "Bounciness", 0.05f, 0.0f, 1.0f);
SHEditorWidgets::DragFloat("Mass Density", [collider] { return collider->GetDensity(); }, [collider](float value) { collider->SetDensity(value); }, "Mass Density", 0.1f, 0.0f); SHEditorWidgets::DragFloat("Mass Density", [collisionShape] { return collisionShape->GetDensity(); }, [collisionShape](float value) { collisionShape->SetDensity(value); }, "Mass Density", 0.1f, 0.0f);
} }
SHEditorWidgets::BeginPanel("Offsets",{ ImGui::GetContentRegionAvail().x, 30.0f }); SHEditorWidgets::BeginPanel("Offsets",{ ImGui::GetContentRegionAvail().x, 30.0f });
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); }); SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collisionShape] {return collisionShape->GetPositionOffset(); }, [&collisionShape](SHVec3 const& vec) {collisionShape->SetPositionOffset(vec); });
SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" }, SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" },
[&collider] [&collisionShape]
{ {
auto offset = collider->GetRotationOffset(); auto offset = collisionShape->GetRotationOffset();
return offset; return offset;
}, },
[&collider](SHVec3 const& vec) [&collisionShape](SHVec3 const& vec)
{ {
collider->SetRotationOffset(vec); collisionShape->SetRotationOffset(vec);
}, true); }, true);
SHEditorWidgets::EndPanel(); SHEditorWidgets::EndPanel();
} }
@ -406,7 +409,7 @@ namespace SHADE
} }
if (colliderToDelete.has_value()) if (colliderToDelete.has_value())
{ {
component->RemoveCollider(colliderToDelete.value()); component->RemoveCollisionShape(colliderToDelete.value());
} }
ImGui::EndChild(); ImGui::EndChild();
@ -416,11 +419,11 @@ namespace SHADE
if (ImGui::Selectable("Box Collider")) if (ImGui::Selectable("Box Collider"))
{ {
newColl = component->AddBoundingBox(); newColl = component->AddBoxCollisionShape(SHVec3::One);
} }
if (ImGui::Selectable("Sphere Collider")) if (ImGui::Selectable("Sphere Collider"))
{ {
newColl = component->AddBoundingSphere(); newColl = component->AddSphereCollisionShape(1.0f);
} }
//No idea why this doesn't work //No idea why this doesn't work

View File

@ -25,6 +25,7 @@
#include "Serialization/SHSerialization.h" #include "Serialization/SHSerialization.h"
#include "Serialization/Configurations/SHConfigurationManager.h" #include "Serialization/Configurations/SHConfigurationManager.h"
#include "Editor/EditorWindow/SHEditorWindowManager.h" #include "Editor/EditorWindow/SHEditorWindowManager.h"
#include "Physics/System/SHPhysicsDebugDrawSystem.h"
const std::string LAYOUT_FOLDER_PATH{ std::string(ASSET_ROOT) + "/Editor/Layouts" }; const std::string LAYOUT_FOLDER_PATH{ std::string(ASSET_ROOT) + "/Editor/Layouts" };
@ -88,6 +89,7 @@ namespace SHADE
DrawThemeMenu(); DrawThemeMenu();
DrawLayoutMenu(); DrawLayoutMenu();
DrawApplicationConfig(); DrawApplicationConfig();
DrawPhysicsSettings();
std::string const sceneName{std::format("Current Scene: {}",SHSceneManager::GetSceneName().data())}; std::string const sceneName{std::format("Current Scene: {}",SHSceneManager::GetSceneName().data())};
auto const size = ImGui::CalcTextSize(sceneName.data()); auto const size = ImGui::CalcTextSize(sceneName.data());
@ -304,4 +306,27 @@ namespace SHADE
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
void SHEditorMenuBar::DrawPhysicsSettings() noexcept
{
if (ImGui::BeginMenu("Physics Settings"))
{
if (auto* physicsDebugDraw = SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>())
{
bool drawColliders = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDERS);
if (ImGui::Checkbox("Draw Colliders", &drawColliders))
physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::COLLIDERS, drawColliders);
bool drawContactPoints = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACTS);
if (ImGui::Checkbox("Draw Contact Points", &drawContactPoints))
physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACTS, drawContactPoints);
bool drawRays = physicsDebugDraw->GetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS);
if (ImGui::Checkbox("Draw Rays", &drawRays))
physicsDebugDraw->SetFlagState(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS, drawRays);
}
ImGui::EndMenu();
}
}
}//namespace SHADE }//namespace SHADE

View File

@ -25,6 +25,7 @@ namespace SHADE
void DrawThemeMenu() noexcept; void DrawThemeMenu() noexcept;
void DrawLayoutMenu() noexcept; void DrawLayoutMenu() noexcept;
void DrawApplicationConfig() noexcept; void DrawApplicationConfig() noexcept;
void DrawPhysicsSettings() noexcept;
float menuBarHeight = 20.0f; float menuBarHeight = 20.0f;
std::vector<std::filesystem::path> layoutPaths; std::vector<std::filesystem::path> layoutPaths;

View File

@ -24,4 +24,5 @@ constexpr SHEventIdentifier SH_SCENE_EXIT_PRE { 15 };
constexpr SHEventIdentifier SH_SCENE_EXIT_POST { 16 }; constexpr SHEventIdentifier SH_SCENE_EXIT_POST { 16 };
constexpr SHEventIdentifier SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT { 17 }; constexpr SHEventIdentifier SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT { 17 };
constexpr SHEventIdentifier SH_BUTTON_CLICK_EVENT { 18 }; constexpr SHEventIdentifier SH_BUTTON_CLICK_EVENT { 18 };
constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_DRAW_EVENT { 19 };

View File

@ -1,250 +0,0 @@
/****************************************************************************************
* \file SHBox.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a 3-Dimensional Axis Aligned Bounding Box
*
* \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 "SHBox.h"
// Project Headers
#include "Math/SHMathHelpers.h"
#include "Math/SHRay.h"
using namespace DirectX;
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHBox::SHBox() noexcept
: RelativeExtents { SHVec3::One }
{
type = Type::BOX;
}
SHBox::SHBox(const SHVec3& c, const SHVec3& hE) noexcept
: RelativeExtents { SHVec3::One }
{
type = Type::BOX;
Center = c;
Extents = hE;
}
SHBox::SHBox(const SHBox& rhs) noexcept
{
if (this == &rhs)
return;
type = Type::BOX;
Center = rhs.Center;
Extents = rhs.Extents;
RelativeExtents = rhs.RelativeExtents;
}
SHBox::SHBox(SHBox&& rhs) noexcept
{
type = Type::BOX;
Center = rhs.Center;
Extents = rhs.Extents;
RelativeExtents = rhs.RelativeExtents;
}
/*-----------------------------------------------------------------------------------*/
/* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/
SHBox& SHBox::operator=(const SHBox& rhs) noexcept
{
if (rhs.type != Type::BOX)
{
SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!")
}
else if (this != &rhs)
{
Center = rhs.Center;
Extents = rhs.Extents;
RelativeExtents = rhs.RelativeExtents;
}
return *this;
}
SHBox& SHBox::operator=(SHBox&& rhs) noexcept
{
if (rhs.type != Type::BOX)
{
SHLOG_WARNING("Cannot assign a non-bounding box to a bounding box!")
}
else
{
Center = rhs.Center;
Extents = rhs.Extents;
RelativeExtents = rhs.RelativeExtents;
}
return *this;
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHVec3 SHBox::GetCenter() const noexcept
{
return Center;
}
SHVec3 SHBox::GetWorldExtents() const noexcept
{
return Extents;
}
const SHVec3& SHBox::GetRelativeExtents() const noexcept
{
return RelativeExtents;
}
SHVec3 SHBox::GetMin() const noexcept
{
return SHVec3{ Center.x - Extents.x, Center.y - Extents.y, Center.z - Extents.z };
}
SHVec3 SHBox::GetMax() const noexcept
{
return SHVec3{ Center.x + Extents.x, Center.y + Extents.y, Center.z + Extents.z };
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHBox::SetCenter(const SHVec3& newCenter) noexcept
{
Center = newCenter;
}
void SHBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept
{
Extents = newWorldExtents;
}
void SHBox::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept
{
RelativeExtents = newRelativeExtents;
}
void SHBox::SetMin(const SHVec3& min) noexcept
{
const SHVec3 MAX = GetMax();
Center = SHVec3::Lerp(min, MAX, 0.5f);
Extents = SHVec3::Abs((MAX - min) * 0.5f);
}
void SHBox::SetMax(const SHVec3& max) noexcept
{
const SHVec3 MIN = GetMin();
Center = SHVec3::Lerp(MIN, max, 0.5f);
Extents = SHVec3::Abs((max - MIN) * 0.5f);
}
void SHBox::SetMinMax(const SHVec3& min, const SHVec3& max) noexcept
{
Center = SHVec3::Lerp(min, max, 0.5f);
Extents = SHVec3::Abs((max - min) * 0.5f);
}
std::vector<SHVec3> SHBox::GetVertices() const noexcept
{
std::vector<SHVec3> vertices{ 8 };
GetCorners(vertices.data());
return vertices;
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHBox::TestPoint(const SHVec3& point) const noexcept
{
return BoundingBox::Contains(point);
}
SHRaycastResult SHBox::Raycast(const SHRay& ray) const noexcept
{
SHRaycastResult result;
result.hit = Intersects(ray.position, ray.direction, result.distance);
if (result.hit)
{
result.position = ray.position + ray.direction * result.distance;
result.angle = SHVec3::Angle(ray.position, result.position);
}
return result;
}
bool SHBox::Contains(const SHBox& rhs) const noexcept
{
return BoundingBox::Contains(rhs);
}
float SHBox::Volume() const noexcept
{
return 8.0f * (Extents.x * Extents.y * Extents.z);
}
float SHBox::SurfaceArea() const noexcept
{
return 8.0f * ((Extents.x * Extents.y)
+ (Extents.x * Extents.z)
+ (Extents.y * Extents.z));
}
/*-----------------------------------------------------------------------------------*/
/* Static Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHBox SHBox::Combine(const SHBox& lhs, const SHBox& rhs) noexcept
{
SHBox result;
CreateMerged(result, lhs, rhs);
return result;
}
bool SHBox::Intersect(const SHBox& lhs, const SHBox& rhs) noexcept
{
return lhs.Intersects(rhs);
}
SHBox SHBox::BuildFromBoxes(const SHBox* boxes, size_t numBoxes) noexcept
{
SHBox result;
for (size_t i = 1; i < numBoxes; ++i)
CreateMerged(result, boxes[i - 1], boxes[i]);
return result;
}
SHBox SHBox::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept
{
SHBox result;
CreateFromPoints(result, numVertices, vertices, stride);
return result;
}
} // namespace SHADE

View File

@ -1,105 +0,0 @@
/****************************************************************************************
* \file SHBox.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a 3-Dimensional Axis Aligned Bounding Box
*
* \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 <DirectXCollision.h>
// Project Headers
#include "SHShape.h"
#include "SH_API.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHBox : public SHShape,
private DirectX::BoundingBox
{
public:
/*---------------------------------------------------------------------------------*/
/* Static Data Members */
/*---------------------------------------------------------------------------------*/
static constexpr size_t NUM_VERTICES = 8;
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
~SHBox () override = default;
SHBox () noexcept;
SHBox (const SHVec3& center, const SHVec3& halfExtents) noexcept;
SHBox (const SHBox& rhs) noexcept;
SHBox (SHBox&& rhs) noexcept;
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
SHBox& operator= (const SHBox& rhs) noexcept;
SHBox& operator= (SHBox&& rhs) noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] SHVec3 GetCenter () const noexcept;
[[nodiscard]] SHVec3 GetWorldExtents () const noexcept;
[[nodiscard]] const SHVec3& GetRelativeExtents () const noexcept;
[[nodiscard]] SHVec3 GetMin () const noexcept;
[[nodiscard]] SHVec3 GetMax () const noexcept;
[[nodiscard]] std::vector<SHVec3> GetVertices () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetCenter (const SHVec3& newCenter) noexcept;
void SetWorldExtents (const SHVec3& newWorldExtents) noexcept;
void SetRelativeExtents (const SHVec3& newRelativeExtents) noexcept;
void SetMin (const SHVec3& min) noexcept;
void SetMax (const SHVec3& max) noexcept;
void SetMinMax (const SHVec3& min, const SHVec3& max) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override;
[[nodiscard]] SHRaycastResult Raycast(const SHRay& ray) const noexcept override;
[[nodiscard]] bool Contains (const SHBox& rhs) const noexcept;
[[nodiscard]] float Volume () const noexcept;
[[nodiscard]] float SurfaceArea () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Static Function Members */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] static SHBox Combine (const SHBox& lhs, const SHBox& rhs) noexcept;
[[nodiscard]] static bool Intersect (const SHBox& lhs, const SHBox& rhs) noexcept;
[[nodiscard]] static SHBox BuildFromBoxes (const SHBox* boxes, size_t numBoxes) noexcept;
[[nodiscard]] static SHBox BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
SHVec3 RelativeExtents;
};
} // namespace SHADE

View File

@ -1,208 +0,0 @@
/****************************************************************************************
* \file SHBoundingSphere.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Bounding Sphere
*
* \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 "SHSphere.h"
// Project Headers
#include "Math/SHMathHelpers.h"
#include "Math/SHRay.h"
using namespace DirectX;
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHSphere::SHSphere() noexcept
: RelativeRadius { 1.0f }
{
type = Type::SPHERE;
}
SHSphere::SHSphere(const SHVec3& center, float radius) noexcept
: RelativeRadius { 1.0f }
{
type = Type::SPHERE;
Center = center;
Radius = radius;
}
SHSphere::SHSphere(const SHSphere& rhs) noexcept
{
if (this == &rhs)
return;
type = Type::SPHERE;
Center = rhs.Center;
Radius = rhs.Radius;
RelativeRadius = rhs.RelativeRadius;
}
SHSphere::SHSphere(SHSphere&& rhs) noexcept
{
type = Type::SPHERE;
Center = rhs.Center;
Radius = rhs.Radius;
RelativeRadius = rhs.RelativeRadius;
}
/*-----------------------------------------------------------------------------------*/
/* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/
SHSphere& SHSphere::operator=(const SHSphere& rhs) noexcept
{
if (rhs.type != Type::SPHERE)
{
SHLOG_WARNING("Cannot assign a non-sphere to a sphere!")
}
else if (this != &rhs)
{
Center = rhs.Center;
Radius = rhs.Radius;
RelativeRadius = rhs.RelativeRadius;
}
return *this;
}
SHSphere& SHSphere::operator=(SHSphere&& rhs) noexcept
{
if (rhs.type != Type::SPHERE)
{
SHLOG_WARNING("Cannot assign a non-sphere to a sphere!")
}
else
{
Center = rhs.Center;
Radius = rhs.Radius;
RelativeRadius = rhs.RelativeRadius;
}
return *this;
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHVec3 SHSphere::GetCenter() const noexcept
{
return Center;
}
float SHSphere::GetWorldRadius() const noexcept
{
return Radius;
}
float SHSphere::GetRelativeRadius() const noexcept
{
return RelativeRadius;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHSphere::SetCenter(const SHVec3& center) noexcept
{
Center = center;
}
void SHSphere::SetWorldRadius(float newWorldRadius) noexcept
{
Radius = newWorldRadius;
}
void SHSphere::SetRelativeRadius(float newRelativeRadius) noexcept
{
RelativeRadius = newRelativeRadius;
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHSphere::TestPoint(const SHVec3& point) const noexcept
{
return BoundingSphere::Contains(point);
}
SHRaycastResult SHSphere::Raycast(const SHRay& ray) const noexcept
{
SHRaycastResult result;
result.hit = Intersects(ray.position, ray.direction, result.distance);
if (result.hit)
{
result.position = ray.position + ray.direction * result.distance;
result.angle = SHVec3::Angle(ray.position, result.position);
}
return result;
}
bool SHSphere::Contains(const SHSphere& rhs) const noexcept
{
return BoundingSphere::Contains(rhs);
}
float SHSphere::Volume() const noexcept
{
return (4.0f / 3.0f) * SHMath::PI * (Radius * Radius * Radius);
}
float SHSphere::SurfaceArea() const noexcept
{
return 4.0f * SHMath::PI * (Radius * Radius);
}
/*-----------------------------------------------------------------------------------*/
/* Static Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHSphere SHSphere::Combine(const SHSphere& lhs, const SHSphere& rhs) noexcept
{
SHSphere result;
CreateMerged(result, lhs, rhs);
return result;
}
bool SHSphere::Intersect(const SHSphere& lhs, const SHSphere& rhs) noexcept
{
return lhs.Intersects(rhs);
}
SHSphere SHSphere::BuildFromSpheres(const SHSphere* spheres, size_t numSpheres) noexcept
{
SHSphere result;
for (size_t i = 1; i < numSpheres; ++i)
CreateMerged(result, spheres[i - 1], spheres[i]);
return result;
}
SHSphere SHSphere::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept
{
SHSphere result;
CreateFromPoints(result, numVertices, vertices, stride);
return result;
}
} // namespace SHADE

View File

@ -10,6 +10,8 @@
#include <SHpch.h> #include <SHpch.h>
#include <reactphysics3d/mathematics/Ray.h>
// Primary Header // Primary Header
#include "SHRay.h" #include "SHRay.h"
@ -30,7 +32,7 @@ namespace SHADE
, direction { dir } , direction { dir }
{} {}
SHRay::SHRay(const reactphysics3d::Ray rp3dRay) noexcept SHRay::SHRay(const reactphysics3d::Ray& rp3dRay) noexcept
: position { rp3dRay.point1 } : position { rp3dRay.point1 }
, direction { SHVec3::Normalise(rp3dRay.point2 - rp3dRay.point1) } , direction { SHVec3::Normalise(rp3dRay.point2 - rp3dRay.point1) }
{} {}

View File

@ -16,8 +16,13 @@
#include "SH_API.h" #include "SH_API.h"
#include "Vector/SHVec3.h" #include "Vector/SHVec3.h"
/*-------------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-------------------------------------------------------------------------------------*/
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -40,7 +45,7 @@ namespace SHADE
SHRay () noexcept; SHRay () noexcept;
SHRay (const SHVec3& pos, const SHVec3& dir) noexcept; SHRay (const SHVec3& pos, const SHVec3& dir) noexcept;
SHRay (const reactphysics3d::Ray rp3dRay) noexcept; SHRay (const reactphysics3d::Ray& rp3dRay) noexcept;
SHRay (const SHRay&) noexcept = default; SHRay (const SHRay&) noexcept = default;
SHRay (SHRay&& ) noexcept = default; SHRay (SHRay&& ) noexcept = default;

View File

@ -1,350 +0,0 @@
/****************************************************************************************
* \file SHPhysicsRaycaster.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics Raycaster.
*
* \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 "SHPhysicsRaycaster.h"
/*
* TODO(DIREN):
* Once the physics engine has been rebuilt, this whole implementation should change
* and just call PhysicsWorld.Raycast etc.
*
* SHRaycastResult can be converted to a bool when necessary.
*/
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsRaycaster::SHPhysicsRaycaster() noexcept
: world { nullptr }
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
const SHPhysicsRaycaster::RaycastPairs& SHPhysicsRaycaster::GetRaycasts() const noexcept
{
return raycasts;
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsRaycaster::SetObjectManager(SHPhysicsObjectManager* physicsObjectManager) noexcept
{
objectManager = physicsObjectManager;
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsRaycaster::BindToWorld(rp3d::PhysicsWorld* physicsWorld) noexcept
{
world = physicsWorld;
}
void SHPhysicsRaycaster::ClearFrame() noexcept
{
raycasts.clear();
}
SHPhysicsRaycastResult SHPhysicsRaycaster::Raycast(const SHRay& ray, float distance, const SHCollisionTag& collisionTag) noexcept
{
// Reset temp
temp = SHPhysicsRaycastResult{};
temp.distance = distance;
if (!world)
{
SHLOG_ERROR("Physics world missing for raycasting!")
return temp;
}
// If distance in infinity, cast to the default max distance of 2 km.
if (distance == std::numeric_limits<float>::infinity())
{
world->raycast(ray, this, collisionTag);
}
else
{
const SHVec3 END_POINT = ray.position + ray.direction * distance;
const rp3d::Ray RP3D_RAY{ ray.position, END_POINT };
world->raycast(RP3D_RAY, this, collisionTag);
}
// If a hit was found, populate temp info for return.
if (temp.hit)
{
temp.distance = SHVec3::Distance(ray.position, temp.position);
temp.angle = SHVec3::Angle(ray.position, temp.position);
}
raycasts.emplace_back(ray, temp);
return temp;
}
SHPhysicsRaycastResult SHPhysicsRaycaster::Linecast(const SHVec3& start, const SHVec3& end, const SHCollisionTag& collisionTag) noexcept
{
temp = SHPhysicsRaycastResult{};
temp.distance = SHVec3::Distance(start, end);
if (!world)
{
SHLOG_ERROR("Physics world missing for raycasting!")
return temp;
}
const rp3d::Ray RP3D_RAY{ start, end };
world->raycast(RP3D_RAY, this, collisionTag);
if (temp.hit)
{
temp.distance = SHVec3::Distance(start, temp.position);
temp.angle = SHVec3::Angle(start, temp.position);
}
raycasts.emplace_back(RP3D_RAY, temp);
return temp;
}
SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept
{
SHPhysicsRaycastResult result;
result.distance = distance;
// Get a valid physics object with at least 1 collider.
const auto* PHYSICS_OBJECT = validateColliderRaycast(eid);
if (!PHYSICS_OBJECT)
return result;
auto* rp3dBody = PHYSICS_OBJECT->GetCollisionBody();
// Data to populate
rp3d::RaycastInfo rp3dRaycastInfo;
bool hit = false;
if (distance == std::numeric_limits<float>::infinity())
{
hit = rp3dBody->raycast(ray, rp3dRaycastInfo);
}
else
{
const SHVec3 END_POINT = ray.position + ray.direction * distance;
const rp3d::Ray RP3D_RAY{ ray.position, END_POINT };
hit = rp3dBody->raycast(RP3D_RAY, rp3dRaycastInfo);
}
if (hit)
{
result.hit = true;
result.position = rp3dRaycastInfo.worldPoint;
result.normal = rp3dRaycastInfo.worldPoint;
result.distance = SHVec3::Distance(ray.position, result.position);
result.angle = SHVec3::Angle(ray.position, result.position);
result.entityHit = eid;
result.shapeIndex = findColliderIndex(rp3dBody, rp3dRaycastInfo.collider->getEntity());
}
raycasts.emplace_back(ray, result);
return result;
}
SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept
{
SHPhysicsRaycastResult result;
result.distance = distance;
// Get a valid physics object with at least 1 collider.
const auto* PHYSICS_OBJECT = validateColliderRaycast(eid);
if (!PHYSICS_OBJECT)
return result;
// Boundary check for shape index
if (shapeIndex < 0 || shapeIndex >= static_cast<int>(PHYSICS_OBJECT->GetCollisionBody()->getNbColliders()))
{
SHLOGV_WARNING("Invalid collision shape index passed in")
return result;
}
auto* rp3dCollider = PHYSICS_OBJECT->GetCollisionBody()->getCollider(shapeIndex);
rp3d::RaycastInfo rp3dRaycastInfo;
bool hit = false;
if (distance == std::numeric_limits<float>::infinity())
{
hit = rp3dCollider->raycast(ray, rp3dRaycastInfo);
}
else
{
const SHVec3 END_POINT = ray.position + ray.direction * distance;
const rp3d::Ray RP3D_RAY{ ray.position, END_POINT };
hit = rp3dCollider->raycast(RP3D_RAY, rp3dRaycastInfo);
}
if (hit)
{
result.hit = true;
result.position = rp3dRaycastInfo.worldPoint;
result.normal = rp3dRaycastInfo.worldPoint;
result.distance = SHVec3::Distance(ray.position, result.position);
result.angle = SHVec3::Angle(ray.position, result.position);
result.entityHit = eid;
result.shapeIndex = shapeIndex;
}
raycasts.emplace_back(ray, result);
return result;
}
SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept
{
SHPhysicsRaycastResult result;
result.distance = SHVec3::Distance(start, end);
const auto* PHYSICS_OBJECT = validateColliderRaycast(eid);
if (!PHYSICS_OBJECT)
return result;
auto* rp3dBody = PHYSICS_OBJECT->GetCollisionBody();
rp3d::RaycastInfo rp3dRaycastInfo;
const rp3d::Ray RP3D_RAY{ start, end };
if (rp3dBody->raycast(RP3D_RAY, rp3dRaycastInfo))
{
result.hit = true;
result.position = rp3dRaycastInfo.worldPoint;
result.normal = rp3dRaycastInfo.worldPoint;
result.distance = SHVec3::Distance(start, result.position);
result.angle = SHVec3::Angle(end, result.position);
result.entityHit = eid;
result.shapeIndex = findColliderIndex(rp3dBody, rp3dRaycastInfo.collider->getEntity());
}
raycasts.emplace_back(RP3D_RAY, result);
return result;
}
SHPhysicsRaycastResult SHPhysicsRaycaster::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept
{
SHPhysicsRaycastResult result;
result.distance = SHVec3::Distance(start, end);
const auto* PHYSICS_OBJECT = validateColliderRaycast(eid);
if (!PHYSICS_OBJECT)
return result;
if (shapeIndex < 0 || shapeIndex >= static_cast<int>(PHYSICS_OBJECT->GetCollisionBody()->getNbColliders()))
{
SHLOGV_WARNING("Invalid collision shape index passed in")
return result;
}
auto* rp3dCollider = PHYSICS_OBJECT->GetCollisionBody()->getCollider(shapeIndex);
rp3d::RaycastInfo rp3dRaycastInfo;
const rp3d::Ray RP3D_RAY{ start, end };
if (rp3dCollider->raycast(RP3D_RAY, rp3dRaycastInfo))
{
result.hit = true;
result.position = rp3dRaycastInfo.worldPoint;
result.normal = rp3dRaycastInfo.worldPoint;
result.distance = SHVec3::Distance(start, result.position);
result.angle = SHVec3::Angle(end, result.position);
result.entityHit = eid;
result.shapeIndex = shapeIndex;
}
raycasts.emplace_back(RP3D_RAY, result);
return result;
}
rp3d::decimal SHPhysicsRaycaster::notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo)
{
temp.hit = true;
temp.position = raycastInfo.worldPoint;
temp.normal = raycastInfo.worldNormal;
if (!objectManager)
{
SHLOGV_ERROR("No physics object manager linked with raycaster to match bodies")
return 0.0f;
}
// Compare body IDs to find the matching physics object
const auto HIT_BODY_EID = raycastInfo.body->getEntity();
for (const auto& [entityID, physicsObject] : objectManager->GetPhysicsObjects())
{
const auto RP3D_BODY = physicsObject.GetCollisionBody();
// Match rp3d bodies
if (RP3D_BODY->getEntity() != HIT_BODY_EID)
continue;
temp.entityHit = entityID;
// Find collider index
if (const int INDEX = findColliderIndex(RP3D_BODY, raycastInfo.collider->getEntity()); INDEX > -1)
{
temp.shapeIndex = INDEX;
break;
}
}
return 0.0f;
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject* SHPhysicsRaycaster::validateColliderRaycast(EntityID eid) noexcept
{
if (!objectManager)
{
SHLOGV_ERROR("No physics object manager linked with raycaster to match bodies")
return nullptr;
}
auto* physicsObject = objectManager->GetPhysicsObject(eid);
if (!physicsObject || physicsObject->GetCollisionBody()->getNbColliders() == 0)
{
SHLOGV_WARNING("Cannot cast ray at an entity without colliders!")
return nullptr;
}
return physicsObject;
}
int SHPhysicsRaycaster::findColliderIndex(const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept
{
const int NUM_COLLISION_SHAPES = static_cast<int>(rp3dBody->getNbColliders());
for (int i = 0; i < NUM_COLLISION_SHAPES; ++i)
{
const auto COLLIDER_EID = rp3dBody->getCollider(i)->getEntity();
if (COLLIDER_EID == rp3dColliderEID)
return i;
}
return -1;
}
} // namespace SHADE

View File

@ -1,134 +0,0 @@
/****************************************************************************************
* \file SHPhysicsRaycaster.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Physics Raycaster.
*
* \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 <vector>
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "Math/SHRay.h"
#include "Physics/PhysicsObject/SHPhysicsObjectManager.h"
#include "Physics/SHPhysicsWorld.h"
#include "SH_API.h"
#include "SHCollisionTags.h"
#include "SHPhysicsRaycastResult.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsRaycaster : public reactphysics3d::RaycastCallback
{
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using RaycastPair = std::pair<SHRay, SHPhysicsRaycastResult>;
using RaycastPairs = std::vector<RaycastPair>;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsRaycaster() noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] const RaycastPairs& GetRaycasts() const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetObjectManager(SHPhysicsObjectManager* physicsObjectManager) noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void BindToWorld (rp3d::PhysicsWorld* physicsWorld) noexcept;
void ClearFrame () noexcept;
// TODO(Diren): Filtering, return all shades ray hits
SHPhysicsRaycastResult Raycast
(
const SHRay& ray
, float distance = std::numeric_limits<float>::infinity()
, const SHCollisionTag& collisionTag = SHCollisionTag{}
) noexcept;
SHPhysicsRaycastResult Linecast
(
const SHVec3& start
, const SHVec3& end
, const SHCollisionTag& collisionTag = SHCollisionTag{}
) noexcept;
SHPhysicsRaycastResult ColliderRaycast
(
EntityID eid
, const SHRay& ray
, float distance = std::numeric_limits<float>::infinity()
) noexcept;
SHPhysicsRaycastResult ColliderRaycast
(
EntityID eid
, int shapeIndex
, const SHRay& ray
, float distance = std::numeric_limits<float>::infinity()
) noexcept;
SHPhysicsRaycastResult ColliderLinecast
(
EntityID eid
, const SHVec3& start
, const SHVec3& end
) noexcept;
SHPhysicsRaycastResult ColliderLinecast
(
EntityID eid
, int shapeIndex
, const SHVec3& start
, const SHVec3& end
) noexcept;
rp3d::decimal notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) override;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
rp3d::PhysicsWorld* world;
SHPhysicsObjectManager* objectManager; // For
SHPhysicsRaycastResult temp; // Holds the temporary result after casting into the world
RaycastPairs raycasts; // Used for debug drawing
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsObject* validateColliderRaycast (EntityID eid) noexcept;
static int findColliderIndex (const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept;
};
} // namespace SHADE

View File

@ -0,0 +1,105 @@
/****************************************************************************************
* \file SHBoxCollisionShape.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Box Collision Shape.
*
* \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>
#include <reactphysics3d/reactphysics3d.h>
// Primary Header
#include "SHBox.h"
// Project Headers
#include "Math/SHMatrix.h"
#include "Physics/Interface/SHColliderComponent.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHBox::SHBox() noexcept
: SHCollisionShape (Type::BOX)
, relativeExtents { SHVec3::One }
, scale { SHVec3::One }
{
if (rp3dCollider)
dynamic_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape())->setHalfExtents(SHVec3::One * 0.5f);
}
/*-----------------------------------------------------------------------------------*/
/* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHVec3 SHBox::GetWorldExtents() const noexcept
{
return SHVec3{ dynamic_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape())->getHalfExtents() };
}
SHVec3 SHBox::GetRelativeExtents() const noexcept
{
return relativeExtents;
}
SHVec3 SHBox::GetWorldCentroid() const noexcept
{
const SHQuaternion ROTATION = collider->GetTransform().orientation * SHQuaternion::FromEuler(rotationOffset);
const SHMatrix TRS = SHMatrix::Rotate(ROTATION) * SHMatrix::Translate(collider->GetTransform().position);
return SHVec3::Transform(positionOffset, TRS);
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept
{
dynamic_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape())->setHalfExtents(newWorldExtents);
// Recompute Relative radius
relativeExtents = 2.0f * newWorldExtents / scale;
}
void SHBox::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept
{
relativeExtents = newRelativeExtents;
// Recompute world radius
dynamic_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape())->setHalfExtents(relativeExtents * scale * 0.5f);
}
void SHBox::SetScale(const SHVec3& newScale) noexcept
{
scale = SHVec3::Abs(newScale);
// Recompute world radius
dynamic_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape())->setHalfExtents(relativeExtents * scale * 0.5f);
}
/*-----------------------------------------------------------------------------------*/
/* Public Member Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHMatrix SHBox::GetTRS() const noexcept
{
const SHQuaternion ROTATION = collider->GetTransform().orientation * SHQuaternion::FromEuler(rotationOffset);
const SHVec3 SCALE = GetWorldExtents() * 2.0f;
const SHMatrix TRS = SHMatrix::Rotate(ROTATION) * SHMatrix::Translate(collider->GetTransform().position);
const SHVec3 POSITION = SHVec3::Transform(positionOffset, TRS);
return SHMatrix::Transform(POSITION, ROTATION, SCALE);
}
} // namespace SHADE

View File

@ -1,7 +1,7 @@
/**************************************************************************************** /****************************************************************************************
* \file SHBoundingSphere.h * \file SHBox.h
* \author Diren D Bharwani, diren.dbharwani, 390002520 * \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Bounding Sphere. * \brief Interface for a Box Collision Shape.
* *
* \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
@ -10,11 +10,8 @@
#pragma once #pragma once
#include <DirectXCollision.h>
// Project Headers // Project Headers
#include "SHShape.h" #include "SHCollisionShape.h"
#include "SH_API.h"
namespace SHADE namespace SHADE
{ {
@ -22,71 +19,60 @@ namespace SHADE
/* Type Definitions */ /* Type Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
class SH_API SHSphere : public SHShape, /**
private DirectX::BoundingSphere * @brief
* Encapsulate a Box Shape used for Physics Simulations.
*/
class SH_API SHBox final : public SHCollisionShape
{ {
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHColliderComponent;
public: public:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */ /* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHSphere () noexcept; SHBox () noexcept;
SHSphere (const SHVec3& center, float radius) noexcept; ~SHBox () override = default;
SHSphere (const SHSphere& rhs) noexcept;
SHSphere (SHSphere&& rhs) noexcept;
~SHSphere () override = default;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Operator Overloads */ /* Operator Overloads */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHSphere& operator= (const SHSphere& rhs) noexcept;
SHSphere& operator= (SHSphere&& rhs) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] SHVec3 GetCenter () const noexcept; [[nodiscard]] SHVec3 GetWorldExtents () const noexcept;
[[nodiscard]] float GetWorldRadius () const noexcept; [[nodiscard]] SHVec3 GetRelativeExtents () const noexcept;
[[nodiscard]] float GetRelativeRadius () const noexcept;
[[nodiscard]] SHVec3 GetWorldCentroid () const noexcept override;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SetCenter (const SHVec3& center) noexcept; void SetWorldExtents (const SHVec3& newWorldExtents) noexcept;
void SetWorldRadius (float newWorldRadius) noexcept; void SetRelativeExtents (const SHVec3& newRelativeExtents) noexcept;
void SetRelativeRadius (float newRelativeRadius) noexcept; void SetScale (const SHVec3& newScale) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] bool TestPoint (const SHVec3& point) const noexcept override; [[nodiscard]] SHMatrix GetTRS () const noexcept override;
[[nodiscard]] SHRaycastResult Raycast(const SHRay& ray) const noexcept override;
[[nodiscard]] bool Contains (const SHSphere& rhs) const noexcept;
[[nodiscard]] float Volume () const noexcept;
[[nodiscard]] float SurfaceArea () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Static Function Members */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] static SHSphere Combine (const SHSphere& lhs, const SHSphere& rhs) noexcept;
[[nodiscard]] static bool Intersect (const SHSphere& lhs, const SHSphere& rhs) noexcept;
[[nodiscard]] static SHSphere BuildFromSpheres (const SHSphere* spheres, size_t numSpheres) noexcept;
[[nodiscard]] static SHSphere BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept;
private: private:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
float RelativeRadius; SHVec3 relativeExtents;
SHVec3 scale;
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -0,0 +1,209 @@
/****************************************************************************************
* \file SHCollider.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Collider.
*
* \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>
#include <reactphysics3d/reactphysics3d.h>
// Primary Header
#include "SHCollisionShape.h"
// Project Headers
#include "Physics/Interface/SHColliderComponent.h"
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Reflection/SHReflectionMetadata.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHCollisionShape::SHCollisionShape(Type colliderType)
: rp3dCollider { nullptr }
, collider { nullptr }
, collisionTag { SHCollisionTagMatrix::GetTag(0) }
, flags { 0 }
{
flags |= 1U << SHUtilities::ConvertEnum(colliderType);
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
float SHCollisionShape::GetFriction() const noexcept
{
return material.GetFriction();
}
float SHCollisionShape::GetBounciness() const noexcept
{
return material.GetBounciness();
}
float SHCollisionShape::GetDensity() const noexcept
{
return material.GetDensity();
}
const SHPhysicsMaterial& SHCollisionShape::GetMaterial() const noexcept
{
return material;
}
const SHVec3& SHCollisionShape::GetPositionOffset() const noexcept
{
return positionOffset;
}
const SHVec3& SHCollisionShape::GetRotationOffset() const noexcept
{
return rotationOffset;
}
SHCollisionShape::Type SHCollisionShape::GetType() const noexcept
{
for (int i = 0; i < SHUtilities::ConvertEnum(Type::COUNT); ++i)
{
const uint8_t FLAG_VALUE = 1U << SHUtilities::ConvertEnum(static_cast<Type>(i));
if (flags & FLAG_VALUE)
return static_cast<Type>(i);
}
return Type::INVALID;
}
bool SHCollisionShape::IsTrigger() const noexcept
{
static constexpr int FLAG_POS = 3;
static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS;
return flags & FLAG_VALUE;
}
bool SHCollisionShape::IsColliding() const noexcept
{
static constexpr int FLAG_POS = 4;
static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS;
return flags & FLAG_VALUE;
}
const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept
{
return *collisionTag;
}
SHVec3 SHCollisionShape::GetWorldCentroid() const noexcept
{
return collider->GetTransform().position;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionShape::SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept
{
collisionTag = newCollisionTag;
}
void SHCollisionShape::SetFriction(float friction) noexcept
{
material.SetFriction(friction);
rp3dCollider->getMaterial().setFrictionCoefficient(material.GetFriction());
}
void SHCollisionShape::SetBounciness(float bounciness) noexcept
{
material.SetBounciness(bounciness);
rp3dCollider->getMaterial().setBounciness(material.GetBounciness());
}
void SHCollisionShape::SetDensity(float density) noexcept
{
material.SetDensity(density);
rp3dCollider->getMaterial().setMassDensity(material.GetDensity());
}
void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept
{
material = newMaterial;
auto& rp3dMaterial = rp3dCollider->getMaterial();
rp3dMaterial.setFrictionCoefficient(material.GetFriction());
rp3dMaterial.setBounciness(material.GetBounciness());
rp3dMaterial.setMassDensity(material.GetDensity());
}
void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept
{
positionOffset = posOffset;
Update();
}
void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept
{
rotationOffset = rotOffset;
Update();
}
void SHCollisionShape::SetIsTrigger(bool isTrigger) noexcept
{
static constexpr int FLAG_POS = 3;
static constexpr uint8_t FLAG_VALUE = 1U << FLAG_POS;
isTrigger ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
rp3dCollider->setIsTrigger(isTrigger);
}
/*-----------------------------------------------------------------------------------*/
/* Public Member Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionShape::Update() noexcept
{
const rp3d::Transform OFFSETS{ positionOffset, SHQuaternion::FromEuler(rotationOffset) };
rp3dCollider->setLocalToBodyTransform(OFFSETS);
}
SHMatrix SHCollisionShape::GetTRS() const noexcept
{
return SHMatrix::Identity;
}
} // namespace SHADE
RTTR_REGISTRATION
{
using namespace SHADE;
using namespace rttr;
registration::enumeration<SHCollisionShape::Type>("Collider Type")
(
value("Box", SHCollisionShape::Type::BOX),
value("Sphere", SHCollisionShape::Type::SPHERE)
// TODO(Diren): Add More Shapes
);
registration::class_<SHCollisionShape>("Collider")
.property("IsTrigger" , &SHCollisionShape::IsTrigger , &SHCollisionShape::SetIsTrigger )
.property("Friction" , &SHCollisionShape::GetFriction , &SHCollisionShape::SetFriction )
.property("Bounciness" , &SHCollisionShape::GetBounciness , &SHCollisionShape::SetBounciness )
.property("Density" , &SHCollisionShape::GetDensity , &SHCollisionShape::SetDensity )
.property("Position Offset" , &SHCollisionShape::GetPositionOffset, &SHCollisionShape::SetPositionOffset)
.property("Rotation Offset" , &SHCollisionShape::GetRotationOffset, &SHCollisionShape::SetRotationOffset) (metadata(META::angleInRad, true));
}

View File

@ -0,0 +1,157 @@
/****************************************************************************************
* \file SHCollisionShape.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Base CollisionShape Class.
*
* \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 <rttr/registration>
#include <reactphysics3d/collision/Collider.h>
// Project Headers
#include "ECS_Base/Entity/SHEntity.h"
#include "Physics/Collision/CollisionTags/SHCollisionTags.h"
#include "Physics/Collision/SHPhysicsMaterial.h"
#include "Math/Transform/SHTransform.h"
#include "Physics/Collision/SHPhysicsRaycastResult.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHColliderComponent;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHCollisionShape
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem;
friend class SHColliderComponent;
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class Type
{
SPHERE
, BOX
, COUNT
, INVALID = -1
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHCollisionShape(Type colliderType = Type::INVALID);
SHCollisionShape(const SHCollisionShape& rhs) noexcept = default;
SHCollisionShape(SHCollisionShape&& rhs) noexcept = default;
virtual ~SHCollisionShape() noexcept = default;
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
SHCollisionShape& operator=(const SHCollisionShape& rhs) noexcept = default;
SHCollisionShape& operator=(SHCollisionShape&& rhs) noexcept = default;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
// Material Properties
// TODO: Remove individual setters once instanced materials are supported
[[nodiscard]] float GetFriction() const noexcept;
[[nodiscard]] float GetBounciness() const noexcept;
[[nodiscard]] float GetDensity() const noexcept;
[[nodiscard]] const SHPhysicsMaterial& GetMaterial() const noexcept;
// Offsets
[[nodiscard]] const SHVec3& GetPositionOffset() const noexcept;
[[nodiscard]] const SHVec3& GetRotationOffset() const noexcept;
// Flags
[[nodiscard]] Type GetType() const noexcept;
[[nodiscard]] bool IsTrigger() const noexcept;
[[nodiscard]] bool IsColliding() const noexcept;
[[nodiscard]] const SHCollisionTag& GetCollisionTag() const noexcept;
[[nodiscard]] virtual SHVec3 GetWorldCentroid() const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept;
void SetFriction(float friction) noexcept;
void SetBounciness(float bounciness) noexcept;
void SetDensity(float density) noexcept;
void SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept;
void SetPositionOffset(const SHVec3& posOffset) noexcept;
void SetRotationOffset(const SHVec3& rotOffset) noexcept;
// Forces rigidbody to recompute mass if one exists
void SetIsTrigger(bool isTrigger) noexcept;
/*---------------------------------------------------------------------------------*/
/* Member Functions */
/*---------------------------------------------------------------------------------*/
/**
* @brief
* Computes the transform of the shape.
*/
void Update() noexcept;
/**
* @brief
* Computes the TRS matrix for rendering the shape.
* @return
* The model-to-world matrix for rendering the shape.
*/
[[nodiscard]] virtual SHMatrix GetTRS() const noexcept;
protected:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
reactphysics3d::Collider* rp3dCollider;
SHColliderComponent* collider; // The collider it belongs to.
SHCollisionTag* collisionTag;
SHPhysicsMaterial material; // TODO: Change to pointer once instancing is supported
SHVec3 positionOffset;
SHVec3 rotationOffset;
uint8_t flags; // 0 0 0 trigger 0 capsule sphere box
RTTR_ENABLE()
};
}

View File

@ -0,0 +1,105 @@
/****************************************************************************************
* \file SHSphereCollisionShape.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Sphere Collision Shape.
*
* \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>
#include <reactphysics3d/reactphysics3d.h>
// Primary Header
#include "SHSphere.h"
// Project Headers
#include "Math/SHMathHelpers.h"
#include "Math/SHMatrix.h"
#include "Physics/Interface/SHColliderComponent.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHSphere::SHSphere() noexcept
: SHCollisionShape (Type::SPHERE)
, relativeRadius { 1.0f }
, scale { 1.0f }
{
if (rp3dCollider)
dynamic_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape())->setRadius(0.5f);
}
/*-----------------------------------------------------------------------------------*/
/* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
float SHSphere::GetWorldRadius() const noexcept
{
return dynamic_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape())->getRadius();
}
float SHSphere::GetRelativeRadius() const noexcept
{
return relativeRadius;
}
SHVec3 SHSphere::GetWorldCentroid() const noexcept
{
const SHQuaternion ROTATION = collider->GetTransform().orientation * SHQuaternion::FromEuler(rotationOffset);
const SHMatrix TRS = SHMatrix::Rotate(ROTATION) * SHMatrix::Translate(collider->GetTransform().position);
return SHVec3::Transform(positionOffset, TRS);
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHSphere::SetWorldRadius(float newWorldRadius) noexcept
{
dynamic_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape())->setRadius(newWorldRadius);
// Recompute Relative radius
relativeRadius = 2.0f * newWorldRadius / scale;
}
void SHSphere::SetRelativeRadius(float newRelativeRadius) noexcept
{
relativeRadius = newRelativeRadius;
// Recompute world radius
dynamic_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape())->setRadius(relativeRadius * scale * 0.5f);
}
void SHSphere::SetScale(float maxScale) noexcept
{
scale = std::fabs(maxScale);
// Recompute world radius
dynamic_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape())->setRadius(relativeRadius * scale * 0.5f);
}
/*-----------------------------------------------------------------------------------*/
/* Public Member Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHMatrix SHSphere::GetTRS() const noexcept
{
const SHQuaternion ROTATION = collider->GetTransform().orientation * SHQuaternion::FromEuler(rotationOffset);
const SHVec3 SCALE = GetWorldRadius() * 2.0f;
const SHMatrix TRS = SHMatrix::Rotate(ROTATION) * SHMatrix::Translate(collider->GetTransform().position);
const SHVec3 POSITION = SHVec3::Transform(positionOffset, TRS);
return SHMatrix::Transform(POSITION, ROTATION, SCALE);
}
} // namespace SHADE

View File

@ -1,7 +1,7 @@
/**************************************************************************************** /****************************************************************************************
* \file SHShape.h * \file SHSphereCollisionShape.h
* \author Diren D Bharwani, diren.dbharwani, 390002520 * \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a shape. * \brief Interface for a Sphere Collision Shape.
* *
* \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,9 +11,7 @@
#pragma once #pragma once
// Project Headers // Project Headers
#include "SH_API.h" #include "SHCollisionShape.h"
#include "Math/SHRay.h"
namespace SHADE namespace SHADE
{ {
@ -21,62 +19,60 @@ namespace SHADE
/* Type Definitions */ /* Type Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
class SH_API SHShape /**
* @brief
* Encapsulate a Sphere Shape used for Physics Simulations.
*/
class SH_API SHSphere final : public SHCollisionShape
{ {
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHColliderComponent;
public: public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class Type
{
BOX
, SPHERE
, CAPSULE
, CONVEX_HULL
, COUNT
, NONE = -1
};
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
bool isIntersecting;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */ /* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
virtual ~SHShape () = default; SHSphere () noexcept;
~SHSphere () override = default;
SHShape (const SHShape&) = default; /*---------------------------------------------------------------------------------*/
SHShape (SHShape&&) = default; /* Operator Overloads */
/*---------------------------------------------------------------------------------*/
SHShape& operator=(const SHShape&) = default;
SHShape& operator=(SHShape&&) = default;
SHShape();
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] Type GetType () const noexcept; [[nodiscard]] float GetWorldRadius () const noexcept;
[[nodiscard]] float GetRelativeRadius () const noexcept;
[[nodiscard]] SHVec3 GetWorldCentroid () const noexcept override;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetWorldRadius (float newWorldRadius) noexcept;
void SetRelativeRadius (float newRelativeRadius) noexcept;
void SetScale (float maxScale) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] virtual bool TestPoint (const SHVec3& point) const noexcept = 0; [[nodiscard]] SHMatrix GetTRS () const noexcept override;
[[nodiscard]] virtual SHRaycastResult Raycast (const SHRay& ray) const noexcept = 0;
protected: private:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Type type; float relativeRadius;
float scale;
}; };
} // namespace SHADE }

View File

@ -1,7 +1,7 @@
/**************************************************************************************** /****************************************************************************************
* \file SHShape.cpp * \file SHPhysicsObject.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520 * \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a shape. * \brief Implementation for a Physics Object.
* *
* \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,25 +11,25 @@
#include <SHpch.h> #include <SHpch.h>
// Primary Header // Primary Header
#include "SHShape.h" #include "SHPhysicsObject.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */ /* Constructor & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHShape::SHShape() SHPhysicsObject::SHPhysicsObject(EntityID eid) noexcept
: type { Type::NONE } : entityID { eid }
{} {}
/*-----------------------------------------------------------------------------------*/ SHPhysicsObject::~SHPhysicsObject() noexcept
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHShape::Type SHShape::GetType() const noexcept
{ {
return type; entityID = MAX_EID;
body = nullptr;
} }
} // namespace SHADE } // namespace SHADE

View File

@ -0,0 +1,48 @@
/****************************************************************************************
* \file SHPhysicsObject.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface 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.
****************************************************************************************/
#pragma once
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "ECS_Base/Entity/SHEntity.h"
namespace SHADE
{
/*-------------------------------------------------------------------------------------*/
/* Type Definitions */
/*-------------------------------------------------------------------------------------*/
/**
* @brief
* Encapsulates a rigid body and a collider tied to an Entity.
*/
struct SH_API SHPhysicsObject
{
public:
/*-----------------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------------*/
// We use a rigid body all the time. Colliders without rigid bodies have a static body.
EntityID entityID = MAX_EID;
rp3d::RigidBody* body = nullptr;
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject (EntityID eid) noexcept;
~SHPhysicsObject () noexcept;
};
} // namespace SHADE

View File

@ -0,0 +1,408 @@
/****************************************************************************************
* \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 "Math/Transform/SHTransformComponent.h"
#include "Physics/Collision/Shapes/SHSphere.h"
#include "Physics/Collision/Shapes/SHBox.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Physics/Interface/SHRigidBodyComponent.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObjectManager::SHPhysicsObjectManager() noexcept
: factory { nullptr }
, physicsWorld { nullptr }
{}
SHPhysicsObjectManager::~SHPhysicsObjectManager() noexcept
{
RemoveAllObjects();
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObjectManager::EntityObjectMap& SHPhysicsObjectManager::GetPhysicsObjects() noexcept
{
return physicsObjects;
}
const SHPhysicsObject* SHPhysicsObjectManager::GetPhysicsObject(EntityID entityID) noexcept
{
const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID);
if (PHYSICS_OBJECT_ITERATOR == physicsObjects.end())
{
SHLOG_ERROR("Cannot find physics object for entity {}!", entityID)
return nullptr;
}
return &PHYSICS_OBJECT_ITERATOR->second;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObjectManager::SetFactory(rp3d::PhysicsCommon* physicsFactory) noexcept
{
factory = physicsFactory;
}
void SHPhysicsObjectManager::SetPhysicsWorld(rp3d::PhysicsWorld* world) noexcept
{
physicsWorld = world;
}
/*-----------------------------------------------------------------------------------*/
/* Public Member Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObjectManager::AddRigidBody(EntityID entityID) noexcept
{
SHASSERT(physicsWorld, "Physics World Missing ffrom Physics Object Manager!")
SHPhysicsObject* physicsObject = ensurePhysicsObject(entityID);
// Get the rigidbody and transform components
auto* rigidBodyComponent = SHComponentManager::GetComponent<SHRigidBodyComponent>(entityID);
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (!physicsObject->body)
{
if (!transformComponent)
{
SHLOG_ERROR("Unable to create a rigid body for Entity {} with missing transform!", entityID)
return;
}
// Create a new rigidbody in the physics object
const rp3d::Transform RP3D_TRANSFORM{ transformComponent->GetWorldPosition(), transformComponent->GetWorldOrientation() };
physicsObject->body = physicsWorld->createRigidBody(RP3D_TRANSFORM);
}
// Link with the component
rigidBodyComponent->SetRigidBody(physicsObject->body);
// Reset the type
const auto RIGID_BODY_TYPE = rigidBodyComponent->GetType();
switch (RIGID_BODY_TYPE)
{
case SHRigidBodyComponent::Type::STATIC:
physicsObject->body->setType(rp3d::BodyType::STATIC);
break;
case SHRigidBodyComponent::Type::KINEMATIC:
physicsObject->body->setType(rp3d::BodyType::KINEMATIC);
break;
case SHRigidBodyComponent::Type::DYNAMIC:
physicsObject->body->setType(rp3d::BodyType::DYNAMIC);
break;
default:
break;
}
}
void SHPhysicsObjectManager::RemoveRigidBody(EntityID entityID) noexcept
{
SHASSERT(physicsWorld, "Physics World Missing from Physics Object Manager!")
const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID);
if (PHYSICS_OBJECT_ITERATOR == physicsObjects.end())
return;
SHPhysicsObject* physicsObject = &PHYSICS_OBJECT_ITERATOR->second;
// If a collider component exists, we just set the body to static
if (SHComponentManager::GetComponent_s<SHColliderComponent>(entityID))
physicsObject->body->setType(rp3d::BodyType::STATIC);
else
{
physicsWorld->destroyRigidBody(physicsObject->body);
destroyPhysicsObject(entityID);
}
}
void SHPhysicsObjectManager::AddCollider(EntityID entityID) noexcept
{
SHASSERT(physicsWorld, "Physics World Missing from Physics Object Manager!")
SHPhysicsObject* physicsObject = ensurePhysicsObject(entityID);
// Get the collider & transform component
auto* colliderComponent = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
// Check if a body already exists. If it does, link it with the component
if (!physicsObject->body)
{
if (!transformComponent)
{
SHLOG_ERROR("Unable to create a collider for Entity {} with missing transform!", entityID)
return;
}
// Create a static body
const rp3d::Transform RP3D_TRANSFORM{ transformComponent->GetWorldPosition(), transformComponent->GetWorldOrientation() };
physicsObject->body = physicsWorld->createRigidBody(RP3D_TRANSFORM);
physicsObject->body->setType(rp3d::BodyType::STATIC);
}
// Link with component
colliderComponent->SetFactory(factory);
colliderComponent->SetCollisionBody(physicsObject->body);
}
void SHPhysicsObjectManager::RemoveCollider(EntityID entityID) noexcept
{
auto* colliderComponent = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID);
if (PHYSICS_OBJECT_ITERATOR != physicsObjects.end())
{
SHPhysicsObject* physicsObject = &PHYSICS_OBJECT_ITERATOR->second;
// Remove all collision shapes from the body
int32_t numShapes = static_cast<int32_t>(physicsObject->body->getNbColliders());
while (--numShapes >= 0)
{
auto* rp3dCollider = physicsObject->body->getCollider(numShapes);
physicsObject->body->removeCollider(rp3dCollider);
delete colliderComponent->shapes[numShapes];
colliderComponent->shapes[numShapes] = nullptr;
}
colliderComponent->shapes.clear();
// Destroy if no rigidbody component
if (!SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID))
destroyPhysicsObject(entityID);
}
}
void SHPhysicsObjectManager::RemoveAllObjects() noexcept
{
// Physics objects itself will delete the object
physicsObjects.clear();
}
void SHPhysicsObjectManager::AddRigidBodyDef(EntityID entityID) noexcept
{
auto* rigidBody = SHComponentManager::GetComponent<SHRigidBodyComponent>(entityID);
const SHRigidBodyDef RIGID_BODY_DEF
{
.entityID = rigidBody->GetEID()
, .bodyType = rigidBody->type
, .flags = rigidBody->flags
, .interpolate = rigidBody->interpolate
, .drag = rigidBody->drag
, .angularDrag = rigidBody->angularDrag
};
rigidBodyQueue.push(RIGID_BODY_DEF);
}
void SHPhysicsObjectManager::AddColliderDef(EntityID entityID) noexcept
{
auto* collider = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
SHColliderDef colliderDef
{
.entityID = collider->GetEID()
};
for (const auto* shape : collider->shapes)
{
SHColliderDef::ShapeDef shapeDef
{
.type = shape->GetType()
, .posOffset = shape->GetPositionOffset()
, .rotOffset = shape->GetRotationOffset()
};
switch (shape->GetType())
{
case SHCollisionShape::Type::SPHERE:
shapeDef.size.x = dynamic_cast<const SHSphere*>(shape)->GetWorldRadius();
break;
case SHCollisionShape::Type::BOX:
shapeDef.size = dynamic_cast<const SHBox*>(shape)->GetWorldExtents();
break;
default:
break;
}
colliderDef.shapes.emplace_back(shapeDef);
}
colliderQueue.push(colliderDef);
}
void SHPhysicsObjectManager::FlushDefinitions() noexcept
{
SHASSERT(physicsWorld, "Physics World Missing ffrom Physics Object Manager!")
// Flush all rigid bodies
while (!rigidBodyQueue.empty())
{
const SHRigidBodyDef& DEF = rigidBodyQueue.front();
SHPhysicsObject* physicsObject = ensurePhysicsObject(DEF.entityID);
// Get transform component
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(DEF.entityID);
if (!transformComponent)
{
SHLOG_ERROR("Unable to create a rigid body for Entity {} with missing transform!", DEF.entityID)
rigidBodyQueue.pop();
continue;
}
// Create a new rigidbody in the physics object
const rp3d::Transform RP3D_TRANSFORM{ transformComponent->GetWorldPosition(), transformComponent->GetWorldOrientation() };
physicsObject->body = physicsWorld->createRigidBody(RP3D_TRANSFORM);
// Get rigidBody component
auto* rigidBodyComponent = SHComponentManager::GetComponent<SHRigidBodyComponent>(DEF.entityID);
rigidBodyComponent->SetRigidBody(physicsObject->body);
// Set type
rigidBodyComponent->type = DEF.bodyType;
switch (DEF.bodyType)
{
case SHRigidBodyComponent::Type::STATIC:
physicsObject->body->setType(rp3d::BodyType::STATIC);
break;
case SHRigidBodyComponent::Type::KINEMATIC:
physicsObject->body->setType(rp3d::BodyType::KINEMATIC);
break;
case SHRigidBodyComponent::Type::DYNAMIC:
physicsObject->body->setType(rp3d::BodyType::DYNAMIC);
break;
default:
break;
}
// Re-set properties
rigidBodyComponent->SetGravityEnabled (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::GRAVITY));
rigidBodyComponent->SetIsAllowedToSleep (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::SLEEPING));
rigidBodyComponent->SetFreezePositionX (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::LINEAR_X));
rigidBodyComponent->SetFreezePositionY (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::LINEAR_Y));
rigidBodyComponent->SetFreezePositionZ (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::LINEAR_Z));
rigidBodyComponent->SetFreezeRotationX (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::ANGULAR_X));
rigidBodyComponent->SetFreezeRotationY (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::ANGULAR_Y));
rigidBodyComponent->SetFreezeRotationZ (DEF.flags & SHUtilities::ConvertEnum(SHRigidBodyComponent::Flags::ANGULAR_Z));
rigidBodyComponent->SetInterpolate (DEF.interpolate);
rigidBodyComponent->SetDrag (DEF.drag);
rigidBodyComponent->SetAngularDrag (DEF.angularDrag);
rigidBodyQueue.pop();
}
// Flush all colliders
while (!colliderQueue.empty())
{
const SHColliderDef& DEF = colliderQueue.front();
SHPhysicsObject* physicsObject = ensurePhysicsObject(DEF.entityID);
// Get transform component
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(DEF.entityID);
if (!transformComponent)
{
SHLOG_ERROR("Unable to create a collider for Entity {} with missing transform!", DEF.entityID)
colliderQueue.pop();
continue;
}
if (!physicsObject->body)
{
// Create a static body
const rp3d::Transform RP3D_TRANSFORM{ transformComponent->GetWorldPosition(), transformComponent->GetWorldOrientation() };
physicsObject->body = physicsWorld->createRigidBody(RP3D_TRANSFORM);
physicsObject->body->setType(rp3d::BodyType::STATIC);
}
// Get rigidBody component
auto* colliderComponent = SHComponentManager::GetComponent<SHColliderComponent>(DEF.entityID);
colliderComponent->SetFactory(factory);
colliderComponent->SetCollisionBody(physicsObject->body);
// Add all shapes
for (auto& shapeDef : DEF.shapes)
{
switch (shapeDef.type)
{
case SHCollisionShape::Type::SPHERE:
{
colliderComponent->AddSphereCollisionShape(shapeDef.size.x);
break;
}
case SHCollisionShape::Type::BOX:
{
colliderComponent->AddBoxCollisionShape(shapeDef.size);
break;
}
default: break;
}
}
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Member Function Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject* SHPhysicsObjectManager::createPhysicsObject(EntityID entityID)
{
const auto& NEW_OBJECT = physicsObjects.emplace(entityID, SHPhysicsObject{entityID}).first;
return &NEW_OBJECT->second;
}
SHPhysicsObject* SHPhysicsObjectManager::ensurePhysicsObject(EntityID entityID)
{
const auto PHYSICS_OBJECT_ITERATOR = physicsObjects.find(entityID);
SHPhysicsObject* physicsObject = PHYSICS_OBJECT_ITERATOR == physicsObjects.end()
? createPhysicsObject(entityID)
: &PHYSICS_OBJECT_ITERATOR->second;
return physicsObject;
}
void SHPhysicsObjectManager::destroyPhysicsObject(EntityID entityID)
{
physicsObjects.erase(entityID);
}
} // namespace SHADE

View File

@ -0,0 +1,183 @@
/****************************************************************************************
* \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 <vector>
#include <queue>
#include <unordered_map>
// Project Headers
#include "SHPhysicsObject.h"
#include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Interface/SHColliderComponent.h"
namespace SHADE
{
/*-------------------------------------------------------------------------------------*/
/* Type Definitions */
/*-------------------------------------------------------------------------------------*/
/**
* @brief
* Encapsulates a manager for physics objects that links raw physics components with the
* engine's components.
*/
class SH_API SHPhysicsObjectManager
{
private:
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
using EntityObjectMap = std::unordered_map<EntityID, SHPhysicsObject>;
public:
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
struct SHRigidBodyDef
{
EntityID entityID = MAX_EID;
SHRigidBodyComponent::Type bodyType = SHRigidBodyComponent::Type::STATIC;
uint8_t flags = 0; // aZ aY aX lZ lY lX sleepEnabled gravity
bool interpolate = true;
float drag = 0.0f;
float angularDrag = 0.0f;
};
struct SHColliderDef
{
struct ShapeDef
{
SHCollisionShape::Type type = SHCollisionShape::Type::SPHERE;
SHVec3 posOffset = SHVec3::Zero;
SHVec3 rotOffset = SHVec3::Zero;
SHVec3 size = SHVec3::Zero; // x for sphere radius, all 3 for box extents
};
EntityID entityID = MAX_EID;
std::vector<ShapeDef> shapes;
};
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObjectManager () noexcept;
~SHPhysicsObjectManager () noexcept;
/*-----------------------------------------------------------------------------------*/
/* Getter Functions */
/*-----------------------------------------------------------------------------------*/
[[nodiscard]] EntityObjectMap& GetPhysicsObjects () noexcept;
[[nodiscard]] const SHPhysicsObject* GetPhysicsObject (EntityID entityID) noexcept;
/*-----------------------------------------------------------------------------------*/
/* Setter Functions */
/*-----------------------------------------------------------------------------------*/
void SetFactory (rp3d::PhysicsCommon* physicsFactory) noexcept;
void SetPhysicsWorld(rp3d::PhysicsWorld* world) noexcept;
/*-----------------------------------------------------------------------------------*/
/* Member Functions */
/*-----------------------------------------------------------------------------------*/
/**
* @brief
* Creates a rigid body and links it with the rigid body component.
* @param entityID
* The entity to link the new rigid body to.
*/
void AddRigidBody (EntityID entityID) noexcept;
/**
* @brief
* Destroys a rigid body and removes the link with the rigid body component.
* @param entityID
* The entity to destroy the rigid body of.
*/
void RemoveRigidBody (EntityID entityID) noexcept;
/**
* @brief
* Creates a composite collider and links it with the collider component.
* @param entityID
* The entity to link the new collider to.
*/
void AddCollider (EntityID entityID) noexcept;
/**
* @brief
* Destroys a composite collider and removes the link with the collider component.
* @param entityID
* The entity to destroy the collider of.
*/
void RemoveCollider (EntityID entityID) noexcept;
/**
* @brief
* Removes all physics object in the manager. This is only meant to be called when
* the world is being destroyed or the scene is being changed.
*/
void RemoveAllObjects () noexcept;
/**
* @brief Adds a rigidbody definition to add to the physics world.
* @param rigidBody
* The rigidbody component
*/
void AddRigidBodyDef (EntityID entityID) noexcept;
/**
* @brief Adds a collider definition to add to the physics world.
* @param collider
* The collider component
*/
void AddColliderDef (EntityID entityID) noexcept;
/**
* @brief Adds all loaded definitions into the physics world.
*/
void FlushDefinitions () noexcept;
private:
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
using RigidBodyQueue = std::queue<SHRigidBodyDef>;
using ColliderQueue = std::queue<SHColliderDef>;
/*-----------------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------------*/
rp3d::PhysicsCommon* factory;
rp3d::PhysicsWorld* physicsWorld;
EntityObjectMap physicsObjects;
RigidBodyQueue rigidBodyQueue;
ColliderQueue colliderQueue;
/*-----------------------------------------------------------------------------------*/
/* Member Functions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject* createPhysicsObject (EntityID entityID);
SHPhysicsObject* ensurePhysicsObject (EntityID entityID);
void destroyPhysicsObject (EntityID entityID);
};
} // namespace SHADE

View File

@ -9,6 +9,7 @@
****************************************************************************************/ ****************************************************************************************/
#include <SHpch.h> #include <SHpch.h>
#include <reactphysics3d/reactphysics3d.h>
// Primary Header // Primary Header
#include "SHColliderComponent.h" #include "SHColliderComponent.h"
@ -16,7 +17,9 @@
// 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/System/SHPhysicsSystem.h" #include "Physics/SHPhysicsEvents.h"
#include "Physics/Collision/Shapes/SHSphere.h"
#include "Physics/Collision/Shapes/SHBox.h"
namespace SHADE namespace SHADE
{ {
@ -25,185 +28,237 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHColliderComponent::SHColliderComponent() noexcept SHColliderComponent::SHColliderComponent() noexcept
: system { nullptr } : flags { ACTIVE_FLAG | MOVED_FLAG }
, collisionBody { nullptr }
{} {}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */ /* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
bool SHColliderComponent::GetDebugDrawState() const noexcept
{
return flags & DRAW_FLAG;
}
const SHTransform& SHColliderComponent::GetTransform() const noexcept
{
return transform;
}
const SHVec3& SHColliderComponent::GetPosition() const noexcept const SHVec3& SHColliderComponent::GetPosition() const noexcept
{ {
return position; return transform.position;
} }
const SHQuaternion& SHColliderComponent::GetOrientation() const noexcept const SHQuaternion& SHColliderComponent::GetOrientation() const noexcept
{ {
return orientation; return transform.orientation;
}
SHVec3 SHColliderComponent::GetRotation() const noexcept
{
return orientation.ToEuler();
} }
const SHVec3& SHColliderComponent::GetScale() const noexcept const SHVec3& SHColliderComponent::GetScale() const noexcept
{ {
return scale; return transform.scale;
} }
const SHColliderComponent::CollisionShapes& SHColliderComponent::GetCollisionShapes() const noexcept const SHColliderComponent::CollisionShapes& SHColliderComponent::GetCollisionShapes() const noexcept
{ {
return collisionShapes; return shapes;
} }
SHCollisionShape& SHColliderComponent::GetCollisionShape(int index) SHCollisionShape& SHColliderComponent::GetCollisionShape(int index)
{ {
if (index < 0 || static_cast<size_t>(index) >= collisionShapes.size()) const int NUM_SHAPES = static_cast<int>(shapes.size());
throw std::invalid_argument("Out-of-range access!");
return collisionShapes[index]; if (index < 0 || index >= NUM_SHAPES)
throw std::invalid_argument("Out-of-range index!");
return *shapes[index];
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHColliderComponent::SetDebugDrawState(bool state) noexcept
{
state ? flags |= DRAW_FLAG : flags &= ~(DRAW_FLAG);
#ifdef SHEDITOR
// Broadcast event for the Debug Draw system to catch
const SHColliderOnDebugDrawEvent EVENT_DATA
{
.entityID = GetEID()
, .debugDrawState = state
};
SHEventManager::BroadcastEvent<SHColliderOnDebugDrawEvent>(EVENT_DATA, SH_PHYSICS_COLLIDER_DRAW_EVENT);
#endif
}
void SHColliderComponent::SetFactory(rp3d::PhysicsCommon* physicsCommon) noexcept
{
factory = physicsCommon;
}
void SHColliderComponent::SetCollisionBody(rp3d::CollisionBody* body) noexcept
{
collisionBody = body;
}
void SHColliderComponent::SetTransform(const SHTransform& newTransform) noexcept
{
flags |= MOVED_FLAG;
transform = newTransform;
}
void SHColliderComponent::SetPosition(const SHVec3& newPosition) noexcept
{
flags |= MOVED_FLAG;
transform.position = newPosition;
}
void SHColliderComponent::SetOrientation(const SHQuaternion& newOrientation) noexcept
{
flags |= MOVED_FLAG;
transform.orientation = newOrientation;
}
void SHColliderComponent::SetScale(const SHVec3& newScale) noexcept
{
flags |= MOVED_FLAG;
transform.scale = newScale;
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */ /* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHColliderComponent::OnCreate() const SHMatrix& SHColliderComponent::ComputeTRS() noexcept
{ {
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>(); return transform.ComputeTRS();
if (!physicsSystem) }
int SHColliderComponent::AddSphereCollisionShape(float relativeRadius, const SHVec3& posOffset, const SHVec3& rotOffset)
{ {
SHLOG_ERROR("Physics System does not exist to link with Physics Components!") SHASSERT(factory, "Physics factory missing from Collider Component! Unable to add colliders!")
const float SPHERE_SCALE = std::fabs(SHMath::Max({ transform.scale.x, transform.scale.y, transform.scale.z }));
// Create collision shape
shapes.emplace_back(new SHSphere{});
auto* newSphere = dynamic_cast<SHSphere*>(shapes.back());
newSphere->collider = this;
newSphere->positionOffset = posOffset;
newSphere->rotationOffset = rotOffset;
newSphere->relativeRadius = relativeRadius;
newSphere->scale = SPHERE_SCALE;
rp3d::SphereShape* rp3dSphere = factory->createSphereShape(relativeRadius * SPHERE_SCALE * 0.5f);
const rp3d::Transform OFFSETS{ posOffset, SHQuaternion::FromEuler(rotOffset) };
newSphere->rp3dCollider = collisionBody->addCollider(rp3dSphere, OFFSETS);
const uint32_t NEW_INDEX = static_cast<uint32_t>(shapes.size());
// Broadcast Event for adding a shape
const SHPhysicsColliderAddedEvent EVENT_DATA
{
.entityID = GetEID()
, .colliderType = SHCollisionShape::Type::BOX
, .colliderIndex = static_cast<int>(NEW_INDEX)
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
dynamic_cast<rp3d::RigidBody*>(collisionBody)->updateMassPropertiesFromColliders();
return static_cast<int>(NEW_INDEX);
}
int SHColliderComponent::AddBoxCollisionShape(const SHVec3& relativeExtents, const SHVec3& posOffset, const SHVec3& rotOffset)
{
SHASSERT(factory, "Physics factory missing from Collider Component! Unable to add colliders!")
// Create collision shape
shapes.emplace_back(new SHBox{});
auto* newBox = dynamic_cast<SHBox*>(shapes.back());
newBox->collider = this;
newBox->positionOffset = posOffset;
newBox->rotationOffset = rotOffset;
newBox->relativeExtents = relativeExtents;
newBox->scale = SHVec3::Abs(transform.scale);
rp3d::BoxShape* rp3dBox = factory->createBoxShape(relativeExtents * newBox->scale * 0.5f);
const rp3d::Transform OFFSETS{ posOffset, SHQuaternion::FromEuler(rotOffset) };
newBox->rp3dCollider = collisionBody->addCollider(rp3dBox, OFFSETS);
const uint32_t NEW_INDEX = static_cast<uint32_t>(shapes.size());
// Broadcast Event for adding a shape
const SHPhysicsColliderAddedEvent EVENT_DATA
{
.entityID = GetEID()
, .colliderType = SHCollisionShape::Type::BOX
, .colliderIndex = static_cast<int>(NEW_INDEX)
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
dynamic_cast<rp3d::RigidBody*>(collisionBody)->updateMassPropertiesFromColliders();
return static_cast<int>(NEW_INDEX);
}
void SHColliderComponent::RemoveCollisionShape(int index)
{
const int NUM_SHAPES = static_cast<int>(shapes.size());
if (index < 0 || index >= NUM_SHAPES)
throw std::invalid_argument("Out-of-range index!");
int i = 0;
for (auto shapeIter = shapes.begin(); shapeIter != shapes.end(); ++i, ++shapeIter)
{
if (i == index)
{
collisionBody->removeCollider((*shapeIter)->rp3dCollider);
dynamic_cast<rp3d::RigidBody*>(collisionBody)->updateMassPropertiesFromColliders();
const SHPhysicsColliderRemovedEvent EVENT_DATA
{
.entityID = GetEID()
, .colliderType = (*shapeIter)->GetType()
, .colliderIndex = index
};
// Broadcast Event for removing a shape
SHEventManager::BroadcastEvent<SHPhysicsColliderRemovedEvent>(EVENT_DATA, SH_PHYSICS_COLLIDER_REMOVED_EVENT);
SHLOG_INFO_D("Removing Collision Shape {} from Entity {}", index, GetEID())
delete *shapeIter;
shapeIter = shapes.erase(shapeIter);
return; return;
} }
}
}
system = physicsSystem; void SHColliderComponent::Update() noexcept
// Sync with transform if one already exists
if (auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(GetEID()); transformComponent)
{ {
position = transformComponent->GetWorldPosition(); for (auto& shape : shapes)
orientation = transformComponent->GetWorldOrientation(); shape->Update();
scale = transformComponent->GetWorldScale();
}
} }
void SHColliderComponent::OnDestroy()
{
}
void SHColliderComponent::RecomputeCollisionShapes() noexcept
{
for (auto& collisionShape : collisionShapes)
{
switch (collisionShape.GetType())
{
case SHCollisionShape::Type::BOX:
{
auto* box = reinterpret_cast<SHBox*>(collisionShape.shape);
const SHVec3& RELATIVE_EXTENTS = box->GetRelativeExtents();
// Recompute world extents based on new scale and fixed relative extents
const SHVec3 WORLD_EXTENTS = RELATIVE_EXTENTS * (scale * 0.5f);
box->SetWorldExtents(WORLD_EXTENTS);
continue;
}
case SHCollisionShape::Type::SPHERE:
{
auto* sphere = reinterpret_cast<SHSphere*>(collisionShape.shape);
const float RELATIVE_RADIUS = sphere->GetRelativeRadius();
// Recompute world radius based on new scale and fixed radius
const float MAX_SCALE = SHMath::Max({ scale.x, scale.y, scale.z });
const float WORLD_RADIUS = RELATIVE_RADIUS * MAX_SCALE * 0.5f;
sphere->SetWorldRadius(WORLD_RADIUS);
continue;
}
default: continue;
}
}
}
int SHColliderComponent::AddBoundingBox(const SHVec3& halfExtents, const SHVec3& posOffset, const SHVec3& rotOffset) noexcept
{
if (!system)
{
SHLOG_ERROR("Physics system does not exist, unable to add Box Collider!")
return -1;
}
static constexpr auto TYPE = SHCollisionShape::Type::BOX;
auto& collider = collisionShapes.emplace_back(SHCollisionShape{ GetEID(), TYPE });
collider.entityID = GetEID();
collider.SetPositionOffset(posOffset);
collider.SetRotationOffset(rotOffset);
collider.SetBoundingBox(halfExtents);
// Notify Physics System
const int NEW_SHAPE_INDEX = 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
{
if (!system)
{
SHLOG_ERROR("Physics system does not exist, unable to add Sphere Collider!")
return -1;
}
static constexpr auto TYPE = SHCollisionShape::Type::SPHERE;
auto& collider = collisionShapes.emplace_back(SHCollisionShape{ GetEID(), TYPE });
collider.entityID = GetEID();
collider.SetPositionOffset(posOffset);
collider.SetBoundingSphere(radius);
// Notify Physics System
const int NEW_SHAPE_INDEX = static_cast<int>(collisionShapes.size()) - 1;
system->AddCollisionShape(GetEID(), NEW_SHAPE_INDEX);
return NEW_SHAPE_INDEX;
}
void SHColliderComponent::RemoveCollider(int index)
{
if (index < 0 || static_cast<size_t>(index) >= collisionShapes.size())
throw std::invalid_argument("Out-of-range access!");
int idx = 0;
auto it = collisionShapes.begin();
for (; it != collisionShapes.end(); ++it)
{
if (idx == index)
break;
++idx;
}
it = collisionShapes.erase(it);
// Notify Physics System
if (!system)
{
SHLOG_ERROR("Physics system does not exist, unable to remove Collider!")
return;
}
system->RemoveCollisionShape(GetEID(), index);
}
} // namespace SHADE } // namespace SHADE

View File

@ -10,18 +10,24 @@
#pragma once #pragma once
#include <vector>
#include <rttr/registration> #include <rttr/registration>
// Project Headers // Project Headers
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "Math/Geometry/SHBox.h" #include "Math/Transform/SHTransform.h"
#include "Math/Geometry/SHSphere.h" #include "Physics/Collision/Shapes/SHCollisionShape.h"
#include "SHCollisionShape.h"
//namespace SHADE /*-------------------------------------------------------------------------------------*/
//{ /* Forward Declarations */
// class SHPhysicsSystem; /*-------------------------------------------------------------------------------------*/
//}
namespace reactphysics3d
{
class PhysicsCommon;
class CollisionBody;
}
namespace SHADE namespace SHADE
{ {
@ -37,13 +43,13 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem; friend class SHPhysicsSystem;
friend class SHPhysicsObject; friend class SHPhysicsObjectManager;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
using CollisionShapes = std::vector<SHCollisionShape>; using CollisionShapes = std::vector<SHCollisionShape*>;
public: public:
@ -67,29 +73,88 @@ namespace SHADE
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] bool HasChanged () const noexcept; [[nodiscard]] bool GetDebugDrawState () const noexcept;
[[nodiscard]] const SHTransform& GetTransform () const noexcept;
[[nodiscard]] const SHVec3& GetPosition () const noexcept; [[nodiscard]] const SHVec3& GetPosition () const noexcept;
[[nodiscard]] const SHQuaternion& GetOrientation () const noexcept; [[nodiscard]] const SHQuaternion& GetOrientation () const noexcept;
[[nodiscard]] SHVec3 GetRotation () const noexcept;
[[nodiscard]] const SHVec3& GetScale () const noexcept; [[nodiscard]] const SHVec3& GetScale () const noexcept;
[[nodiscard]] const CollisionShapes& GetCollisionShapes () const noexcept; [[nodiscard]] const CollisionShapes& GetCollisionShapes () const noexcept;
[[nodiscard]] SHCollisionShape& GetCollisionShape (int index); [[nodiscard]] SHCollisionShape& GetCollisionShape (int index);
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetDebugDrawState (bool state) noexcept;
void SetFactory (reactphysics3d::PhysicsCommon* physicsCommon) noexcept;
void SetCollisionBody (reactphysics3d::CollisionBody* body) noexcept;
void SetTransform (const SHTransform& newTransform) noexcept;
void SetPosition (const SHVec3& newPosition) noexcept;
void SetOrientation (const SHQuaternion& newOrientation) noexcept;
void SetScale (const SHVec3& newScale) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void OnCreate () override; /**
void OnDestroy () override; * @brief
* Computes the TRS for the collider's transform
* @return
* The computed TRS.
*/
const SHMatrix& ComputeTRS() noexcept;
void RecomputeCollisionShapes () noexcept; /**
* @brief
* Adds a sphere collision shape.
* @param relativeRadius
* The relative radius is constructed with respect to the world scale. <br/>
* Radius = max(scale.x, scale.y, scale.z) * 0.5 * relativeRadius
* @param posOffset
* The position offset of the sphere from the center of the collider. Defaults to a Zero Vector.
* @param rotOffset
* The rotation offset of the sphere from the rotation of the collider. Defaults to a Zero Vector.
* @return
* The index of the newly added shape.
*/
int AddSphereCollisionShape (float relativeRadius, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero);
void RemoveCollider (int index); /**
* @brief
* Adds a box collision shape.
* @param relativeExtents
* The relative extents are constructed with respect to the world scale. <br/>
* Extents = scale * 0.5 * relativeExtents
* @param posOffset
* The position offset of the box from the center of the collider. Defaults to a Zero Vector.
* @param rotOffset
* The rotation offset of the box from the rotation of the collider. Defaults to a Zero Vector.
* @return
* The index of the newly added shape.
*/
int AddBoxCollisionShape (const SHVec3& relativeExtents, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero);
int AddBoundingBox (const SHVec3& halfExtents = SHVec3::One, const SHVec3& posOffset = SHVec3::Zero, const SHVec3& rotOffset = SHVec3::Zero) noexcept; /**
int AddBoundingSphere (float radius = 1.0f, const SHVec3& posOffset = SHVec3::Zero) noexcept; * @brief
* Removes a shape from the container. Removal reduces the size of the container.
* If removing all, perform removal from back to front.
* @param index
* The index of the shape to remove.
* @throws
* Invalid argument for out-of-range indices.
*/
void RemoveCollisionShape (int index);
/**
* @brief
* Recomputes the transforms for all shapes in this composite collider.
*/
void Update () noexcept;
private: private:
@ -97,12 +162,15 @@ namespace SHADE
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHPhysicsSystem* system; static constexpr uint8_t ACTIVE_FLAG = 1U << 0;
static constexpr uint8_t DRAW_FLAG = 1U << 1;
static constexpr uint8_t MOVED_FLAG = 1U << 2;
SHVec3 position; uint8_t flags; // 0 0 0 0 0 hasMoved debugDraw active
SHQuaternion orientation; reactphysics3d::PhysicsCommon* factory;
SHVec3 scale; reactphysics3d::CollisionBody* collisionBody;
CollisionShapes collisionShapes; SHTransform transform;
CollisionShapes shapes;
RTTR_ENABLE() RTTR_ENABLE()
}; };

View File

@ -1,368 +0,0 @@
/****************************************************************************************
* \file SHCollider.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Collider.
*
* \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 "SHCollisionShape.h"
// Project Headers
#include "Math/Geometry/SHBox.h"
#include "Math/Geometry/SHSphere.h"
#include "Math/SHMathHelpers.h"
#include "Physics/Collision/SHCollisionTagMatrix.h"
#include "Reflection/SHReflectionMetadata.h"
#include "SHColliderComponent.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHCollisionShape::SHCollisionShape(EntityID eid, Type colliderType, const SHPhysicsMaterial& physicsMaterial)
: type { colliderType }
, entityID { eid }
, isTrigger { false }
, dirty { true }
, shape { nullptr }
, material { physicsMaterial }
, collisionTag { SHCollisionTagMatrix::GetTag(0) }
{
switch (type)
{
case Type::BOX:
{
shape = new SHBox{ SHVec3::Zero, SHVec3::One };
break;
}
case Type::SPHERE:
{
shape = new SHSphere{ SHVec3::Zero, 0.5f };
break;
}
default: break;
}
}
SHCollisionShape::SHCollisionShape(const SHCollisionShape& rhs) noexcept
: type { rhs.type}
, entityID { rhs.entityID }
, isTrigger { rhs.isTrigger }
, dirty { true }
, shape { nullptr }
, material { rhs.material }
, positionOffset { rhs.positionOffset }
, rotationOffset { rhs.rotationOffset }
, collisionTag { rhs.collisionTag }
{
CopyShape(rhs.shape);
}
SHCollisionShape::SHCollisionShape(SHCollisionShape&& rhs) noexcept
: type { rhs.type}
, entityID { rhs.entityID }
, isTrigger { rhs.isTrigger }
, dirty { true }
, shape { nullptr }
, material { rhs.material }
, positionOffset { rhs.positionOffset }
, rotationOffset { rhs.rotationOffset }
, collisionTag { rhs.collisionTag }
{
CopyShape(rhs.shape);
}
SHCollisionShape::~SHCollisionShape() noexcept
{
shape = nullptr;
}
/*-----------------------------------------------------------------------------------*/
/* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/
SHCollisionShape& SHCollisionShape::operator=(const SHCollisionShape& rhs) noexcept
{
if (this == &rhs)
return *this;
type = rhs.type;
entityID = rhs.entityID;
isTrigger = rhs.isTrigger;
dirty = true;
material = rhs.material;
positionOffset = rhs.positionOffset;
rotationOffset = rhs.rotationOffset;
collisionTag = rhs.collisionTag;
delete shape;
CopyShape(rhs.shape);
return *this;
}
SHCollisionShape& SHCollisionShape::operator=(SHCollisionShape&& rhs) noexcept
{
type = rhs.type;
entityID = rhs.entityID;
isTrigger = rhs.isTrigger;
dirty = true;
material = rhs.material;
positionOffset = rhs.positionOffset;
rotationOffset = rhs.rotationOffset;
collisionTag = rhs.collisionTag;
delete shape;
CopyShape(rhs.shape);
return *this;
}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
bool SHCollisionShape::HasChanged() const noexcept
{
return dirty;
}
bool SHCollisionShape::IsTrigger() const noexcept
{
return isTrigger;
}
SHCollisionShape::Type SHCollisionShape::GetType() const noexcept
{
return type;
}
const SHCollisionTag& SHCollisionShape::GetCollisionTag() const noexcept
{
return *collisionTag;
}
float SHCollisionShape::GetFriction() const noexcept
{
return material.GetFriction();
}
float SHCollisionShape::GetBounciness() const noexcept
{
return material.GetBounciness();
}
float SHCollisionShape::GetDensity() const noexcept
{
return material.GetDensity();
}
const SHPhysicsMaterial& SHCollisionShape::GetMaterial() const noexcept
{
return material;
}
const SHVec3& SHCollisionShape::GetPositionOffset() const noexcept
{
return positionOffset;
}
const SHVec3& SHCollisionShape::GetRotationOffset() const noexcept
{
return rotationOffset;
}
const SHShape* SHCollisionShape::GetShape() const noexcept
{
return shape;
}
/*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionShape::SetBoundingBox(const SHVec3& halfExtents)
{
dirty = true;
const auto* COLLIDER = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
auto* box = reinterpret_cast<SHBox*>(shape);
SHVec3 correctedHalfExtents = halfExtents;
// Get current relative halfExtents for error checking. 0 is ignored
const SHVec3& CURRENT_RELATIVE_EXTENTS = box->GetRelativeExtents();
for (size_t i = 0; i < SHVec3::SIZE; ++i)
{
if (SHMath::CompareFloat(halfExtents[i], 0.0f))
correctedHalfExtents[i] = CURRENT_RELATIVE_EXTENTS[i];
}
// Set the half extents relative to world scale
const SHVec3 WORLD_EXTENTS = correctedHalfExtents * COLLIDER->GetScale() * 0.5f;
if (type != Type::BOX)
{
type = Type::BOX;
delete shape;
shape = new SHBox{ positionOffset, WORLD_EXTENTS };
}
box->SetWorldExtents(WORLD_EXTENTS);
box->SetRelativeExtents(correctedHalfExtents);
}
void SHCollisionShape::SetBoundingSphere(float radius)
{
dirty = true;
auto* sphere = reinterpret_cast<SHSphere*>(shape);
const auto* COLLIDER = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
// Get current relative halfExtents for error checking. 0 is ignored
const float CURRENT_RELATIVE_RADIUS = sphere->GetRelativeRadius();
if (SHMath::CompareFloat(radius, 0.0f))
radius = CURRENT_RELATIVE_RADIUS;
// Set the radius relative to world scale
const SHVec3 WORLD_SCALE = COLLIDER->GetScale();
const float MAX_SCALE = SHMath::Max({ WORLD_SCALE.x, WORLD_SCALE.y, WORLD_SCALE.z });
const float WORLD_RADIUS = radius * MAX_SCALE * 0.5f;
if (type != Type::SPHERE)
{
type = Type::SPHERE;
delete shape;
shape = new SHSphere{ positionOffset, WORLD_RADIUS };
}
sphere->SetWorldRadius(WORLD_RADIUS);
sphere->SetRelativeRadius(radius);
}
void SHCollisionShape::SetIsTrigger(bool trigger) noexcept
{
dirty = true;
isTrigger = trigger;
}
void SHCollisionShape::SetCollisionTag(SHCollisionTag* newCollisionTag) noexcept
{
dirty = true;
collisionTag = newCollisionTag;
}
void SHCollisionShape::SetFriction(float friction) noexcept
{
dirty = true;
material.SetFriction(friction);
}
void SHCollisionShape::SetBounciness(float bounciness) noexcept
{
dirty = true;
material.SetBounciness(bounciness);
}
void SHCollisionShape::SetDensity(float density) noexcept
{
dirty = true;
material.SetDensity(density);
}
void SHCollisionShape::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept
{
dirty = true;
material = newMaterial;
}
void SHCollisionShape::SetPositionOffset(const SHVec3& posOffset) noexcept
{
dirty = true;
positionOffset = posOffset;
switch (type)
{
case Type::BOX:
{
reinterpret_cast<SHBox*>(shape)->SetCenter(positionOffset);
break;
}
case Type::SPHERE:
{
reinterpret_cast<SHSphere*>(shape)->SetCenter(positionOffset);
break;
}
default: break;
}
}
void SHCollisionShape::SetRotationOffset(const SHVec3& rotOffset) noexcept
{
dirty = true;
rotationOffset = rotOffset;
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionShape::CopyShape(const SHShape* rhs)
{
switch (type)
{
case Type::BOX:
{
const auto* RHS_BOX = reinterpret_cast<const SHBox*>(rhs);
shape = new SHBox{ positionOffset, RHS_BOX->GetWorldExtents() };
auto* lhsBox = reinterpret_cast<SHBox*>(shape);
lhsBox->SetRelativeExtents(RHS_BOX->GetRelativeExtents());
break;
}
case Type::SPHERE:
{
const auto* RHS_SPHERE = reinterpret_cast<const SHSphere*>(rhs);
shape = new SHSphere{ positionOffset, RHS_SPHERE->GetWorldRadius() };
auto* lhsSphere = reinterpret_cast<SHSphere*>(shape);
lhsSphere->SetRelativeRadius(RHS_SPHERE->GetRelativeRadius());
break;
}
default: break;
}
}
} // namespace SHADE
RTTR_REGISTRATION
{
using namespace SHADE;
using namespace rttr;
registration::enumeration<SHCollisionShape::Type>("Collider Type")
(
value("Box", SHCollisionShape::Type::BOX),
value("Sphere", SHCollisionShape::Type::SPHERE)
// TODO(Diren): Add More Shapes
);
registration::class_<SHCollisionShape>("Collider")
.property("IsTrigger" , &SHCollisionShape::IsTrigger , &SHCollisionShape::SetIsTrigger )
.property("Friction" , &SHCollisionShape::GetFriction , &SHCollisionShape::SetFriction )
.property("Bounciness" , &SHCollisionShape::GetBounciness , &SHCollisionShape::SetBounciness )
.property("Density" , &SHCollisionShape::GetDensity , &SHCollisionShape::SetDensity )
.property("Position Offset" , &SHCollisionShape::GetPositionOffset, &SHCollisionShape::SetPositionOffset)
.property("Rotation Offset" , &SHCollisionShape::GetRotationOffset, &SHCollisionShape::SetRotationOffset) (metadata(META::angleInRad, true));
}

View File

@ -1,134 +0,0 @@
/****************************************************************************************
* \file SHCollider.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Collider.
*
* \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 <rttr/registration>
// Project Headers
#include "ECS_Base/Entity/SHEntity.h"
#include "Math/Geometry/SHShape.h"
#include "Math/SHQuaternion.h"
#include "SHPhysicsMaterial.h"
#include "Physics/Collision/SHCollisionTags.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHCollisionShape
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHColliderComponent;
friend class SHPhysicsObject;
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class Type
{
BOX
, SPHERE
, CAPSULE
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHCollisionShape (EntityID eid, Type colliderType = Type::BOX, const SHPhysicsMaterial& physicsMaterial = SHPhysicsMaterial::DEFAULT);
SHCollisionShape (const SHCollisionShape& rhs) noexcept;
SHCollisionShape (SHCollisionShape&& rhs) noexcept;
~SHCollisionShape () noexcept;
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
SHCollisionShape& operator=(const SHCollisionShape& rhs) noexcept;
SHCollisionShape& operator=(SHCollisionShape&& rhs) noexcept;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] bool HasChanged () const noexcept;
[[nodiscard]] bool IsTrigger () const noexcept;
[[nodiscard]] Type GetType () const noexcept;
[[nodiscard]] const SHCollisionTag& GetCollisionTag () const noexcept;
[[nodiscard]] float GetFriction () const noexcept;
[[nodiscard]] float GetBounciness () const noexcept;
[[nodiscard]] float GetDensity () const noexcept;
[[nodiscard]] const SHPhysicsMaterial& GetMaterial () const noexcept;
[[nodiscard]] const SHVec3& GetPositionOffset () const noexcept;
[[nodiscard]] const SHVec3& GetRotationOffset () const noexcept;
[[nodiscard]] const SHShape* GetShape () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetBoundingBox (const SHVec3& halfExtents);
void SetBoundingSphere (float radius);
void SetIsTrigger (bool isTrigger) noexcept;
void SetCollisionTag (SHCollisionTag* newCollisionTag) noexcept;
void SetFriction (float friction) noexcept;
void SetBounciness (float bounciness) noexcept;
void SetDensity (float density) noexcept;
void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept;
void SetPositionOffset (const SHVec3& posOffset) noexcept;
void SetRotationOffset (const SHVec3& rotOffset) noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
Type type;
EntityID entityID; // The entity this collider belongs to
bool isTrigger;
bool dirty;
SHShape* shape;
SHPhysicsMaterial material;
SHVec3 positionOffset;
SHVec3 rotationOffset;
SHCollisionTag* collisionTag;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void CopyShape(const SHShape* rhs);
RTTR_ENABLE()
};
} // namespace SHADE

View File

@ -20,6 +20,7 @@
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Math/SHMathHelpers.h" #include "Math/SHMathHelpers.h"
#include "Physics/System/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE namespace SHADE
{ {
@ -29,99 +30,78 @@ namespace SHADE
SHRigidBodyComponent::SHRigidBodyComponent() noexcept SHRigidBodyComponent::SHRigidBodyComponent() noexcept
: type { Type::DYNAMIC } : type { Type::DYNAMIC }
, interpolate { true }
, flags { 0 } , flags { 0 }
, dirtyFlags { std::numeric_limits<uint16_t>::max() }
, mass { 1.0f }
, drag { 0.01f } , drag { 0.01f }
, angularDrag { 0.01f } , angularDrag { 0.1f }
, system { nullptr } , rigidBody { nullptr }
{ {
// Initialise default flags // Default flags
flags |= 1U << 0; // Gravity set to true flags |= 1U << 0; // enable gravity
flags |= 1U << 1; // Sleeping allowed
flags |= 1U << 8; // Interpolate by default
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */ /* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
bool SHRigidBodyComponent::IsGravityEnabled() const noexcept
{
static constexpr int FLAG_POS = 0;
return flags & (1U << FLAG_POS);
}
bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept
{
static constexpr int FLAG_POS = 1;
return flags & (1U << FLAG_POS);
}
bool SHRigidBodyComponent::IsInterpolating() const noexcept
{
static constexpr int FLAG_POS = 8;
return flags & (1U << FLAG_POS);
}
bool SHRigidBodyComponent::GetIsSleeping() const noexcept
{
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject)
return physicsObject->GetRigidBody()->isSleeping();
return false;
}
SHRigidBodyComponent::Type SHRigidBodyComponent::GetType() const noexcept SHRigidBodyComponent::Type SHRigidBodyComponent::GetType() const noexcept
{ {
return type; return type;
} }
bool SHRigidBodyComponent::IsGravityEnabled() const noexcept
{
return flags & SHUtilities::ConvertEnum(Flags::GRAVITY);
}
bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept
{
return flags & SHUtilities::ConvertEnum(Flags::SLEEPING);
}
bool SHRigidBodyComponent::IsInterpolating() const noexcept
{
return interpolate;
}
bool SHRigidBodyComponent::IsSleeping() const noexcept
{
return rigidBody ? rigidBody->isSleeping() : false;
}
bool SHRigidBodyComponent::GetFreezePositionX() const noexcept bool SHRigidBodyComponent::GetFreezePositionX() const noexcept
{ {
static constexpr int FLAG_POS = 2; return flags & SHUtilities::ConvertEnum(Flags::LINEAR_X);
return flags & (1U << FLAG_POS);
} }
bool SHRigidBodyComponent::GetFreezePositionY() const noexcept bool SHRigidBodyComponent::GetFreezePositionY() const noexcept
{ {
static constexpr int FLAG_POS = 3; return flags & SHUtilities::ConvertEnum(Flags::LINEAR_Y);
return flags & (1U << FLAG_POS);
} }
bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept
{ {
static constexpr int FLAG_POS = 4; return flags & SHUtilities::ConvertEnum(Flags::LINEAR_Z);
return flags & (1U << FLAG_POS);
} }
bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept
{ {
static constexpr int FLAG_POS = 5; return flags & SHUtilities::ConvertEnum(Flags::ANGULAR_X);
return flags & (1U << FLAG_POS);
} }
bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept
{ {
static constexpr int FLAG_POS = 6; return flags & SHUtilities::ConvertEnum(Flags::ANGULAR_Y);
return flags & (1U << FLAG_POS);
} }
bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept
{ {
static constexpr int FLAG_POS = 7; return flags & SHUtilities::ConvertEnum(Flags::ANGULAR_Z);
return flags & (1U << FLAG_POS);
} }
//bool SHRigidBodyComponent::GetAutoMass() const noexcept
//{
// static constexpr int FLAG_POS = 9;
// return flags & (1U << FLAG_POS);
//}
float SHRigidBodyComponent::GetMass() const noexcept float SHRigidBodyComponent::GetMass() const noexcept
{ {
return mass; return rigidBody ? rigidBody->getMass() : 0.0f;
} }
float SHRigidBodyComponent::GetDrag() const noexcept float SHRigidBodyComponent::GetDrag() const noexcept
@ -136,49 +116,32 @@ namespace SHADE
SHVec3 SHRigidBodyComponent::GetForce() const noexcept SHVec3 SHRigidBodyComponent::GetForce() const noexcept
{ {
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) return rigidBody ? SHVec3{ rigidBody->getForce() } : SHVec3::Zero;
return physicsObject->GetRigidBody()->getForce();
return SHVec3::Zero;
} }
SHVec3 SHRigidBodyComponent::GetTorque() const noexcept SHVec3 SHRigidBodyComponent::GetTorque() const noexcept
{ {
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) return rigidBody ? SHVec3{ rigidBody->getTorque() } : SHVec3::Zero;
return physicsObject->GetRigidBody()->getTorque();
return SHVec3::Zero;
} }
SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept
{ {
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) return rigidBody ? SHVec3{ rigidBody->getLinearVelocity() } : SHVec3::Zero;
return physicsObject->GetRigidBody()->getLinearVelocity();
return SHVec3::Zero;
} }
SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept
{ {
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) return rigidBody ? SHVec3{ rigidBody->getAngularVelocity() } : SHVec3::Zero;
return physicsObject->GetRigidBody()->getAngularVelocity();
return SHVec3::Zero;
} }
const SHVec3& SHRigidBodyComponent::GetPosition() const noexcept SHVec3 SHRigidBodyComponent::GetPosition() const noexcept
{ {
return position; return rigidBody ? SHVec3{ rigidBody->getTransform().getPosition() } : SHVec3::Zero;
}
const SHQuaternion& SHRigidBodyComponent::GetOrientation() const noexcept
{
return orientation;
} }
SHVec3 SHRigidBodyComponent::GetRotation() const noexcept SHVec3 SHRigidBodyComponent::GetRotation() const noexcept
{ {
return orientation.ToEuler(); return rigidBody ? SHQuaternion{ rigidBody->getTransform().getOrientation() }.ToEuler() : SHVec3::Zero;
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -187,224 +150,174 @@ 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;
SHASSERT(rigidBody, "Unable to find rp3dBody on RigidBodyComponent!")
switch (type)
{
case Type::STATIC:
rigidBody->setType(rp3d::BodyType::STATIC);
break;
case Type::KINEMATIC:
rigidBody->setType(rp3d::BodyType::KINEMATIC);
break;
case Type::DYNAMIC:
rigidBody->setType(rp3d::BodyType::DYNAMIC);
break;
default:
break;
} }
}
void SHRigidBodyComponent::SetRigidBody(rp3d::RigidBody* body) noexcept
{
rigidBody = body;
}
void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept
{ {
static constexpr int FLAG_POS = 0; constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::GRAVITY);
enableGravity ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type != Type::DYNAMIC) if (rigidBody)
{ rigidBody->enableGravity(enableGravity);
SHLOG_WARNING("Cannot enable gravity of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << FLAG_POS;
enableGravity ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
} }
void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept
{ {
static constexpr int FLAG_POS = 1; constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::SLEEPING);
isAllowedToSleep ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type != Type::DYNAMIC) if (rigidBody)
{ rigidBody->setIsAllowedToSleep(isAllowedToSleep);
SHLOG_WARNING("Cannot enable sleeping of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << FLAG_POS;
isAllowedToSleep ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
} }
void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept
{ {
static constexpr int FLAG_POS = 2; constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::LINEAR_X);
freezePositionX ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type == Type::STATIC) if (rigidBody)
{ {
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) rp3d::Vector3 linearLock = rigidBody->getLinearLockAxisFactor();
return; linearLock.x = freezePositionX ? 0.0f : 1.0f;
rigidBody->setLinearLockAxisFactor(linearLock);
} }
dirtyFlags |= 1U << FLAG_POS;
freezePositionX ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
} }
void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept
{ {
static constexpr int FLAG_POS = 3; constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::LINEAR_Y);
freezePositionY ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type == Type::STATIC) if (rigidBody)
{ {
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) rp3d::Vector3 linearLock = rigidBody->getLinearLockAxisFactor();
return; linearLock.y = freezePositionY ? 0.0f : 1.0f;
rigidBody->setLinearLockAxisFactor(linearLock);
} }
dirtyFlags |= 1U << FLAG_POS;
freezePositionY ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
} }
void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept
{ {
static constexpr int FLAG_POS = 4; constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::LINEAR_Z);
freezePositionZ ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type == Type::STATIC) if (rigidBody)
{ {
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID()) rp3d::Vector3 linearLock = rigidBody->getLinearLockAxisFactor();
return; linearLock.z = freezePositionZ ? 0.0f : 1.0f;
rigidBody->setLinearLockAxisFactor(linearLock);
} }
dirtyFlags |= 1U << FLAG_POS;
freezePositionZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
} }
void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept
{ {
static constexpr int FLAG_POS = 5; constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::ANGULAR_X);
freezeRotationX ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type == Type::STATIC) if (rigidBody)
{ {
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) rp3d::Vector3 angularLock = rigidBody->getAngularLockAxisFactor();
return; angularLock.x = freezeRotationX ? 0.0f : 1.0f;
rigidBody->setAngularLockAxisFactor(angularLock);
} }
dirtyFlags |= 1U << FLAG_POS;
freezeRotationX ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
} }
void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept
{ {
static constexpr int FLAG_POS = 6; constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::ANGULAR_Y);
freezeRotationY ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type == Type::STATIC) if (rigidBody)
{ {
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) rp3d::Vector3 angularLock = rigidBody->getAngularLockAxisFactor();
return; angularLock.y = freezeRotationY ? 0.0f : 1.0f;
rigidBody->setAngularLockAxisFactor(angularLock);
} }
dirtyFlags |= 1U << FLAG_POS;
freezeRotationY ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
} }
void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept
{ {
static constexpr int FLAG_POS = 7; constexpr uint8_t FLAG_VALUE = SHUtilities::ConvertEnum(Flags::ANGULAR_Z);
freezeRotationZ ? flags |= FLAG_VALUE : flags &= ~FLAG_VALUE;
if (type == Type::STATIC) if (rigidBody)
{ {
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID()) rp3d::Vector3 angularLock = rigidBody->getAngularLockAxisFactor();
return; angularLock.z = freezeRotationZ ? 0.0f : 1.0f;
rigidBody->setAngularLockAxisFactor(angularLock);
} }
dirtyFlags |= 1U << FLAG_POS;
freezeRotationZ ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
} }
void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept
{ {
static constexpr int FLAG_POS = 8; interpolate = allowInterpolation;
allowInterpolation ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
} }
//void SHRigidBodyComponent::SetAutoMass(bool autoMass) noexcept
//{
// static constexpr int FLAG_POS = 9;
// autoMass ? flags |= 1U << FLAG_POS : flags &= ~(1U << FLAG_POS);
// dirtyFlags |= 1U << FLAG_POS;
//}
//void SHRigidBodyComponent::SetMass(float newMass) noexcept
//{
// static constexpr int FLAG_POS = 9;
// if (newMass < 0.0f)
// return;
// if (type != Type::DYNAMIC)
// {
// SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID())
// return;
// }
// dirtyFlags |= 1U << FLAG_POS;
// mass = newMass;
// // Turn off automass
// flags &= ~(1U << FLAG_POS);
//}
void SHRigidBodyComponent::SetDrag(float newDrag) noexcept void SHRigidBodyComponent::SetDrag(float newDrag) noexcept
{ {
static constexpr int FLAG_POS = 10;
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot set drag of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << FLAG_POS;
drag = newDrag; drag = newDrag;
if (rigidBody)
rigidBody->setLinearDamping(newDrag);
} }
void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept
{ {
static constexpr int FLAG_POS = 11;
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot set angular drag of a non-dynamic object {}", GetEID())
return;
}
dirtyFlags |= 1U << FLAG_POS;
angularDrag = newAngularDrag; angularDrag = newAngularDrag;
if (rigidBody)
rigidBody->setAngularDamping(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;
} }
auto* physicsObject = system->GetPhysicsObject(GetEID()); if (rigidBody)
if (!physicsObject) rigidBody->setLinearVelocity(newLinearVelocity);
{
SHLOGV_ERROR("Unable to retrieve physics object of Entity {}", GetEID())
return;
}
physicsObject->GetRigidBody()->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;
} }
auto* physicsObject = system->GetPhysicsObject(GetEID()); if (rigidBody)
if (!physicsObject) rigidBody->setAngularVelocity(newAngularVelocity);
{
SHLOGV_ERROR("Unable to retrieve physics object of Entity {}", GetEID())
return;
}
physicsObject->GetRigidBody()->setAngularVelocity(newAngularVelocity);
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -413,81 +326,67 @@ namespace SHADE
void SHRigidBodyComponent::OnCreate() void SHRigidBodyComponent::OnCreate()
{ {
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!physicsSystem)
{
SHLOG_ERROR("Physics System does not exist to link with Physics Components!")
return;
}
system = physicsSystem;
// Sync with transform if one already exists
if (auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(GetEID()); transformComponent)
{
position = transformComponent->GetWorldPosition();
orientation = transformComponent->GetWorldOrientation();
}
} }
void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept void SHRigidBodyComponent::AddForce(const SHVec3& force) const noexcept
{ {
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) if (rigidBody)
physicsObject->GetRigidBody()->applyWorldForceAtCenterOfMass(force); rigidBody->applyWorldForceAtCenterOfMass(force);
} }
void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept void SHRigidBodyComponent::AddForceAtLocalPos(const SHVec3& force, const SHVec3& localPos) const noexcept
{ {
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) if (rigidBody)
physicsObject->GetRigidBody()->applyWorldForceAtLocalPosition(force, localPos); rigidBody->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 (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) if (rigidBody)
physicsObject->GetRigidBody()->applyWorldForceAtWorldPosition(force, worldPos); rigidBody->applyWorldForceAtWorldPosition(force, worldPos);
} }
void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept void SHRigidBodyComponent::AddRelativeForce(const SHVec3& relativeForce) const noexcept
{ {
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) if (rigidBody)
physicsObject->GetRigidBody()->applyLocalForceAtCenterOfMass(relativeForce); rigidBody->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 (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) if (rigidBody)
physicsObject->GetRigidBody()->applyLocalForceAtLocalPosition(relativeForce, localPos); rigidBody->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 (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) if (rigidBody)
physicsObject->GetRigidBody()->applyLocalForceAtWorldPosition(relativeForce, worldPos); rigidBody->applyLocalForceAtWorldPosition(relativeForce, worldPos);
} }
void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept void SHRigidBodyComponent::AddTorque(const SHVec3& torque) const noexcept
{ {
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) if (rigidBody)
physicsObject->GetRigidBody()->applyWorldTorque(torque); rigidBody->applyWorldTorque(torque);
} }
void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept void SHRigidBodyComponent::AddRelativeTorque(const SHVec3& relativeTorque) const noexcept
{ {
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) if (rigidBody)
physicsObject->GetRigidBody()->applyLocalTorque(relativeTorque); rigidBody->applyLocalTorque(relativeTorque);
} }
void SHRigidBodyComponent::ClearForces() const noexcept void SHRigidBodyComponent::ClearForces() const noexcept
{ {
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) if (rigidBody)
physicsObject->GetRigidBody()->resetForce(); rigidBody->resetForce();
} }
void SHRigidBodyComponent::ClearTorque() const noexcept void SHRigidBodyComponent::ClearTorque() const noexcept
{ {
if (auto* physicsObject = system->GetPhysicsObject(GetEID()); physicsObject) if (rigidBody)
physicsObject->GetRigidBody()->resetTorque(); rigidBody->resetTorque();
} }
} // namespace SHADE } // namespace SHADE
@ -506,13 +405,11 @@ RTTR_REGISTRATION
registration::class_<SHRigidBodyComponent>("RigidBody Component") registration::class_<SHRigidBodyComponent>("RigidBody Component")
.property("Type" , &SHRigidBodyComponent::GetType , &SHRigidBodyComponent::SetType ) .property("Type" , &SHRigidBodyComponent::GetType , &SHRigidBodyComponent::SetType )
//.property("Mass" , &SHRigidBodyComponent::GetMass , &SHRigidBodyComponent::SetMass )
.property("Drag" , &SHRigidBodyComponent::GetDrag , &SHRigidBodyComponent::SetDrag ) .property("Drag" , &SHRigidBodyComponent::GetDrag , &SHRigidBodyComponent::SetDrag )
.property("Angular Drag" , &SHRigidBodyComponent::GetAngularDrag , &SHRigidBodyComponent::SetAngularDrag ) .property("Angular Drag" , &SHRigidBodyComponent::GetAngularDrag , &SHRigidBodyComponent::SetAngularDrag )
.property("Use Gravity" , &SHRigidBodyComponent::IsGravityEnabled , &SHRigidBodyComponent::SetGravityEnabled ) .property("Use Gravity" , &SHRigidBodyComponent::IsGravityEnabled , &SHRigidBodyComponent::SetGravityEnabled )
.property("Interpolate" , &SHRigidBodyComponent::IsInterpolating , &SHRigidBodyComponent::SetInterpolate ) .property("Interpolate" , &SHRigidBodyComponent::IsInterpolating , &SHRigidBodyComponent::SetInterpolate )
.property("Sleeping Enabled" , &SHRigidBodyComponent::IsAllowedToSleep , &SHRigidBodyComponent::SetIsAllowedToSleep) .property("Sleeping Enabled" , &SHRigidBodyComponent::IsAllowedToSleep , &SHRigidBodyComponent::SetIsAllowedToSleep)
//.property("Auto Mass" , &SHRigidBodyComponent::GetAutoMass , &SHRigidBodyComponent::SetAutoMass )
.property("Freeze Position X" , &SHRigidBodyComponent::GetFreezePositionX , &SHRigidBodyComponent::SetFreezePositionX ) .property("Freeze Position X" , &SHRigidBodyComponent::GetFreezePositionX , &SHRigidBodyComponent::SetFreezePositionX )
.property("Freeze Position Y" , &SHRigidBodyComponent::GetFreezePositionY , &SHRigidBodyComponent::SetFreezePositionY ) .property("Freeze Position Y" , &SHRigidBodyComponent::GetFreezePositionY , &SHRigidBodyComponent::SetFreezePositionY )
.property("Freeze Position Z" , &SHRigidBodyComponent::GetFreezePositionZ , &SHRigidBodyComponent::SetFreezePositionZ ) .property("Freeze Position Z" , &SHRigidBodyComponent::GetFreezePositionZ , &SHRigidBodyComponent::SetFreezePositionZ )

View File

@ -17,6 +17,15 @@
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
#include "Math/SHQuaternion.h" #include "Math/SHQuaternion.h"
/*-------------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-------------------------------------------------------------------------------------*/
namespace reactphysics3d
{
class RigidBody;
}
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -31,7 +40,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem; friend class SHPhysicsSystem;
friend class SHPhysicsObject; friend class SHPhysicsObjectManager;
public: public:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -67,13 +76,12 @@ namespace SHADE
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] Type GetType () const noexcept;
[[nodiscard]] bool IsGravityEnabled () const noexcept; [[nodiscard]] bool IsGravityEnabled () const noexcept;
[[nodiscard]] bool IsAllowedToSleep () const noexcept; [[nodiscard]] bool IsAllowedToSleep () const noexcept;
[[nodiscard]] bool IsInterpolating () const noexcept; [[nodiscard]] bool IsInterpolating () const noexcept;
[[nodiscard]] bool IsSleeping () const noexcept;
[[nodiscard]] bool GetIsSleeping () const noexcept;
[[nodiscard]] Type GetType () const noexcept;
[[nodiscard]] bool GetFreezePositionX () const noexcept; [[nodiscard]] bool GetFreezePositionX () const noexcept;
[[nodiscard]] bool GetFreezePositionY () const noexcept; [[nodiscard]] bool GetFreezePositionY () const noexcept;
@ -82,8 +90,6 @@ namespace SHADE
[[nodiscard]] bool GetFreezeRotationY () const noexcept; [[nodiscard]] bool GetFreezeRotationY () const noexcept;
[[nodiscard]] bool GetFreezeRotationZ () const noexcept; [[nodiscard]] bool GetFreezeRotationZ () const noexcept;
//[[nodiscard]] bool GetAutoMass () const noexcept;
[[nodiscard]] float GetMass () const noexcept; [[nodiscard]] float GetMass () const noexcept;
[[nodiscard]] float GetDrag () const noexcept; [[nodiscard]] float GetDrag () const noexcept;
[[nodiscard]] float GetAngularDrag () const noexcept; [[nodiscard]] float GetAngularDrag () const noexcept;
@ -93,8 +99,7 @@ namespace SHADE
[[nodiscard]] SHVec3 GetLinearVelocity () const noexcept; [[nodiscard]] SHVec3 GetLinearVelocity () const noexcept;
[[nodiscard]] SHVec3 GetAngularVelocity () const noexcept; [[nodiscard]] SHVec3 GetAngularVelocity () const noexcept;
[[nodiscard]] const SHVec3& GetPosition () const noexcept; [[nodiscard]] SHVec3 GetPosition () const noexcept;
[[nodiscard]] const SHQuaternion& GetOrientation () const noexcept;
[[nodiscard]] SHVec3 GetRotation () const noexcept; [[nodiscard]] SHVec3 GetRotation () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -103,8 +108,11 @@ namespace SHADE
void SetType (Type newType) noexcept; void SetType (Type newType) noexcept;
void SetRigidBody (reactphysics3d::RigidBody* body) 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;
@ -112,9 +120,7 @@ namespace SHADE
void SetFreezeRotationY (bool freezeRotationY) noexcept; void SetFreezeRotationY (bool freezeRotationY) noexcept;
void SetFreezeRotationZ (bool freezeRotationZ) noexcept; void SetFreezeRotationZ (bool freezeRotationZ) noexcept;
void SetInterpolate (bool allowInterpolation) noexcept; void SetInterpolate (bool allowInterpolation) noexcept;
//void SetAutoMass (bool autoMass) noexcept;
//void SetMass (float newMass) noexcept;
void SetDrag (float newDrag) noexcept; void SetDrag (float newDrag) noexcept;
void SetAngularDrag (float newAngularDrag) noexcept; void SetAngularDrag (float newAngularDrag) noexcept;
@ -140,30 +146,43 @@ namespace SHADE
void ClearTorque () const noexcept; void ClearTorque () const noexcept;
private: private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class Flags : uint8_t
{
GRAVITY = 0x0
, SLEEPING = 0x1
, LINEAR_X = 0x2
, LINEAR_Y = 0x4
, LINEAR_Z = 0x8
, ANGULAR_X = 0x10
, ANGULAR_Y = 0x20
, ANGULAR_Z = 0x30
};
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
static constexpr size_t NUM_FLAGS = 8; static constexpr size_t NUM_FLAGS = 8;
static constexpr size_t NUM_DIRTY_FLAGS = 12;
Type type; Type type;
bool interpolate;
uint16_t flags; // 0 0 0 0 0 0 am ip aZ aY aX lZ lY lX slp g // Used for storing serialised data
uint16_t dirtyFlags; // 0 0 0 0 aD d m t aZ aY aX lZ lY lX slp g uint8_t flags; // aZ aY aX lZ lY lX sleepEnabled gravity
float mass;
float drag; float drag;
float angularDrag; float angularDrag;
SHVec3 linearVelocity; // For interpolation
SHVec3 angularVelocity;
SHPhysicsSystem* system;
SHVec3 position; SHVec3 position;
SHQuaternion orientation; SHQuaternion orientation;
reactphysics3d::RigidBody* rigidBody;
RTTR_ENABLE() RTTR_ENABLE()
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -1,431 +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"
#include "Scene/SHSceneManager.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept
: entityID { eid }
, collidersActive { true }
, 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)
{
// 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;
}
auto* rp3dCollider = rp3dBody->getCollider(rp3dBody->getNbColliders() - 1);
syncColliderProperties(collisionShape, rp3dCollider);
if (rp3dBody->getType() == rp3d::BodyType::DYNAMIC)
{
rp3dBody->updateMassPropertiesFromColliders();
if (auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID); rigidBodyComponent)
rigidBodyComponent->mass = rp3dBody->getMass();
}
return index;
}
void SHPhysicsObject::RemoveCollisionShape(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);
if (rp3dBody->getType() == rp3d::BodyType::DYNAMIC)
{
rp3dBody->updateMassPropertiesFromColliders();
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
if (rigidBodyComponent)
rigidBodyComponent->mass = rp3dBody->getMass();
}
}
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
{
// This state is synced in the pre-update routine
if (!rp3dBody->isActive())
return;
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);
//if (component.GetAutoMass())
//{
// rp3dBody->updateMassPropertiesFromColliders();
// component.mass = rp3dBody->getMass();
//}
//else
//{
// 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
{
// This state is synced in the pre-update routine
if (!rp3dBody->isActive())
return;
const int NUM_SHAPES = static_cast<int>(rp3dBody->getNbColliders());
for (int i = 0; i < NUM_SHAPES; ++i)
{
auto& collisionShape = component.collisionShapes[i];
if (!collisionShape.dirty)
continue;
switch (collisionShape.GetType())
{
case SHCollisionShape::Type::BOX: syncBoxShape(i, collisionShape); break;
case SHCollisionShape::Type::SPHERE: syncSphereShape(i, collisionShape); break;
default: break;
}
auto* rp3dCollider = rp3dBody->getCollider(i);
syncColliderProperties(collisionShape, rp3dCollider);
collisionShape.dirty = false;
}
// Set rigidbody mass if dynamic
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
if (rigidBodyComponent)
{
// This is generally expensive, will be optimised in the future with my own engine.
rp3dBody->updateMassPropertiesFromColliders();
rigidBodyComponent->mass = rp3dBody->getMass();
}
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsObject::syncColliderProperties(const SHCollisionShape& collisionShape, rp3d::Collider* rp3dCollider) const noexcept
{
rp3dCollider->setIsTrigger(collisionShape.IsTrigger());
auto& rp3dMaterial = rp3dCollider->getMaterial();
rp3dMaterial.setFrictionCoefficient(collisionShape.GetFriction());
rp3dMaterial.setBounciness(collisionShape.GetBounciness());
rp3dMaterial.setMassDensity(collisionShape.GetDensity());
const unsigned short MASK_BITS = collisionShape.GetCollisionTag();
rp3dCollider->setCollisionCategoryBits(MASK_BITS);
rp3dCollider->setCollideWithMaskBits(MASK_BITS);
}
void SHPhysicsObject::addBoxShape(const SHCollisionShape& boxShape) const noexcept
{
const rp3d::Transform OFFSETS
{
boxShape.GetPositionOffset()
, boxShape.GetRotationOffset()
};
const auto* BOX = reinterpret_cast<const SHBox*>(boxShape.GetShape());
rp3d::BoxShape* newBox = factory->createBoxShape(BOX->GetWorldExtents());
rp3dBody->addCollider(newBox, OFFSETS);
}
void SHPhysicsObject::syncBoxShape(int index, const SHCollisionShape& boxShape) const noexcept
{
const auto* BOX = reinterpret_cast<const SHBox*>(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(const SHCollisionShape& sphereShape) const noexcept
{
const rp3d::Transform OFFSETS
{
sphereShape.GetPositionOffset()
, sphereShape.GetRotationOffset()
};
const auto* SPHERE = reinterpret_cast<const SHSphere*>(sphereShape.GetShape());
rp3d::SphereShape* newSphere = factory->createSphereShape(SPHERE->GetWorldRadius());
rp3dBody->addCollider(newSphere, OFFSETS);
}
void SHPhysicsObject::syncSphereShape(int index, const SHCollisionShape& sphereShape) const noexcept
{
const auto* SPHERE = reinterpret_cast<const SHSphere*>(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

@ -1,111 +0,0 @@
/****************************************************************************************
* \file SHPhysicsObject.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface 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.
****************************************************************************************/
#pragma once
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "Math/Transform/SHTransformComponent.h"
#include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Interface/SHColliderComponent.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHPhysicsObject
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend class SHPhysicsSystem;
friend class SHPhysicsObjectManager;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsObject (EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept;
SHPhysicsObject (const SHPhysicsObject& rhs) noexcept = default;
SHPhysicsObject (SHPhysicsObject&& rhs) noexcept = default;
virtual ~SHPhysicsObject () noexcept;
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
SHPhysicsObject& operator=(const SHPhysicsObject& rhs) noexcept = default;
SHPhysicsObject& operator=(SHPhysicsObject&& rhs) noexcept = default;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] SHVec3 GetPosition () const noexcept;
[[nodiscard]] SHQuaternion GetOrientation () const noexcept;
[[nodiscard]] SHVec3 GetRotation () const noexcept;
[[nodiscard]] rp3d::CollisionBody* GetCollisionBody () const noexcept;
[[nodiscard]] rp3d::RigidBody* GetRigidBody () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Setter Functions */
/*---------------------------------------------------------------------------------*/
void SetStaticBody () const noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
int AddCollisionShape (int index);
void RemoveCollisionShape (int index);
void RemoveAllCollisionShapes () const noexcept;
void SyncRigidBody (SHRigidBodyComponent& component) const noexcept;
void SyncColliders (SHColliderComponent& component) const noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
EntityID entityID;
bool collidersActive; // Only used to sync with SHADE components
rp3d::PhysicsCommon* factory;
rp3d::PhysicsWorld* world;
rp3d::RigidBody* rp3dBody;
rp3d::Transform prevTransform; // Cached transform for interpolation
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void syncColliderProperties (const SHCollisionShape& collisionShape, rp3d::Collider* rp3dCollider) const noexcept;
// Box Shapes
void addBoxShape (const SHCollisionShape& boxShape) const noexcept;
void syncBoxShape (int index, const SHCollisionShape& boxShape) const noexcept;
// Sphere Shapes
void addSphereShape (const SHCollisionShape& sphereShape) const noexcept;
void syncSphereShape (int index, const SHCollisionShape& sphereShape) const noexcept;
};
} // namespace SHADE

View File

@ -1,309 +0,0 @@
/****************************************************************************************
* \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/Utilities/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Data Member Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsObjectManager::CommandFunctionPtr SHPhysicsObjectManager::componentFunc[3][2]
{
addRigidBody , addCollider , addCollisionShape
, removeRigidBody , removeCollider , 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);
wakeAllObjects();
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);
// If any removal was done, wake all objects
if (COMMAND.command == QueueCommand::Command::REMOVE)
wakeAllObjects();
}
}
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.
// Nothing is needed here.
}
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);
}
void SHPhysicsObjectManager::wakeAllObjects() noexcept
{
for (auto& physicsObject : physicsObjects | std::views::values)
physicsObject.GetRigidBody()->setIsSleeping(false);
}
} // namespace SHADE

View File

@ -1,181 +0,0 @@
/****************************************************************************************
* \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[3][2]; // 3 components, 2 commands
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;
void wakeAllObjects () 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

@ -15,7 +15,7 @@
// Project Headers // Project Headers
#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHEntityManager.h"
#include "Physics/PhysicsObject/SHPhysicsObject.h" #include "Physics/Interface/PhysicsObject/SHPhysicsObject.h"
#include "Physics/System/SHPhysicsSystem.h" #include "Physics/System/SHPhysicsSystem.h"
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
@ -25,9 +25,9 @@
uint32_t matchColliders(const SHADE::SHPhysicsObject&physicsObject, const rp3d::Entity colliderID) uint32_t matchColliders(const SHADE::SHPhysicsObject&physicsObject, const rp3d::Entity colliderID)
{ {
for (uint32_t i = 0; i < physicsObject.GetCollisionBody()->getNbColliders(); ++i) for (uint32_t i = 0; i < physicsObject.body->getNbColliders(); ++i)
{ {
const auto* collider = physicsObject.GetCollisionBody()->getCollider(i); const auto* collider = physicsObject.body->getCollider(i);
if (collider->getEntity() == colliderID) if (collider->getEntity() == colliderID)
return i; return i;
} }
@ -178,10 +178,10 @@ namespace SHADE
bool matched[2] = { false, false }; bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : system->GetPhysicsObjects()) for (auto& [entityID, physicsObject] : system->objectManager.GetPhysicsObjects())
{ {
// Match body 1 // Match body 1
if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.GetCollisionBody()->getEntity() == body1) if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.body->getEntity() == body1)
{ {
cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID; cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1); cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1);
@ -190,7 +190,7 @@ namespace SHADE
} }
// Match body 2 // Match body 2
if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.GetCollisionBody()->getEntity() == body2) if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.body->getEntity() == body2)
{ {
cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID; cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2); cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2);
@ -222,10 +222,10 @@ namespace SHADE
bool matched[2] = { false, false }; bool matched[2] = { false, false };
for (auto& [entityID, physicsObject] : system->GetPhysicsObjects()) for (auto& [entityID, physicsObject] : system->objectManager.GetPhysicsObjects())
{ {
// Match body 1 // Match body 1
if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.GetCollisionBody()->getEntity() == body1) if (matched[SHCollisionInfo::ENTITY_A] == false && physicsObject.body->getEntity() == body1)
{ {
cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID; cInfo.ids[SHCollisionInfo::ENTITY_A] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1); cInfo.ids[SHCollisionInfo::COLLIDER_A] = matchColliders(physicsObject, collider1);
@ -234,7 +234,7 @@ namespace SHADE
} }
// Match body 2 // Match body 2
if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.GetCollisionBody()->getEntity() == body2) if (matched[SHCollisionInfo::ENTITY_B] == false && physicsObject.body->getEntity() == body2)
{ {
cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID; cInfo.ids[SHCollisionInfo::ENTITY_B] = entityID;
cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2); cInfo.ids[SHCollisionInfo::COLLIDER_B] = matchColliders(physicsObject, collider2);

View File

@ -15,7 +15,7 @@
// Project Headers // Project Headers
#include "SH_API.h" #include "SH_API.h"
#include "SHCollisionInfo.h" #include "Physics/Collision/SHCollisionInfo.h"
namespace SHADE namespace SHADE
{ {

View File

@ -13,8 +13,7 @@
#include <reactphysics3d/reactphysics3d.h> #include <reactphysics3d/reactphysics3d.h>
// Project Headers // Project Headers
#include "Math/SHMath.h" #include "Math/Vector/SHVec3.h"
#include "SH_API.h"
namespace SHADE namespace SHADE
{ {

View File

@ -0,0 +1,132 @@
/****************************************************************************************
* \file SHPhysicsRaycaster.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for a Physics Raycaster.
*
* \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 "SHRaycaster.h"
#include "Physics/System/SHPhysicsSystem.h"
/*
* TODO(DIREN):
* Once the physics engine has been rebuilt, this whole implementation should change
* and just call PhysicsWorld.Raycast etc.
*
* SHRaycastResult can be converted to a bool when necessary.
*/
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHRaycaster::SHRaycaster() noexcept
: system { nullptr }
, world { nullptr }
{}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHRaycaster::BindToSystem(SHPhysicsSystem* physicsSystem) noexcept
{
system = physicsSystem;
}
void SHRaycaster::BindToWorld(rp3d::PhysicsWorld* physicsWorld) noexcept
{
world = physicsWorld;
}
const SHRaycaster::RaycastResults& SHRaycaster::Raycast(const RaycastInfo& info) noexcept
{
results.clear();
currentInfo = info;
SHASSERT(world, "Physics World missing link with Raycaster!")
// Clamp distance to 2km
const float DISTANCE = std::clamp(info.distance, 0.0f, SHRay::MAX_RAYCAST_DIST);
const rp3d::Ray RP3D_RAY = { info.ray.position, info.ray.position + info.ray.direction * DISTANCE };
world->raycast(RP3D_RAY, this, info.layers);
// Reset
currentInfo.reset();
return results;
}
rp3d::decimal SHRaycaster::notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo)
{
SHASSERT(system, "Physics System unlinked with Raycaster!")
SHPhysicsRaycastResult result;
// Compare body IDs to find the matching physics object
const auto HIT_BODY_EID = raycastInfo.body->getEntity();
for (const auto& [entityID, physicsObject] : system->objectManager.GetPhysicsObjects())
{
// Match rp3d bodies
if (physicsObject.body->getEntity() != HIT_BODY_EID)
continue;
// Skip ignored entity
if (currentInfo->colliderEntityID.has_value())
if (entityID == currentInfo->colliderEntityID)
return 1.0f;
result.entityHit = entityID;
// Find collider index
if (const int INDEX = findColliderIndex(physicsObject.body, raycastInfo.collider->getEntity()); INDEX > -1)
{
result.shapeIndex = INDEX;
break;
}
}
result.hit = true;
result.position = raycastInfo.worldPoint;
result.normal = raycastInfo.worldNormal;
result.distance = SHVec3::Distance(currentInfo->ray.position, result.position);
result.angle = SHVec3::Angle(currentInfo->ray.position, result.position);
results.emplace_back(result);
if (currentInfo->continuous)
return 1.0f;
return 0.0f;
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
int SHRaycaster::findColliderIndex(const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept
{
const int NUM_COLLISION_SHAPES = static_cast<int>(rp3dBody->getNbColliders());
for (int i = 0; i < NUM_COLLISION_SHAPES; ++i)
{
const auto COLLIDER_EID = rp3dBody->getCollider(i)->getEntity();
if (COLLIDER_EID == rp3dColliderEID)
return i;
}
return -1;
}
} // namespace SHADE

View File

@ -0,0 +1,133 @@
/****************************************************************************************
* \file SHPhysicsRaycaster.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for a Physics Raycaster.
*
* \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 <vector>
#include <reactphysics3d/reactphysics3d.h>
// Project Headers
#include "Math/SHRay.h"
#include "Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h"
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Physics/Collision/SHPhysicsRaycastResult.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHPhysicsSystem;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
class SH_API SHRaycaster : public reactphysics3d::RaycastCallback
{
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using RaycastResults = std::vector<SHPhysicsRaycastResult>;
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
struct RaycastInfo
{
private:
/*-------------------------------------------------------------------------------*/
/* Friends */
/*-------------------------------------------------------------------------------*/
friend class SHRaycaster;
public:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
bool continuous = false;
uint16_t layers = static_cast<uint16_t>(SHCollisionTag::Layer::ALL);
float distance = std::numeric_limits<float>::infinity();
SHRay ray;
/*-------------------------------------------------------------------------------*/
/* Setter Functions */
/*-------------------------------------------------------------------------------*/
/**
* @brief
* Sets the collider ID for the raycast. Setting this specifies that the ray
* should ignore this collider.
* @param eid
* The entity ID of the collider.
*/
void SetColliderID(EntityID eid) noexcept { colliderEntityID = eid; }
private:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
std::optional<EntityID> colliderEntityID;
};
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHRaycaster() noexcept;
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
void BindToSystem (SHPhysicsSystem* physicsSystem) noexcept;
void BindToWorld (rp3d::PhysicsWorld* physicsWorld) noexcept;
rp3d::decimal notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) override;
/**
* @brief
* Casts a ray into the physics world.
* @param info
* Contains the information for the raycast.
* @return
* A container of the objects hit by the ray. If nothing was hit, the container
* will be empty.
*/
[[nodiscard]] const RaycastResults& Raycast(const RaycastInfo& info) noexcept;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
SHPhysicsSystem* system;
rp3d::PhysicsWorld* world;
RaycastResults results; // Holds the temporary result after casting into the world
std::optional<RaycastInfo> currentInfo; // Hold the state of the current raycast.
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/
static int findColliderIndex (const rp3d::CollisionBody* rp3dBody, rp3d::Entity rp3dColliderEID) noexcept;
};
} // namespace SHADE

View File

@ -11,8 +11,7 @@
#pragma once #pragma once
// Project Headers // Project Headers
#include "Interface/SHCollisionShape.h" #include "Collision/Shapes/SHCollisionShape.h"
namespace SHADE namespace SHADE
{ {
@ -30,8 +29,15 @@ namespace SHADE
struct SHPhysicsColliderRemovedEvent struct SHPhysicsColliderRemovedEvent
{ {
EntityID entityID; EntityID entityID;
SHCollisionShape::Type colliderType;
int colliderIndex; int colliderIndex;
}; };
struct SHColliderOnDebugDrawEvent
{
EntityID entityID;
bool debugDrawState;
};
} // namespace SHADE } // namespace SHADE

View File

@ -0,0 +1,113 @@
/****************************************************************************************
* \file SHPhysicsDebugDrawRutine.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for the Physics Debut Draw Routine
*
* \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 "Physics/System/SHPhysicsDebugDrawSystem.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Physics/System/SHPhysicsSystem.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsDebugDrawSystem::PhysicsDebugDraw::PhysicsDebugDraw()
: SHSystemRoutine { "Physics Debug-Draw", true }
{}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsDebugDrawSystem::PhysicsDebugDraw::Execute(double) noexcept
{
auto* physicsDebugDrawSystem = reinterpret_cast<SHPhysicsDebugDrawSystem*>(GetSystem());
if (!physicsDebugDrawSystem->IsDebugDrawActive())
return;
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
const bool DRAW_COLLIDERS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::COLLIDERS);
const bool DRAW_CONTACTS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::CONTACTS);
const bool DRAW_RAYCASTS = physicsDebugDrawSystem->GetFlagState(DebugDrawFlags::RAYCASTS);
\
// If draw all colliders is active, get all colliders from the dense set and draw.
// Else we check if any colliders have been flagged for drawing.
if (DRAW_COLLIDERS)
{
const auto& COLLIDER_COMPONENT_DENSE = SHComponentManager::GetDense<SHColliderComponent>();
for (const auto& COLLIDER_COMPONENT : COLLIDER_COMPONENT_DENSE)
drawCollider(debugDrawSystem, COLLIDER_COMPONENT);
}
else if (!physicsDebugDrawSystem->collidersToDraw.empty())
{
for (const auto EID : physicsDebugDrawSystem->collidersToDraw)
drawCollider(debugDrawSystem, *SHComponentManager::GetComponent<SHColliderComponent>(EID));
}
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!physicsSystem)
return;
rp3d::DebugRenderer* rp3dRenderer = nullptr;
if (physicsSystem->worldState.world)
rp3dRenderer = &physicsSystem->worldState.world->getDebugRenderer();
// No world exists, nothing else to be drawn
if (!rp3dRenderer)
return;
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, DRAW_CONTACTS);
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, DRAW_CONTACTS);
if (DRAW_CONTACTS)
{
const SHColour& CONTACT_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::CONTACT)];
const int NUM_TRIS = static_cast<int>(rp3dRenderer->getNbTriangles());
if (NUM_TRIS == 0) // No contact points
return;
// Draw contacts
const auto& TRI_ARRAY = rp3dRenderer->getTrianglesArray();
for (int i = 0; i < NUM_TRIS; ++i)
debugDrawSystem->DrawTri(TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3, CONTACT_COLOUR, true);
// Draw normals
const int NUM_LINES = static_cast<int>(rp3dRenderer->getNbLines());
const auto& LINE_ARRAY = rp3dRenderer->getLinesArray();
for (int i = 0; i < NUM_LINES; ++i)
debugDrawSystem->DrawLine(LINE_ARRAY[i].point1, LINE_ARRAY[i].point2, CONTACT_COLOUR, true);
}
if (DRAW_RAYCASTS)
{
const SHColour& RAY_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::RAYCAST)];
const auto& RAYS = physicsSystem->raycastHits;
for (const auto& hit : RAYS)
debugDrawSystem->DrawLine(hit.start, hit.end, RAY_COLOUR, true);
// Clear rays for the physics system
physicsSystem->raycastHits.clear();
}
}
} // namespace SHADE

View File

@ -0,0 +1,120 @@
/****************************************************************************************
* \file SHPhysicsPostUpdateRoutine.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for the Physics Post-Update Routine
*
* \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 "Physics/System/SHPhysicsSystem.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneManager.h"
#include "Scripting/SHScriptEngine.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsSystem::PhysicsPostUpdate::PhysicsPostUpdate()
: SHSystemRoutine { "Physics Post-Update", false }
{}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
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!");
}
const float FACTOR = static_cast<float>(physicsSystem->interpolationFactor);
// Interpolate transforms for rendering.
// Only rigid bodies can move due to physics, so we run through the rigid body component dense set.
if (physicsSystem->worldUpdated)
{
for (auto& [entityID, physicsObject] : physicsSystem->objectManager.GetPhysicsObjects())
{
// Skip missing transforms
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
if (!transformComponent)
continue;
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
// Skip invalid bodies (Should not occur)
if (!rigidBodyComponent || !rigidBodyComponent->rigidBody)
continue;
// Skip inactive bodies
const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(entityID);
if (!IS_ACTIVE || rigidBodyComponent->type == SHRigidBodyComponent::Type::STATIC)
continue;
const rp3d::Transform& CURRENT_TF = physicsObject.body->getTransform();
if (rigidBodyComponent->IsInterpolating())
{
const rp3d::Transform PREV_TF
{
rigidBodyComponent->position
, rigidBodyComponent->orientation
};
const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast<rp3d::decimal>(FACTOR));
const SHVec3 RENDER_POSITION = INTERPOLATED_TF.getPosition();
const SHQuaternion RENDER_ORIENTATION = INTERPOLATED_TF.getOrientation();
transformComponent->SetWorldPosition(RENDER_POSITION);
transformComponent->SetWorldOrientation(RENDER_ORIENTATION);
}
else
{
transformComponent->SetWorldPosition(CURRENT_TF.getPosition());
transformComponent->SetWorldOrientation(CURRENT_TF.getOrientation());
}
rigidBodyComponent->position = CURRENT_TF.getPosition();
rigidBodyComponent->orientation = CURRENT_TF.getOrientation();
// Set colliders transform if exists
if (auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID); colliderComponent)
{
colliderComponent->transform.position = CURRENT_TF.getPosition();
colliderComponent->transform.orientation = CURRENT_TF.getOrientation();
}
/*
* TODO: Test if the scene graph transforms abides by setting world position. Collisions will ignore the scene graph hierarchy.
*/
}
// Since this function never runs when editor in not in play, execute the function anyway
physicsSystem->collisionListener.CleanContainers();
}
// Collision & Trigger messages
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteCollisionFunctions();
}
} // namespace SHADE

View File

@ -0,0 +1,95 @@
/****************************************************************************************
* \file SHPhysicsPreUpdateRoutine.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for the Physics Pre-Update Routine
*
* \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 "Physics/System/SHPhysicsSystem.h"
// Project Headers
#include "ECS_Base/Managers/SHComponentManager.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneManager.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsSystem::PhysicsPreUpdate::PhysicsPreUpdate()
: SHSystemRoutine { "Physics Pre-Update", true }
{}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::PhysicsPreUpdate::Execute(double) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
// Get all physics objects & sync transforms
auto& physicsObjects = physicsSystem->objectManager.GetPhysicsObjects();
for (auto& [entityID, physicsObject] : physicsObjects)
{
const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
// Assume transform is always active
const bool UPDATE_TRANSFORM = TRANSFORM_COMPONENT && TRANSFORM_COMPONENT->HasChanged();
if (!UPDATE_TRANSFORM)
continue;
// We assume that all engine components and physics object components have been successfully linked
if (!physicsObject.body)
continue;
// Set body transform
const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition();
const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation();
const rp3d::Transform NEW_TRANSFORM{ WORLD_POS, WORLD_ROT };
physicsObject.body->setTransform(NEW_TRANSFORM);
// Sync rigid body active states if one exists
if (auto* shadeBody = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID); shadeBody)
{
const bool SHADE_BODY_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(entityID);
const bool RP3D_BODY_ACTIVE = physicsObject.body->isActive();
if (SHADE_BODY_ACTIVE != RP3D_BODY_ACTIVE)
physicsObject.body->setIsActive(SHADE_BODY_ACTIVE);
shadeBody->position = WORLD_POS;
shadeBody->orientation = WORLD_ROT;
}
// Sync collider active states if one exists
if (auto* shadeCollider = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID); shadeCollider)
{
const bool SHADE_COLLIDER_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(entityID);
const bool RP3D_COLLIDERS_ACTIVE = shadeCollider->flags & SHColliderComponent::ACTIVE_FLAG;
// Modify the static body's active state
// The collision listener & raycaster will handle culling inactive colliders.
if (SHADE_COLLIDER_ACTIVE != RP3D_COLLIDERS_ACTIVE)
physicsObject.body->setIsActive(SHADE_COLLIDER_ACTIVE);
shadeCollider->transform.position = WORLD_POS;
shadeCollider->transform.orientation = WORLD_ROT;
shadeCollider->transform.scale = TRANSFORM_COMPONENT->GetWorldScale();
shadeCollider->Update();
}
}
}
} // namespace SHADE

View File

@ -0,0 +1,66 @@
/****************************************************************************************
* \file SHPhysicsUpdateRoutine.cpp
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Implementation for the Physics Update Routine
*
* \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 "Physics/System/SHPhysicsSystem.h"
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Scripting/SHScriptEngine.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHPhysicsSystem::PhysicsUpdate::PhysicsUpdate()
: SHFixedSystemRoutine { DEFAULT_FIXED_STEP, "Physics Update", false }
{}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::PhysicsUpdate::Execute(double dt) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptEngine = SHSystemManager::GetSystem<SHScriptEngine>();
if (!scriptEngine)
{
SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing ScriptEngine!")
}
const double FIXED_DT = physicsSystem->fixedDT;
accumulatedTime += dt;
int count = 0;
while (accumulatedTime > FIXED_DT)
{
if (scriptEngine)
scriptEngine->ExecuteFixedUpdates();
if (physicsSystem->worldState.world)
physicsSystem->worldState.world->update(static_cast<rp3d::decimal>(FIXED_DT));
accumulatedTime -= FIXED_DT;
++count;
}
stats.numSteps = count;
physicsSystem->worldUpdated = count > 0;
physicsSystem->interpolationFactor = physicsSystem->worldUpdated ? accumulatedTime / FIXED_DT : 0.0;
}
} // namespace SHADE

View File

@ -13,79 +13,59 @@
// Primary Header // Primary Header
#include "SHPhysicsDebugDrawSystem.h" #include "SHPhysicsDebugDrawSystem.h"
// Project Headers // Project Header
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h" #include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneManager.h" #include "Physics/SHPhysicsEvents.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ const SHColour SHPhysicsDebugDrawSystem::DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::COUNT)]
/* Static Data Member Definitions */
/*-----------------------------------------------------------------------------------*/
const SHPhysicsDebugDrawSystem::DebugDrawFunction SHPhysicsDebugDrawSystem::drawFunctions[NUM_FLAGS] =
{ {
drawColliders SHColour::GREEN // Colliders
, drawColliderAABBs , SHColour::PURPLE // Triggers
, drawBroadPhaseAABBs , SHColour::RED // Contacts
, drawContactPoints , SHColour::ORANGE // Raycasts
, drawContactNormals
, drawRaycasts
}; };
SHVec3 SHPhysicsDebugDrawSystem::boxVertices[NUM_BOX_VERTICES];
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Constructors & Destructor Definitions */ /* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHPhysicsDebugDrawSystem::SHPhysicsDebugDrawSystem() noexcept SHPhysicsDebugDrawSystem::SHPhysicsDebugDrawSystem() noexcept
: debugDrawFlags { 0 } : flags { 0 }
, physicsSystem { nullptr }
{ {
debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::COLLIDER)] = SHColour::GREEN; collidersToDraw.clear();
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;
debugColours[SHUtilities::ConvertEnum(DebugDrawFlags::RAYCASTS)] = SHColour::ORANGE;
} }
SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::PhysicsDebugDrawRoutine()
: SHSystemRoutine { "Physics Debug Draw", true }
{}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */ /* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
bool SHPhysicsDebugDrawSystem::GetDebugDrawFlag(DebugDrawFlags flag) const noexcept bool SHPhysicsDebugDrawSystem::IsDebugDrawActive() const noexcept
{ {
const auto INT_FLAG = SHUtilities::ConvertEnum(flag); return flags & ACTIVE_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); bool SHPhysicsDebugDrawSystem::GetFlagState(DebugDrawFlags flag) const noexcept
{
const uint8_t ENUM_VALUE = SHUtilities::ConvertEnum(flag);
return flags & ENUM_VALUE;
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */ /* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHPhysicsDebugDrawSystem::SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept void SHPhysicsDebugDrawSystem::SetFlagState(DebugDrawFlags flag, bool state) noexcept
{ {
const auto INT_FLAG = SHUtilities::ConvertEnum(flag); const uint8_t ENUM_VALUE = SHUtilities::ConvertEnum(flag);
if (INT_FLAG < 0 || INT_FLAG >= NUM_FLAGS) state ? flags |= ENUM_VALUE : flags &= ~ENUM_VALUE;
{
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)); // If no other debug drawing state is active, turn active off. Otherwise, we maintain
// the active state.
flags == ACTIVE_FLAG ? flags = 0 : flags |= ACTIVE_FLAG;
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -96,240 +76,76 @@ namespace SHADE
{ {
SystemFamily::GetID<SHPhysicsDebugDrawSystem>(); SystemFamily::GetID<SHPhysicsDebugDrawSystem>();
SHASSERT(physicsSystem == nullptr, "Non-existent physics system attached to the physics debug draw system!") // Register collider draw event
physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>(); const std::shared_ptr EVENT_RECEIVER = std::make_shared<SHEventReceiverSpec<SHPhysicsDebugDrawSystem>>(this, &SHPhysicsDebugDrawSystem::onColliderDraw);
const ReceiverPtr EVENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(EVENT_RECEIVER);
// Generate shapes //SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_DRAW_EVENT, EVENT_RECEIVER_PTR);
generateBox();
} }
void SHPhysicsDebugDrawSystem::Exit() void SHPhysicsDebugDrawSystem::Exit()
{ {
physicsSystem = nullptr;
}
void SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine::Execute(double) noexcept
{
auto* system = reinterpret_cast<SHPhysicsDebugDrawSystem*>(GetSystem());
auto* debugDrawSystem = SHSystemManager::GetSystem<SHDebugDrawSystem>();
if (debugDrawSystem == nullptr)
{
SHLOG_ERROR("Unable to get a debug draw system for Physics Debug Drawing!")
return;
}
rp3d::DebugRenderer* rp3dRenderer = nullptr;
if (system->physicsSystem->worldState.world)
rp3dRenderer = &system->physicsSystem->worldState.world->getDebugRenderer();
for (int i = 0; i < SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS); ++i)
{
const bool DRAW = (system->debugDrawFlags & (1U << i)) > 0;
if (DRAW)
{
drawFunctions[i](debugDrawSystem, rp3dRenderer);
}
else
{
if (rp3dRenderer && (i == 3 || i == 4))
{
rp3dRenderer->setIsDebugItemDisplayed(reactphysics3d::DebugRenderer::DebugItem::CONTACT_POINT, false);
rp3dRenderer->setIsDebugItemDisplayed(reactphysics3d::DebugRenderer::DebugItem::CONTACT_NORMAL, false);
}
}
} }
// Automatically clear the container of raycasts despite debug drawing state void SHPhysicsDebugDrawSystem::AddRaycast(const SHRay& ray, const SHPhysicsRaycastResult& result) noexcept
// TODO(Diren): Move this somewhere else {
system->physicsSystem->raycaster.ClearFrame();
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */ /* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHPhysicsDebugDrawSystem::drawColliders(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept SHEventHandle SHPhysicsDebugDrawSystem::onColliderDraw(SHEventPtr onColliderDrawEvent)
{ {
const auto& COLLIDER_SET = SHComponentManager::GetDense<SHColliderComponent>(); const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHColliderOnDebugDrawEvent>*>(onColliderDrawEvent.get())->data;
for (const auto& COLLIDER : COLLIDER_SET)
{
// Skip inactive colliders
if (!SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(COLLIDER.GetEID()))
continue;
for (auto& collisionShape : COLLIDER.GetCollisionShapes()) // Add to the container to draw all colliders
if (EVENT_DATA->debugDrawState)
{ {
switch (collisionShape.GetType()) if (collidersToDraw.empty())
flags |= ACTIVE_FLAG;
collidersToDraw.emplace(EVENT_DATA->entityID);
}
else
{ {
case SHCollisionShape::Type::BOX: debugDrawBox(debugRenderer, COLLIDER, collisionShape); break; collidersToDraw.erase(EVENT_DATA->entityID);
case SHCollisionShape::Type::SPHERE: debugDrawSphere(debugRenderer, COLLIDER, collisionShape); break;
// if no colliders queued for drawing and no other debug drawing is enabled, disable debug drawing
if (collidersToDraw.empty() && flags == ACTIVE_FLAG)
flags = 0;
}
return onColliderDrawEvent.get()->handle;
}
void SHPhysicsDebugDrawSystem::drawCollider(SHDebugDrawSystem* debugDrawSystem, const SHColliderComponent& collider) noexcept
{
for (const auto& SHAPE : collider.GetCollisionShapes())
{
const SHColour& DRAW_COLOUR = DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(SHAPE->IsTrigger() ? Colours::TRIGGER : Colours::COLLIDER)];
switch (SHAPE->GetType())
{
case SHCollisionShape::Type::SPHERE:
{
debugDrawSystem->DrawWireSphere(SHAPE->GetTRS(), DRAW_COLOUR, true);
break;
}
case SHCollisionShape::Type::BOX:
{
debugDrawSystem->DrawWireCube(SHAPE->GetTRS(), DRAW_COLOUR, true);
break;
}
//case SHCollisionShape::Type::CAPSULE:
//{
// break;
//}
default: break; default: break;
} }
} }
} }
}
void SHPhysicsDebugDrawSystem::drawColliderAABBs(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept
{
}
void SHPhysicsDebugDrawSystem::drawBroadPhaseAABBs(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept
{
}
void SHPhysicsDebugDrawSystem::drawContactPoints(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept
{
#ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
{
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, true);
const int NUM_TRIS = static_cast<int>(rp3dRenderer->getNbTriangles());
if (NUM_TRIS == 0)
return;
const auto& TRI_ARRAY = rp3dRenderer->getTrianglesArray();
for (int i = 0; i < NUM_TRIS; ++i)
debugRenderer->DrawTri(TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3, SHColour::RED);
}
#else
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, true);
const int NUM_TRIS = static_cast<int>(rp3dRenderer->getNbTriangles());
if (NUM_TRIS == 0)
return;
const auto& TRI_ARRAY = rp3dRenderer->getTrianglesArray();
for (int i = 0; i < NUM_TRIS; ++i)
debugRenderer->DrawTri(TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3, SHColour::RED);
#endif
}
void SHPhysicsDebugDrawSystem::drawContactNormals(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept
{
#ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
{
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, true);
const int NUM_LINES = static_cast<int>(rp3dRenderer->getNbLines());
if (NUM_LINES == 0)
return;
const auto& LINE_ARRAY = rp3dRenderer->getLinesArray();
for (int i = 0; i < NUM_LINES; ++i)
debugRenderer->DrawLine(LINE_ARRAY[i].point1, LINE_ARRAY[i].point2, SHColour::RED);
}
#else
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, true);
const int NUM_LINES = static_cast<int>(rp3dRenderer->getNbLines());
if (NUM_LINES == 0)
return;
const auto& LINE_ARRAY = rp3dRenderer->getLinesArray();
for (int i = 0; i < NUM_LINES; ++i)
debugRenderer->DrawLine(LINE_ARRAY[i].point1, LINE_ARRAY[i].point2, SHColour::RED);
#endif
}
void SHPhysicsDebugDrawSystem::drawRaycasts(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept
{
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (!physicsSystem)
{
SHLOG_ERROR("Unable to retrieve physics system for debug drawing raycasts!")
return;
}
const SHColour& RAY_COLOUR = SHColour::ORANGE;
// Draw all raycast pairs
for (const auto& [ray, raycastResult] : physicsSystem->raycaster.GetRaycasts())
{
// If infinity, it is an infinite raycast. If not, render the distance in raycastResult.
// Ignore the hit variable as it will always correspond to the length of the raycast, hit or miss.
const float RENDER_DIST = raycastResult.distance == std::numeric_limits<float>::infinity() ? SHRay::MAX_RAYCAST_DIST : raycastResult.distance;
const SHVec3 END_POS = ray.position + (ray.direction * RENDER_DIST);
debugRenderer->DrawLine(ray.position, END_POS, RAY_COLOUR);
}
}
void SHPhysicsDebugDrawSystem::generateBox() noexcept
{
boxVertices[0] = { 0.5f, 0.5f, -0.5f }; // TOP_RIGHT_BACK
boxVertices[1] = { -0.5f, 0.5f, -0.5f }; // TOP_LEFT_BACK
boxVertices[2] = { 0.5f, -0.5f, -0.5f }; // BTM_RIGHT_BACK
boxVertices[3] = { -0.5f, -0.5f, -0.5f }; // BTM_LEFT_BACK
boxVertices[4] = { 0.5f, 0.5f, 0.5f }; // TOP_RIGHT_FRONT
boxVertices[5] = { -0.5f, 0.5f, 0.5f }; // TOP_LEFT_FRONT
boxVertices[6] = { 0.5f, -0.5f, 0.5f }; // BTM_RIGHT_FRONT
boxVertices[7] = { -0.5f, -0.5f, 0.5f }; // BTM_LEFT_FRONT
}
void SHPhysicsDebugDrawSystem::debugDrawBox(SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept
{
auto* BOX = reinterpret_cast<const SHBox*>(collisionShape.GetShape());
// Calculate final position & orientation
const SHVec3 COLLIDER_POS = colliderComponent.GetPosition();
const SHVec3 BOX_POS = collisionShape.GetPositionOffset();
const SHQuaternion COLLIDER_ROT = colliderComponent.GetOrientation();
const SHQuaternion BOX_ROT = SHQuaternion::FromEuler(collisionShape.GetRotationOffset());
const SHMatrix COLLIDER_TR = SHMatrix::Rotate(COLLIDER_ROT) * SHMatrix::Translate(COLLIDER_POS);
const SHMatrix BOX_TRS = SHMatrix::Scale(BOX->GetWorldExtents() * 2.0f) * SHMatrix::Rotate(BOX_ROT) * SHMatrix::Translate(BOX_POS);
const SHMatrix FINAL_TRS = BOX_TRS * COLLIDER_TR;
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], FINAL_TRS);
transformedVertices[IDX2] = SHVec3::Transform(boxVertices[IDX2], FINAL_TRS);
// Draw 4 line to connect the quads
debugRenderer->DrawLine(transformedVertices[IDX1], transformedVertices[IDX2], COLLIDER_COLOUR);
}
// A, B, C, D
std::array backQuad { transformedVertices[0], transformedVertices[1], transformedVertices[3], transformedVertices[2] };
debugRenderer->DrawLineLoop(backQuad.begin(), backQuad.end(), COLLIDER_COLOUR);
// E, F, G, H
std::array frontQuad { transformedVertices[4], transformedVertices[5], transformedVertices[7], transformedVertices[6] };
debugRenderer->DrawLineLoop(frontQuad.begin(), frontQuad.end(), COLLIDER_COLOUR);
}
void SHPhysicsDebugDrawSystem::debugDrawSphere(SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept
{
auto* SPHERE = reinterpret_cast<const SHSphere*>(collisionShape.GetShape());
const SHColour COLLIDER_COLOUR = collisionShape.IsTrigger() ? SHColour::PURPLE : SHColour::GREEN;
// Calculate final position & orientation
const SHQuaternion FINAL_ROT = colliderComponent.GetOrientation() * SHQuaternion::FromEuler(collisionShape.GetRotationOffset());
const SHMatrix TR = SHMatrix::Rotate(FINAL_ROT) * SHMatrix::Translate(colliderComponent.GetPosition());
/* #KWFix */
//debugRenderer->DrawSphere(COLLIDER_COLOUR, SHVec3::Transform(collisionShape.GetPositionOffset(), TR), SPHERE->GetWorldRadius());
}
} // namespace SHADE } // namespace SHADE

View File

@ -10,14 +10,16 @@
#pragma once #pragma once
#include <reactphysics3d/reactphysics3d.h> #include <unordered_set>
// Project Headers // Project Headers
#include "ECS_Base/Entity/SHEntity.h"
#include "ECS_Base/System/SHSystem.h"
#include "ECS_Base/System/SHSystemRoutine.h" #include "ECS_Base/System/SHSystemRoutine.h"
#include "Events/SHEvent.h"
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" #include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
#include "Math/SHColour.h" #include "Physics/Interface/SHColliderComponent.h"
#include "SHPhysicsSystem.h" #include "Physics/Collision/SHPhysicsRaycastResult.h"
#include "Tools/Utilities/SHUtilities.h"
namespace SHADE namespace SHADE
{ {
@ -28,20 +30,12 @@ namespace SHADE
class SH_API SHPhysicsDebugDrawSystem final : public SHSystem class SH_API SHPhysicsDebugDrawSystem final : public SHSystem
{ {
public: public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
enum class DebugDrawFlags enum class DebugDrawFlags : uint8_t
{ {
COLLIDER COLLIDERS = 0x02
, COLLIDER_AABB , CONTACTS = 0x04
, BROAD_PHASE_AABB , RAYCASTS = 0x08
, CONTACT_POINTS
, CONTACT_NORMALS
, RAYCASTS
, NUM_FLAGS
}; };
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -49,42 +43,41 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHPhysicsDebugDrawSystem () noexcept; SHPhysicsDebugDrawSystem () noexcept;
~SHPhysicsDebugDrawSystem() noexcept = default;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
bool GetDebugDrawFlag(DebugDrawFlags flag) const noexcept; [[nodiscard]] bool IsDebugDrawActive () const noexcept;
[[nodiscard]] bool GetFlagState (DebugDrawFlags flag) const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SetDebugDrawFlag(DebugDrawFlags flag, bool value) noexcept; void SetFlagState (DebugDrawFlags flag, bool state) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Member Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void Init () override; void Init () override;
void Exit () override; void Exit () override;
void AddRaycast (const SHRay& ray, const SHPhysicsRaycastResult& result) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* System Routines */ /* System Routines */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
class SH_API PhysicsDebugDrawRoutine final : public SHSystemRoutine /**
* @brief
* If the editor is enabled, this routine invokes debug drawing for colliders and collision information.
*/
class SH_API PhysicsDebugDraw final : public SHSystemRoutine
{ {
public: public:
/*-------------------------------------------------------------------------------*/ PhysicsDebugDraw();
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsDebugDrawRoutine();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override; void Execute(double dt) noexcept override;
}; };
@ -93,46 +86,58 @@ namespace SHADE
/* Type Definitions */ /* Type Definitions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
using DebugDrawFunction = void(*)(SHDebugDrawSystem*, rp3d::DebugRenderer*) noexcept; union DebugDrawInfo
{
struct Contact
{
SHVec3 worldPos;
SHVec3 normal;
} contact;
struct Raycast
{
SHVec3 start;
SHVec3 end;
} raycast;
};
using Colliders = std::unordered_set<EntityID>;
using Raycasts = std::vector<DebugDrawInfo>;
using Contacts = std::vector<DebugDrawInfo>;
enum class Colours
{
COLLIDER
, TRIGGER
, CONTACT
, RAYCAST
, COUNT
};
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
static constexpr int NUM_FLAGS = SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS); static constexpr uint8_t ACTIVE_FLAG = 0x01;
static const DebugDrawFunction drawFunctions[NUM_FLAGS];
// SHAPES INFO static const SHColour DEBUG_DRAW_COLOURS[static_cast<int>(Colours::COUNT)];
static constexpr size_t NUM_BOX_VERTICES = 8; // 0 0 0 drawBroadphase drawRaycasts drawContacts drawAllColliders debugDrawActive
static SHVec3 boxVertices[NUM_BOX_VERTICES]; uint8_t flags;
Colliders collidersToDraw;
uint8_t debugDrawFlags;
SHPhysicsSystem* physicsSystem;
SHColour debugColours[NUM_FLAGS];
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Member Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
// Generic Draw Functions SHEventHandle onColliderDraw(SHEventPtr onColliderDrawEvent);
static void drawColliders (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; static void drawCollider (SHDebugDrawSystem* debugDrawSystem, const SHColliderComponent& collider) noexcept;
static void drawColliderAABBs (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept; static void drawRaycast (SHDebugDrawSystem* debugDrawSystem, const DebugDrawInfo::Raycast& raycastInfo) noexcept;
static void drawBroadPhaseAABBs (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept;
static void drawContactPoints (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept;
static void drawContactNormals (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept;
static void drawRaycasts (SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept;
// Shape Generation Functions
static void generateBox () noexcept;
// Shape Draw Functions
static void debugDrawBox (SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept;
static void debugDrawSphere (SHDebugDrawSystem* debugRenderer, const SHColliderComponent& colliderComponent, const SHCollisionShape& collisionShape) noexcept;
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -19,8 +19,9 @@
#include "ECS_Base/Managers/SHEntityManager.h" #include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h" #include "Editor/SHEditor.h"
#include "Physics/Collision/SHCollisionTagMatrix.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Physics/SHPhysicsEvents.h" #include "Physics/Interface/SHRigidBodyComponent.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
@ -30,11 +31,23 @@ namespace SHADE
/* Constructors & Destructor Definitions */ /* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHPhysicsSystem::SHPhysicsSystem() SHPhysicsSystem::SHPhysicsSystem() noexcept
: worldUpdated { false } : worldUpdated { false }
, interpolationFactor { 0.0 } , interpolationFactor { 0.0 }
, fixedDT { DEFAULT_FIXED_STEP } , fixedDT { DEFAULT_FIXED_STEP }
{} {
// Add more events here to register them
eventFunctions[0] = { &SHPhysicsSystem::onComponentAdded , SH_COMPONENT_ADDED_EVENT };
eventFunctions[1] = { &SHPhysicsSystem::onComponentRemoved, SH_COMPONENT_REMOVED_EVENT };
eventFunctions[2] = { &SHPhysicsSystem::onSceneInit , SH_SCENE_INIT_POST };
eventFunctions[3] = { &SHPhysicsSystem::onSceneExit , SH_SCENE_EXIT_POST };
}
SHPhysicsSystem::~SHPhysicsSystem()
{
worldState.DestroyWorld(factory);
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */ /* Getter Function Definitions */
@ -45,9 +58,9 @@ namespace SHADE
return 1.0 / fixedDT; return 1.0 / fixedDT;
} }
const SHPhysicsWorldState::WorldSettings& SHPhysicsSystem::GetWorldSettings() const noexcept double SHPhysicsSystem::GetFixedDT() const noexcept
{ {
return worldState.settings; return fixedDT;
} }
const std::vector<SHCollisionInfo>& SHPhysicsSystem::GetAllCollisionInfo() const noexcept const std::vector<SHCollisionInfo>& SHPhysicsSystem::GetAllCollisionInfo() const noexcept
@ -60,30 +73,43 @@ namespace SHADE
return collisionListener.GetTriggerInfoContainer(); return collisionListener.GetTriggerInfoContainer();
} }
const SHPhysicsObject* SHPhysicsSystem::GetPhysicsObject(EntityID eid) noexcept
{
return objectManager.GetPhysicsObject(eid);
}
const SHPhysicsObjectManager::PhysicsObjectEntityMap& SHPhysicsSystem::GetPhysicsObjects() const noexcept
{
return objectManager.physicsObjects;
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Setter Function Definitions */ /* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHPhysicsSystem::SetFixedUpdateRate(double fixedUpdateRate) noexcept void SHPhysicsSystem::SetFixedUpdateRate(double fixedUpdateRate) noexcept
{ {
fixedDT = 1.0 / fixedUpdateRate; // Handle invalid input
if (fixedUpdateRate <= 0.0)
{
SHLOGV_WARNING("Invalid value for setting fixed update rate! Fixed update rate unchanged.")
return;
} }
void SHPhysicsSystem::SetWorldSettings(const SHPhysicsWorldState::WorldSettings& settings) noexcept fixedDT = 1.0 / fixedUpdateRate;
// Handle potential incorrect / unintended input
if (fixedDT > 1.0)
{ {
worldState.settings = settings; SHLOGV_WARNING("Fixed Update Rate Time is set below 1. This may result in undesirable behaviour.")
worldState.UpdateSettings(); }
}
void SHPhysicsSystem::SetFixedDT(double fixedDt) noexcept
{
if (fixedDt <= 0.0)
{
SHLOGV_WARNING("Invalid value for setting fixed delta time! Fixed delta time unchanged.")
return;
}
fixedDT = fixedDt;
// Handle potential incorrect / unintended input
if (fixedDT > 1.0)
{
SHLOGV_WARNING("Fixed Delta Time is set above 1. This may result in undesirable behaviour.")
}
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -92,40 +118,23 @@ namespace SHADE
void SHPhysicsSystem::Init() void SHPhysicsSystem::Init()
{ {
// TODO(Diren): Consider using a non-static collision tag matrix.
// Initialise collision tags // Initialise collision tags
std::filesystem::path defaultCollisionTagNameFilePath { ASSET_ROOT }; std::filesystem::path defaultCollisionTagNameFilePath { ASSET_ROOT };
defaultCollisionTagNameFilePath.append("CollisionTags.SHConfig"); defaultCollisionTagNameFilePath.append("CollisionTags.SHConfig");
SHCollisionTagMatrix::Init(defaultCollisionTagNameFilePath); SHCollisionTagMatrix::Init(defaultCollisionTagNameFilePath);
// Link Physics Object Manager with System & Raycaster // Register Events
objectManager.SetFactory(factory); for (int i = 0; i < NUM_EVENT_FUNCTIONS; ++i)
raycaster.SetObjectManager(&objectManager); {
const std::shared_ptr EVENT_RECEIVER = std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, eventFunctions[i].first);
const ReceiverPtr EVENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(EVENT_RECEIVER);
// Link Collision Listener with System SHEventManager::SubscribeTo(eventFunctions[i].second, EVENT_RECEIVER_PTR);
collisionListener.BindToSystem(this); }
// 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
objectManager.SetFactory(&factory);
raycaster.BindToSystem(this);
} }
void SHPhysicsSystem::Exit() void SHPhysicsSystem::Exit()
@ -138,344 +147,165 @@ namespace SHADE
SHCollisionTagMatrix::Exit(defaultCollisionTagNameFilePath); SHCollisionTagMatrix::Exit(defaultCollisionTagNameFilePath);
} }
void SHPhysicsSystem::BuildScene(SHSceneGraph& sceneGraph) const std::vector<SHPhysicsRaycastResult>& SHPhysicsSystem::Raycast(const SHRaycaster::RaycastInfo& info) noexcept
{ {
static const auto BUILD_NEW_SCENE_PHYSICS_OBJECT = [&](SHSceneNode* node) auto& results = raycaster.Raycast(info);
{
const EntityID EID = node->GetEntityID();
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(EID))
objectManager.AddRigidBody(EID);
if (SHComponentManager::HasComponent<SHColliderComponent>(EID))
{
objectManager.AddCollider(EID);
auto* COLLIDER = SHComponentManager::GetComponent<SHColliderComponent>(EID);
for (size_t i = 0; i < COLLIDER->GetCollisionShapes().size(); ++i)
objectManager.AddCollisionShape(EID, i);
}
};
////////////////////////////////
// Destroy an existing world
if (worldState.world != nullptr)
{
objectManager.RemoveAllObjects();
objectManager.SetWorld(nullptr);
collisionListener.ClearContainers();
raycaster.ClearFrame();
worldState.DestroyWorld(factory);
}
worldState.CreateWorld(factory);
#ifdef _PUBLISH
worldState.world->setIsDebugRenderingEnabled(false);
#else
worldState.world->setIsDebugRenderingEnabled(true);
#endif
// Link Collision Listener & Raycaster
collisionListener.BindToWorld(worldState.world);
raycaster.BindToWorld(worldState.world);
// Link with object manager & create all physics objects
objectManager.SetWorld(worldState.world);
// When building a scene, clear the object manager command queue and build scene objects again.
// This is done to avoid duplicate adds.
while (!objectManager.commandQueue.empty())
objectManager.commandQueue.pop();
sceneGraph.Traverse(BUILD_NEW_SCENE_PHYSICS_OBJECT);
objectManager.UpdateCommands();
}
void SHPhysicsSystem::ForceBuild(SHSceneGraph& sceneGraph)
{
// HACK: Band-aid fix. To be removed.
objectManager.UpdateCommands();
}
void SHPhysicsSystem::ForceUpdate()
{
if (!worldState.world)
{
SHLOGV_ERROR("Unable to force update without a Physics world!")
return;
}
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!");
}
// Force the physics world to update once
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteFixedUpdates();
worldState.world->update(static_cast<rp3d::decimal>(fixedDT));
// Sync transforms. No interpolation applied here
for (auto& [entityID, physicsObject] : objectManager.physicsObjects)
{
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
const auto& CURRENT_TF = physicsObject.GetRigidBody()->getTransform();
const auto& RENDER_POS = CURRENT_TF.getPosition();
const auto& RENDER_ROT = CURRENT_TF.getOrientation();
// Cache transform
physicsObject.prevTransform = CURRENT_TF;
// Sync with physics components
if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(entityID))
{
rigidBodyComponent->position = RENDER_POS;
rigidBodyComponent->orientation = RENDER_ROT;
}
if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(entityID))
{
colliderComponent->position = RENDER_POS;
colliderComponent->orientation = RENDER_ROT;
}
// Set transform for rendering
if (transformComponent)
{
transformComponent->SetWorldPosition(RENDER_POS);
transformComponent->SetWorldOrientation(RENDER_ROT);
}
}
}
SHPhysicsRaycastResult SHPhysicsSystem::Raycast(const SHRay& ray, float distance, const SHCollisionTag& collisionTag) noexcept
{
return raycaster.Raycast(ray, distance, collisionTag);
}
SHPhysicsRaycastResult SHPhysicsSystem::Linecast(const SHVec3& start, const SHVec3& end, const SHCollisionTag& collisionTag) noexcept
{
return raycaster.Linecast(start, end, collisionTag);
}
SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept
{
return raycaster.ColliderRaycast(eid, ray, distance);
}
SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept
{
return raycaster.ColliderRaycast(eid, shapeIndex, ray, distance);
}
SHPhysicsRaycastResult SHPhysicsSystem::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept
{
return raycaster.ColliderLinecast(eid, start, end);
}
SHPhysicsRaycastResult SHPhysicsSystem::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept
{
return raycaster.ColliderLinecast(eid, shapeIndex, start, end);
}
void SHPhysicsSystem::AddCollisionShape(EntityID eid, int shapeIndex)
{
static const auto ADD_SHAPE = [&](EntityID entityID, int index)
{
objectManager.AddCollisionShape(entityID, index);
auto* colliderComponent = SHComponentManager::GetComponent<SHColliderComponent>(entityID);
auto& collisionShape = colliderComponent->GetCollisionShape(index);
const SHPhysicsColliderAddedEvent COLLIDER_ADDED_EVENT_DATA
{
.entityID = entityID
, .colliderType = collisionShape.GetType()
, .colliderIndex = index
};
SHEventManager::BroadcastEvent<SHPhysicsColliderAddedEvent>(COLLIDER_ADDED_EVENT_DATA, SH_PHYSICS_COLLIDER_ADDED_EVENT);
};
// Load start and end points into the container for debug drawing
#ifdef SHEDITOR #ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>(); SHVec3 endPos = info.ray.position + info.ray.direction * SHRay::MAX_RAYCAST_DIST;
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
ADD_SHAPE(eid, shapeIndex);
#else if (!results.empty())
endPos = results.back().position;
ADD_SHAPE(eid, shapeIndex); raycastHits.emplace_back(info.ray.position, endPos);
#endif #endif
return results;
} }
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
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */ /* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHEventHandle SHPhysicsSystem::addPhysicsComponent(SHEventPtr addComponentEvent) noexcept SHEventHandle SHPhysicsSystem::onSceneInit(SHEventPtr onSceneInitEvent)
{ {
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(addComponentEvent.get()); /*
* If a world already exists, destroy it
* Recreate the world.
*
* If there is an editor and editor mode is already playing, link all entities with the world immediately.
*/
static const auto RIGID_BODY_ID = ComponentFamily::GetID<SHRigidBodyComponent>(); // Destroy an existing world if there is one.
static const auto COLLIDER_ID = ComponentFamily::GetID<SHColliderComponent>(); //! This should almost never happen.
if (worldState.world)
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; // Remove all references of physics objects from the world
for (const auto& PHYSICS_OBJECT : objectManager.GetPhysicsObjects() | std::views::values)
// We only add tell the physics object manager to add a component if the scene is played {
if (PHYSICS_OBJECT.body)
#ifdef SHEDITOR {
// Remove all colliders and destroy world
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>(); int32_t numShapes = static_cast<int32_t>(PHYSICS_OBJECT.body->getNbColliders());
while (--numShapes >= 0)
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) {
ADDED_ID == RIGID_BODY_ID ? objectManager.AddRigidBody(EID) : objectManager.AddCollider(EID); auto* rp3dCollider = PHYSICS_OBJECT.body->getCollider(numShapes);
PHYSICS_OBJECT.body->removeCollider(rp3dCollider);
#else
ADDED_ID == RIGID_BODY_ID ? objectManager.AddRigidBody(EID) : objectManager.AddCollider(EID);
#endif
} }
return EVENT_DATA->handle; worldState.world->destroyRigidBody(PHYSICS_OBJECT.body);
}
} }
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);
auto* COLLIDER = SHComponentManager::GetComponent<SHColliderComponent>(EID);
for (size_t i = 0; i < COLLIDER->GetCollisionShapes().size(); ++i)
objectManager.AddCollisionShape(EID, i);
}
};
////////////////////////////////
// Create physics world
if (worldState.world != nullptr)
return onPlayEvent->handle;
worldState.CreateWorld(factory);
#ifdef _PUBLISH
worldState.world->setIsDebugRenderingEnabled(false);
#else
worldState.world->setIsDebugRenderingEnabled(true);
#endif
// Link Collision Listener & Raycaster
collisionListener.BindToWorld(worldState.world);
raycaster.BindToWorld(worldState.world);
// Link with object manager & create all physics objects
objectManager.SetWorld(worldState.world);
// Build scene
SHSceneManager::GetCurrentSceneGraph().Traverse(BUILD_PHYSICS_OBJECT);
objectManager.UpdateCommands();
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();
raycaster.ClearFrame();
// Destroy the world
worldState.DestroyWorld(factory); worldState.DestroyWorld(factory);
return onStopEvent->handle;
} }
// Create the physics world & collision space
worldState.CreateWorld(factory);
// Link with managers
objectManager.SetPhysicsWorld(worldState.world);
objectManager.FlushDefinitions();
collisionListener.BindToWorld(worldState.world);
return onSceneInitEvent.get()->handle;
}
SHEventHandle SHPhysicsSystem::onSceneExit(SHEventPtr onSceneExitEvent)
{
/*
* Destroy the physics world.
* Destroy all physics objects.
*/
if (worldState.world)
{
// Remove all references of physics objects from the world
for (const auto& PHYSICS_OBJECT : objectManager.GetPhysicsObjects() | std::views::values)
{
if (PHYSICS_OBJECT.body)
worldState.world->destroyRigidBody(PHYSICS_OBJECT.body);
}
worldState.DestroyWorld(factory);
}
// Unlink with managers
objectManager.SetPhysicsWorld(nullptr);
return onSceneExitEvent.get()->handle;
}
SHEventHandle SHPhysicsSystem::onComponentAdded(SHEventPtr onComponentAddedEvent)
{
static const auto RIGID_BODY_COMPONENT_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_COMPONENT_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentAddedEvent>*>(onComponentAddedEvent.get())->data;
const auto ADDED_ID = EVENT_DATA->addedComponentType;
const bool IS_RIGID_BODY = ADDED_ID == RIGID_BODY_COMPONENT_ID;
const bool IS_COLLIDER = ADDED_ID == COLLIDER_COMPONENT_ID;
// Check if its a physics component
const bool IS_PHYSICS_COMPONENT = IS_RIGID_BODY || IS_COLLIDER;
if (!IS_PHYSICS_COMPONENT)
return onComponentAddedEvent.get()->handle;
const EntityID EID = EVENT_DATA->eid;
// Link engine components with physics object component
if (IS_RIGID_BODY)
{
if (worldState.world)
objectManager.AddRigidBody(EID);
else
objectManager.AddRigidBodyDef(EID);
}
if (IS_COLLIDER)
{
if (worldState.world)
objectManager.AddCollider(EID);
else
objectManager.AddColliderDef(EID);
}
return onComponentAddedEvent.get()->handle;
}
SHEventHandle SHPhysicsSystem::onComponentRemoved(SHEventPtr onComponentRemovedEvent)
{
static const auto RIGID_BODY_COMPONENT_ID = ComponentFamily::GetID<SHRigidBodyComponent>();
static const auto COLLIDER_COMPONENT_ID = ComponentFamily::GetID<SHColliderComponent>();
const auto& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(onComponentRemovedEvent.get())->data;
const auto REMOVED_DATA = EVENT_DATA->removedComponentType;
const bool IS_RIGID_BODY = REMOVED_DATA == RIGID_BODY_COMPONENT_ID;
const bool IS_COLLIDER = REMOVED_DATA == COLLIDER_COMPONENT_ID;
// Check if its a physics component
const bool IS_PHYSICS_COMPONENT = IS_RIGID_BODY || IS_COLLIDER;
if (!IS_PHYSICS_COMPONENT)
return onComponentRemovedEvent.get()->handle;
const EntityID EID = EVENT_DATA->eid;
if (IS_RIGID_BODY)
objectManager.RemoveRigidBody(EID);
if (IS_COLLIDER)
objectManager.RemoveCollider(EID);
return onComponentRemovedEvent.get()->handle;
}
} // namespace SHADE } // namespace SHADE

View File

@ -10,8 +10,7 @@
#pragma once #pragma once
#include <queue> #include <utility>
#include <unordered_map>
// External Dependencies // External Dependencies
#include <reactphysics3d/reactphysics3d.h> #include <reactphysics3d/reactphysics3d.h>
@ -19,14 +18,11 @@
// Project Headers // Project Headers
#include "ECS_Base/System/SHSystemRoutine.h" #include "ECS_Base/System/SHSystemRoutine.h"
#include "ECS_Base/System/SHFixedSystemRoutine.h" #include "ECS_Base/System/SHFixedSystemRoutine.h"
#include "Physics/Collision/SHCollisionInfo.h"
#include "Math/Transform/SHTransformComponent.h" #include "Physics/Interface/PhysicsObject/SHPhysicsObjectManager.h"
#include "Physics/Collision/SHCollisionListener.h" #include "Physics/RP3DWrapper/SHPhysicsWorld.h"
#include "Physics/Collision/SHPhysicsRaycaster.h" #include "Physics/RP3DWrapper/SHCollisionListener.h"
#include "Physics/Interface/SHRigidBodyComponent.h" #include "Physics/RP3DWrapper/SHRaycaster.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Physics/PhysicsObject/SHPhysicsObjectManager.h"
#include "Physics/SHPhysicsWorld.h"
#include "Scene/SHSceneGraph.h" #include "Scene/SHSceneGraph.h"
namespace SHADE namespace SHADE
@ -43,254 +39,150 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
friend class SHPhysicsDebugDrawSystem; friend class SHPhysicsDebugDrawSystem;
friend class SHCollisionListener;
friend class SHRaycaster;
public: public:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */ /* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHPhysicsSystem(); SHPhysicsSystem () noexcept;
~SHPhysicsSystem() noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
[[nodiscard]] double GetFixedUpdateRate () const noexcept; [[nodiscard]] double GetFixedUpdateRate () const noexcept;
[[nodiscard]] const SHPhysicsWorldState::WorldSettings& GetWorldSettings () const noexcept; [[nodiscard]] double GetFixedDT () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllCollisionInfo () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllTriggerInfo () const noexcept; [[nodiscard]] const std::vector<SHCollisionInfo>& GetAllTriggerInfo () const noexcept;
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllCollisionInfo () const noexcept;
[[nodiscard]] const SHPhysicsObject* GetPhysicsObject (EntityID eid) noexcept;
[[nodiscard]] const SHPhysicsObjectManager::PhysicsObjectEntityMap& GetPhysicsObjects () const noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SetFixedUpdateRate (double fixedUpdateRate) noexcept; void SetFixedUpdateRate (double fixedUpdateRate) noexcept;
void SetWorldSettings (const SHPhysicsWorldState::WorldSettings& settings) noexcept; void SetFixedDT (double fixedDt) noexcept;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/**
* @brief
* - Initialises the static collision tag matrix.
* - Registers the system to catch specific events.
*/
void Init() override; void Init() override;
void Exit() override; void Exit() override;
void BuildScene (SHSceneGraph& sceneGraph);
void ForceBuild (SHSceneGraph& sceneGraph);
void ForceUpdate ();
/**
* @brief Casts a ray into the world.
* @param ray The ray to cast.
* @param distance The distance to cast the ray. Defaults to infinity.
* @param collisionTag The collision tag to use for filtering the raycast.
* @return The result of the raycast.
*/
SHPhysicsRaycastResult Raycast
(
const SHRay& ray
, float distance = std::numeric_limits<float>::infinity()
, const SHCollisionTag& collisionTag = SHCollisionTag{}
) noexcept;
/**
* @brief Casts a bounded ray into the world.
* @param start The starting point of the ray.
* @param end The end point of the ray.
* @param collisionTag The collision tag to use for filtering the bounded raycast.
* @return The result of the raycast.
*/
SHPhysicsRaycastResult Linecast
(
const SHVec3& start
, const SHVec3& end
, const SHCollisionTag& collisionTag = SHCollisionTag{}
) noexcept;
/**
* @brief Casts a ray at a body with colliders.
* @param eid The entity to cast to.
* @param ray The ray to cast.
* @param distance The distance to cast the ray. Defaults to infinity.
* @return The result of the raycast.
*/
SHPhysicsRaycastResult ColliderRaycast
(
EntityID eid
, const SHRay& ray
, float distance = std::numeric_limits<float>::infinity()
) noexcept;
/**
* @brief Casts a ray at a collider.
* @param eid The entity to cast to.
* @param shapeIndex The index of the collision shape.
* @param ray The ray to cast.
* @param distance The distance to cast the ray. Defaults to infinity.
* @return The result of the raycast.
*/
SHPhysicsRaycastResult ColliderRaycast
(
EntityID eid
, int shapeIndex
, const SHRay& ray
, float distance = std::numeric_limits<float>::infinity()
) noexcept;
/**
* @brief Casts a bounded ray at a body with colliders.
* @param eid
* @param start
* @param end
* @return The result of the raycast.
*/
SHPhysicsRaycastResult ColliderLinecast
(
EntityID eid
, const SHVec3& start
, const SHVec3& end
) noexcept;
/** /**
* @brief * @brief
* @param eid * Casts a ray into the collision space.
* @param shapeIndex * @param info
* @param start * Contains the information for the raycast.
* @param end * @return
* @return The result of the raycast. * A container of the objects hit by the ray. If nothing was hit, the container
* will be empty.
*/ */
SHPhysicsRaycastResult ColliderLinecast [[nodiscard]] const std::vector<SHPhysicsRaycastResult>& Raycast(const SHRaycaster::RaycastInfo& info) noexcept;
(
EntityID eid
, int shapeIndex
, const SHVec3& start
, const SHVec3& end
) noexcept;
// Specific Handling for Collision Shapes as they are not under the Component System.
// This is done as events need to be sent out.
// TODO(Diren): Consider using a static method through the ColliderComponent.
void AddCollisionShape (EntityID eid, int shapeIndex);
void RemoveCollisionShape (EntityID eid, int shapeIndex);
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* System Routines */ /* System Routines */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/**
* @brief
* The physics update routine that runs before the simulation is updated.
* This is always running, regardless of the editor state.
* <br/>
* This update game logic is applied before the simulation runs.
*/
class SH_API PhysicsPreUpdate final : public SHSystemRoutine class SH_API PhysicsPreUpdate final : public SHSystemRoutine
{ {
public: public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsPreUpdate(); PhysicsPreUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override; void Execute(double dt) noexcept override;
private:
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void syncRigidBodyActive (EntityID eid, SHPhysicsObject& physicsObject) const noexcept;
void syncColliderActive (EntityID eid, SHPhysicsObject& physicsObject) const noexcept;
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 /**
* @brief
* The physics update routine that runs at a fixed rate. This is where the main
* simulation runs. If delta time is large enough, this may run more than once per
* frame. If delta time is small enough, this may not run at all.
*/
class SH_API PhysicsUpdate final : public SHFixedSystemRoutine
{ {
public: public:
/*-------------------------------------------------------------------------------*/ PhysicsUpdate();
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsFixedUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override; void Execute(double dt) noexcept override;
}; };
/**
* @brief
* The physics update that runs after the simulation. This sets the rendering
* transforms and sends messages to scripting system for collision & trigger events. <br/>
*
*/
class SH_API PhysicsPostUpdate final : public SHSystemRoutine class SH_API PhysicsPostUpdate final : public SHSystemRoutine
{ {
public: public:
/*-------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*-------------------------------------------------------------------------------*/
PhysicsPostUpdate(); PhysicsPostUpdate();
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
void Execute(double dt) noexcept override; void Execute(double dt) noexcept override;
private:
/*-------------------------------------------------------------------------------*/
/* Function Members */
/*-------------------------------------------------------------------------------*/
static void postUpdateSyncTransforms
(
SHPhysicsObject& physicsObject
, SHTransformComponent* transformComponent
, SHRigidBodyComponent* rigidBodyComponent
, SHColliderComponent* colliderComponent
, double interpolationFactor
) noexcept;
}; };
private: private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using EventFunctionPair = std::pair<SHEventHandle(SHPhysicsSystem::*)(SHEventPtr), SHEventIdentifier>;
struct RaycastHit
{
SHVec3 start;
SHVec3 end;
};
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
// System data static constexpr int NUM_EVENT_FUNCTIONS = 4;
// Event function container for cleanly registering to events
EventFunctionPair eventFunctions[NUM_EVENT_FUNCTIONS];
// System data
bool worldUpdated; bool worldUpdated;
double interpolationFactor; double interpolationFactor;
double fixedDT; double fixedDT;
// rp3d // Sub-systems / managers
rp3d::PhysicsCommon factory; rp3d::PhysicsCommon factory;
// Interface objects
SHPhysicsWorldState worldState; SHPhysicsWorldState worldState;
SHPhysicsObjectManager objectManager; SHPhysicsObjectManager objectManager;
SHCollisionListener collisionListener; SHCollisionListener collisionListener;
SHPhysicsRaycaster raycaster; SHRaycaster raycaster;
// For the debug drawer to draw rays
#ifdef SHEDITOR
std::vector<RaycastHit> raycastHits;
#endif
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Function Members */ /* Function Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHEventHandle addPhysicsComponent (SHEventPtr addComponentEvent) noexcept; SHEventHandle onSceneInit (SHEventPtr onSceneInitEvent);
SHEventHandle removePhysicsComponent (SHEventPtr removeComponentEvent) noexcept; SHEventHandle onSceneExit (SHEventPtr onSceneExitEvent);
SHEventHandle onPlay (SHEventPtr onPlayEvent); SHEventHandle onComponentAdded (SHEventPtr onComponentAddedEvent);
SHEventHandle onStop (SHEventPtr onStopEvent); SHEventHandle onComponentRemoved (SHEventPtr onComponentRemovedEvent);
SHEventHandle buildScene (SHEventPtr onSceneChangeEvent);
}; };
} // namespace SHADE } // namespace SHADE

View File

@ -52,85 +52,43 @@ namespace SHADE
double SHPhysicsSystemInterface::GetFixedDT() noexcept double SHPhysicsSystemInterface::GetFixedDT() noexcept
{ {
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>(); auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (phySystem) if (physicsSystem)
{ return physicsSystem->GetFixedDT();
return 1.0 / phySystem->GetFixedUpdateRate();
}
SHLOGV_WARNING("Failed to get fixed delta time. 0.0 returned instead."); SHLOGV_WARNING("Failed to get fixed delta time. 0.0 returned instead.");
return 0.0; return 0.0;
} }
SHPhysicsRaycastResult SHPhysicsSystemInterface::Raycast(const SHRay& ray, float distance) noexcept int SHPhysicsSystemInterface::GetFixedUpdateRate() noexcept
{ {
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>(); auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (physicsSystem) if (physicsSystem)
{ return physicsSystem->GetFixedUpdateRate();
return physicsSystem->Raycast(ray, distance);
SHLOGV_WARNING("Failed to get fixed update rate. 0.0 returned instead.");
return 0.0;
} }
SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); const std::vector<SHPhysicsRaycastResult>& SHPhysicsSystemInterface::Raycast(const RaycastInfo& info) noexcept
return SHPhysicsRaycastResult{};
}
SHPhysicsRaycastResult SHPhysicsSystemInterface::Linecast(const SHVec3& start, const SHVec3& end) noexcept
{ {
static std::vector<SHPhysicsRaycastResult> emptyVec;
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>(); auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (physicsSystem) if (physicsSystem)
{ {
return physicsSystem->Linecast(start, end); SHRaycaster::RaycastInfo raycastInfo;
raycastInfo.continuous = info.continuous;
raycastInfo.distance = info.distance;
raycastInfo.layers = info.layers;
raycastInfo.ray = info.ray;
if (info.colliderEntityID.has_value())
raycastInfo.SetColliderID(info.colliderEntityID.value());
return physicsSystem->Raycast(raycastInfo);
} }
SHLOGV_WARNING("Failed to get the physics system. No ray was casted."); return emptyVec;
return SHPhysicsRaycastResult{};
}
SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept
{
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (physicsSystem)
{
return physicsSystem->ColliderRaycast(eid, ray, distance);
}
SHLOGV_WARNING("Failed to get the physics system. No ray was casted.");
return SHPhysicsRaycastResult{};
}
SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderRaycast(EntityID eid, int shapeIndex, const SHRay& ray, float distance) noexcept
{
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (physicsSystem)
{
return physicsSystem->ColliderRaycast(eid, shapeIndex, ray, distance);
}
SHLOGV_WARNING("Failed to get the physics system. No ray was casted.");
return SHPhysicsRaycastResult{};
}
SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderLinecast(EntityID eid, const SHVec3& start, const SHVec3& end) noexcept
{
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (physicsSystem)
{
return physicsSystem->ColliderLinecast(eid, start, end);
}
SHLOGV_WARNING("Failed to get the physics system. No ray was casted.");
return SHPhysicsRaycastResult{};
}
SHPhysicsRaycastResult SHPhysicsSystemInterface::ColliderLinecast(EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept
{
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (physicsSystem)
{
return physicsSystem->ColliderLinecast(eid, shapeIndex, start, end);
}
SHLOGV_WARNING("Failed to get the physics system. No ray was casted.");
return SHPhysicsRaycastResult{};
} }
} }

View File

@ -12,11 +12,13 @@ of DigiPen Institute of Technology is prohibited.
#pragma once #pragma once
// STL Includes // STL Includes
#include <optional>
#include <vector> #include <vector>
// Project Headers // Project Headers
#include "ECS_Base/Entity/SHEntity.h" #include "ECS_Base/Entity/SHEntity.h"
#include "Math/SHRay.h"
#include "Physics/Collision/CollisionTags/SHCollisionTags.h"
namespace SHADE namespace SHADE
{ {
@ -25,11 +27,8 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
class SHCollisionInfo; class SHCollisionInfo;
class SHVec3;
struct SHRay;
struct SHPhysicsRaycastResult; struct SHPhysicsRaycastResult;
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -40,6 +39,48 @@ namespace SHADE
class SH_API SHPhysicsSystemInterface final class SH_API SHPhysicsSystemInterface final
{ {
public: public:
struct RaycastInfo
{
private:
/*-------------------------------------------------------------------------------*/
/* Friends */
/*-------------------------------------------------------------------------------*/
friend class SHPhysicsSystemInterface;
public:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
bool continuous = false;
uint16_t layers = static_cast<uint16_t>(SHCollisionTag::Layer::ALL);
float distance = std::numeric_limits<float>::infinity();
SHRay ray;
/*-------------------------------------------------------------------------------*/
/* Setter Functions */
/*-------------------------------------------------------------------------------*/
/**
* @brief
* Sets the collider ID for the raycast. Setting this specifies that the ray
* should ignore this collider.
* @param eid
* The entity ID of the collider.
*/
void SetColliderID(EntityID eid) noexcept { colliderEntityID = eid; }
private:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
std::optional<EntityID> colliderEntityID;
};
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructor */ /* Constructor */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -52,12 +93,8 @@ namespace SHADE
[[nodiscard]] static const std::vector<SHCollisionInfo>& GetCollisionInfo () noexcept; [[nodiscard]] static const std::vector<SHCollisionInfo>& GetCollisionInfo () noexcept;
[[nodiscard]] static const std::vector<SHCollisionInfo>& GetTriggerInfo () noexcept; [[nodiscard]] static const std::vector<SHCollisionInfo>& GetTriggerInfo () noexcept;
[[nodiscard]] static double GetFixedDT () noexcept; [[nodiscard]] static double GetFixedDT () noexcept;
[[nodiscard]] static int GetFixedUpdateRate () noexcept;
[[nodiscard]] static const std::vector<SHPhysicsRaycastResult>& Raycast (const RaycastInfo& info) noexcept;
[[nodiscard]] static SHPhysicsRaycastResult Raycast (const SHRay& ray, float distance = std::numeric_limits<float>::infinity()) noexcept;
[[nodiscard]] static SHPhysicsRaycastResult Linecast (const SHVec3& start, const SHVec3& end) noexcept;
[[nodiscard]] static SHPhysicsRaycastResult ColliderRaycast (EntityID eid, const SHRay& ray, float distance = std::numeric_limits<float>::infinity()) noexcept;
[[nodiscard]] static SHPhysicsRaycastResult ColliderRaycast (EntityID eid, int shapeIndex, const SHRay& ray, float distance = std::numeric_limits<float>::infinity()) noexcept;
[[nodiscard]] static SHPhysicsRaycastResult ColliderLinecast (EntityID eid, const SHVec3& start, const SHVec3& end) noexcept;
[[nodiscard]] static SHPhysicsRaycastResult ColliderLinecast (EntityID eid, int shapeIndex, const SHVec3& start, const SHVec3& end) noexcept;
}; };
} }

View File

@ -1,412 +0,0 @@
/****************************************************************************************
* \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/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h"
#include "Scene/SHSceneManager.h"
#include "Scripting/SHScriptEngine.h"
#include "Input/SHInputManager.h"
#include "Physics/Collision/SHCollisionTagMatrix.h"
/*-------------------------------------------------------------------------------------*/
/* Local Functions */
/*-------------------------------------------------------------------------------------*/
void testFunction();
/////////////////////////////////////////////////////////////////////////////////////////
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
// Only Sync on Play.
// Otherwise, Components are only holding data until the world is built on play.
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && 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;
// Sync active states between SHADE & RP3D
syncRigidBodyActive(entityID, physicsObject);
syncColliderActive(entityID, physicsObject);
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;
syncRigidBodyActive(entityID, physicsObject);
syncColliderActive(entityID, physicsObject);
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!");
}
const double FIXED_DT = physicsSystem->fixedDT;
// HACK: Clamp DT here to prevent a ridiculous amount of updates. This limits updates from large dt to 2.
// HACK: This should be done by the FRC and not here for predictable behaviour.
accumulatedTime += dt;
//testFunction();
int count = 0;
while (accumulatedTime > FIXED_DT)
{
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteFixedUpdates();
physicsSystem->worldState.world->update(static_cast<rp3d::decimal>(FIXED_DT));
accumulatedTime -= FIXED_DT;
++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);
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::syncRigidBodyActive(EntityID eid, SHPhysicsObject& physicsObject) const noexcept
{
if (!SHComponentManager::HasComponent<SHRigidBodyComponent>(eid))
return;
const bool IS_ACTIVE_IN_SCENE = SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(eid);
const bool IS_RP3D_BODY_ACTIVE = physicsObject.GetRigidBody()->isActive();
if (IS_ACTIVE_IN_SCENE != IS_RP3D_BODY_ACTIVE)
physicsObject.GetRigidBody()->setIsActive(IS_ACTIVE_IN_SCENE);
}
void SHPhysicsSystem::PhysicsPreUpdate::syncColliderActive(EntityID eid, SHPhysicsObject& physicsObject) const noexcept
{
const auto* COLLIDER = SHComponentManager::GetComponent_s<SHColliderComponent>(eid);
if (!COLLIDER)
return;
const bool IS_ACTIVE_IN_SCENE = SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(eid);
const bool IS_RP3D_COLLIDER_ACTIVE = physicsObject.collidersActive;
if (IS_ACTIVE_IN_SCENE != IS_RP3D_COLLIDER_ACTIVE)
{
// HACK: If active state turned off, remove all collision shapes. If turned on, add them back.
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
const int NUM_SHAPES = static_cast<int>(COLLIDER->GetCollisionShapes().size());
if (IS_ACTIVE_IN_SCENE)
{
for (int i = 0; i < NUM_SHAPES; ++i)
physicsSystem->objectManager.AddCollisionShape(eid, i);
}
else
{
for (int i = NUM_SHAPES - 1; i >= 0; --i)
physicsSystem->objectManager.RemoveCollisionShape(eid, i);
}
physicsObject.collidersActive = IS_ACTIVE_IN_SCENE;
}
}
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())
{
physicsObject.GetRigidBody()->setIsSleeping(false);
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
{
if (!transformComponent)
return;
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);
physicsObject.prevTransform = RP3D_TRANSFORM;
if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(physicsObject.entityID))
{
rigidBodyComponent->position = WORLD_POS;
rigidBodyComponent->orientation = WORLD_ROT;
}
if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(physicsObject.entityID))
{
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
{
const rp3d::Transform& CURRENT_TF = physicsObject.GetRigidBody()->getTransform();
auto renderPos = CURRENT_TF.getPosition();
auto renderRot = CURRENT_TF.getOrientation();
// Cache transforms
if (physicsObject.GetRigidBody()->isActive())
physicsObject.prevTransform = CURRENT_TF;
// Sync with rigid bodies
if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(physicsObject.entityID))
{
// Skip static bodies
if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
return;
// Check if transform should be interpolated
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));
renderPos = INTERPOLATED_TF.getPosition();
renderRot = INTERPOLATED_TF.getOrientation();
}
rigidBodyComponent->position = CURRENT_TF.getPosition();
rigidBodyComponent->orientation = CURRENT_TF.getOrientation();
// Sync with colliders
if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(physicsObject.entityID))
{
// Skip colliders without rigidbody components. If any transform was updated, it was done in pre-update.
colliderComponent->position = CURRENT_TF.getPosition();
colliderComponent->orientation = CURRENT_TF.getOrientation();
}
// Set transform for rendering
if (transformComponent)
{
transformComponent->SetWorldPosition(renderPos);
transformComponent->SetWorldOrientation(renderRot);
}
}
}
} // namespace SHADE
/////////////////////////////////////////////////////////////////////////////////////////
void testFunction()
{
using namespace SHADE;
// Test movement
const float forceModifier = 25.0f;
EntityID eid = 65538;
if (SHEntityManager::IsValidEID(eid))
{
auto* rb = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(eid);
if (rb)
{
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::W))
rb->AddForce(SHVec3::UnitZ * forceModifier);
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::A))
rb->AddForce(-SHVec3::UnitX * forceModifier);
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::S))
rb->AddForce(-SHVec3::UnitZ * forceModifier);
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::D))
rb->AddForce(SHVec3::UnitX * forceModifier);
}
}
// Cast rays
auto* tag = SHCollisionTagMatrix::GetTag(1);
tag->SetLayerState(SHCollisionTag::Layer::_1, false);
tag->SetLayerState(SHCollisionTag::Layer::_2, true);
SHRay ray { SHVec3{3.0f, 3.5f, 0.0f}, -SHVec3::UnitX };
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
physicsSystem->Raycast(ray, std::numeric_limits<float>::infinity(), *tag);
}

View File

@ -3,9 +3,8 @@
#include "Physics/Interface/SHColliderComponent.h" #include "Physics/Interface/SHColliderComponent.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h"
#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h"
#include "Math/Geometry/SHBox.h" #include "Physics/Collision/Shapes/SHSphere.h"
#include "Math/Geometry/SHSphere.h" #include "Physics/Collision/Shapes/SHBox.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"
@ -15,7 +14,7 @@
#include "SHSerializationTools.h" #include "SHSerializationTools.h"
#include "Graphics/MiddleEnd/TextRendering/SHFont.h" #include "Graphics/MiddleEnd/TextRendering/SHFont.h"
#include "Animation/SHAnimatorComponent.h" #include "Animation/SHAnimatorComponent.h"
#include "Physics/Collision/SHCollisionTagMatrix.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
namespace YAML namespace YAML
{ {
@ -149,17 +148,17 @@ namespace YAML
{ {
case SHCollisionShape::Type::BOX: case SHCollisionShape::Type::BOX:
{ {
const auto* BOX = reinterpret_cast<const SHBox*>(rhs.GetShape()); const auto& BOX_SHAPE = dynamic_cast<SHBox&>(rhs);
node[HalfExtents] = BOX->GetRelativeExtents(); node[HalfExtents] = BOX_SHAPE.GetRelativeExtents();
} }
break; break;
case SHCollisionShape::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
{ {
const auto* SPHERE = reinterpret_cast<const SHSphere*>(rhs.GetShape()); const auto& SPHERE_SHAPE = dynamic_cast<SHSphere&>(rhs);
node[Radius] = SPHERE->GetRelativeRadius(); node[Radius] = SPHERE_SHAPE.GetRelativeRadius();
} }
break; break;
case SHCollisionShape::Type::CAPSULE: break; //case SHCollisionShape::Type::CAPSULE: break;
default:; default:;
} }
@ -192,16 +191,16 @@ namespace YAML
case SHCollisionShape::Type::BOX: case SHCollisionShape::Type::BOX:
{ {
if (node[HalfExtents].IsDefined()) if (node[HalfExtents].IsDefined())
rhs.SetBoundingBox(node[HalfExtents].as<SHVec3>()); dynamic_cast<SHBox&>(rhs).SetRelativeExtents(node[HalfExtents].as<SHVec3>());
} }
break; break;
case SHCollisionShape::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
{ {
if (node[Radius].IsDefined()) if (node[Radius].IsDefined())
rhs.SetBoundingSphere(node[Radius].as<float>()); dynamic_cast<SHSphere&>(rhs).SetRelativeRadius(node[Radius].as<float>());
} }
break; break;
case SHCollisionShape::Type::CAPSULE: break; //case SHCollisionShape::Type::CAPSULE: break;
default:; default:;
} }
if (node[Friction].IsDefined()) if (node[Friction].IsDefined())
@ -254,9 +253,9 @@ namespace YAML
switch (colliderType) switch (colliderType)
{ {
case SHCollisionShape::Type::BOX: rhs.AddBoundingBox(); break; case SHCollisionShape::Type::BOX: rhs.AddBoxCollisionShape(SHVec3::One); break;
case SHCollisionShape::Type::SPHERE: rhs.AddBoundingSphere(); break; case SHCollisionShape::Type::SPHERE: rhs.AddSphereCollisionShape(1.0f); break;
case SHCollisionShape::Type::CAPSULE: break; //case SHCollisionShape::Type::CAPSULE: break;
default:; default:;
} }
YAML::convert<SHCollisionShape>::decode(colliderNode, rhs.GetCollisionShape(numColliders++)); YAML::convert<SHCollisionShape>::decode(colliderNode, rhs.GetCollisionShape(numColliders++));

View File

@ -4,7 +4,6 @@
\par email: kahwei.tng\@digipen.edu \par email: kahwei.tng\@digipen.edu
\date Oct 20, 2022 \date Oct 20, 2022
\brief Contains the definition of the functions of the managed Collider class. \brief Contains the definition of the functions of the managed Collider class.
Note: This file is written in C++17/CLI. Note: This file is written in C++17/CLI.
Copyright (C) 2022 DigiPen Institute of Technology. Copyright (C) 2022 DigiPen Institute of Technology.
@ -15,6 +14,9 @@ of DigiPen Institute of Technology is prohibited.
#include "SHpch.h" #include "SHpch.h"
// Primary Header // Primary Header
#include "Collider.hxx" #include "Collider.hxx"
#include "Physics/Collision/Shapes/SHBox.h"
#include "Physics/Collision/Shapes/SHSphere.h"
#include "Utility/Debug.hxx" #include "Utility/Debug.hxx"
namespace SHADE namespace SHADE
@ -120,7 +122,7 @@ namespace SHADE
/* BoxCollider - Constructors */ /* BoxCollider - Constructors */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
BoxCollider::BoxCollider(int arrayIdx, Entity attachedEntity) BoxCollider::BoxCollider(int arrayIdx, Entity attachedEntity)
: CollisionShape { arrayIndex, attachedEntity } : CollisionShape { arrayIdx, attachedEntity }
{} {}
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -128,11 +130,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Vector3 BoxCollider::Center::get() Vector3 BoxCollider::Center::get()
{ {
return Convert::ToCLI(getNativeCollisionShape<SHBox>().GetCenter()); return Convert::ToCLI(getNativeCollisionShape<SHBox>().GetWorldCentroid());
}
void BoxCollider::Center::set(Vector3 value)
{
getNativeCollisionShape<SHBox>().SetCenter(Convert::ToNative(value));
} }
Vector3 BoxCollider::HalfExtents::get() Vector3 BoxCollider::HalfExtents::get()
{ {
@ -142,21 +140,10 @@ namespace SHADE
{ {
getNativeCollisionShape<SHBox>().SetWorldExtents(Convert::ToNative(value)); getNativeCollisionShape<SHBox>().SetWorldExtents(Convert::ToNative(value));
} }
Vector3 BoxCollider::Min::get() Quaternion BoxCollider::Orientation::get()
{ {
return Convert::ToCLI(getNativeCollisionShape<SHBox>().GetMin()); //return Convert::ToCLI(getNativeCollisionShape<SHBox>().GetWorldOrientation());
} return Quaternion::Identity;
void BoxCollider::Min::set(Vector3 value)
{
getNativeCollisionShape<SHBox>().SetMin(Convert::ToNative(value));
}
Vector3 BoxCollider::Max::get()
{
return Convert::ToCLI(getNativeCollisionShape<SHBox>().GetMax());
}
void BoxCollider::Max::set(Vector3 value)
{
getNativeCollisionShape<SHBox>().SetMax(Convert::ToNative(value));
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -164,11 +151,13 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
bool BoxCollider::TestPoint(Vector3 point) bool BoxCollider::TestPoint(Vector3 point)
{ {
return getNativeCollisionShape<SHBox>().TestPoint(Convert::ToNative(point)); //return getNativeCollisionShape<SHAABB>().TestPoint(Convert::ToNative(point));
return false;
} }
bool BoxCollider::Raycast(Ray ray, float maxDistance) bool BoxCollider::Raycast(Ray ray, float maxDistance)
{ {
return getNativeCollisionShape<SHBox>().Raycast(Convert::ToNative(ray)); //return getNativeCollisionShape<SHAABB>().Raycast(Convert::ToNative(ray));
return false;
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -176,11 +165,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Vector3 SphereCollider::Center::get() Vector3 SphereCollider::Center::get()
{ {
return Convert::ToCLI(getNativeCollisionShape<SHSphere>().GetCenter()); return Convert::ToCLI(getNativeCollisionShape<SHSphere>().GetWorldCentroid());
}
void SphereCollider::Center::set(Vector3 value)
{
getNativeCollisionShape<SHSphere>().SetCenter(Convert::ToNative(value));
} }
float SphereCollider::Radius::get() float SphereCollider::Radius::get()
{ {
@ -196,11 +181,13 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
bool SphereCollider::TestPoint(Vector3 point) bool SphereCollider::TestPoint(Vector3 point)
{ {
return getNativeCollisionShape<SHBox>().TestPoint(Convert::ToNative(point)); //return getNativeCollisionShape<SHSphere>().TestPoint(Convert::ToNative(point));
return false;
} }
bool SphereCollider::Raycast(Ray ray, float maxDistance) bool SphereCollider::Raycast(Ray ray, float maxDistance)
{ {
return getNativeCollisionShape<SHBox>().Raycast(Convert::ToNative(ray)); //return getNativeCollisionShape<SHSphere>().Raycast(Convert::ToNative(ray));
return false;
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -231,7 +218,10 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
int Collider::CollisionShapeCount::get() int Collider::CollisionShapeCount::get()
{ {
return static_cast<int>(GetNativeComponent()->GetCollisionShapes().size()); if (const auto* nativeComponent = GetNativeComponent(); nativeComponent)
return static_cast<int>(nativeComponent->GetCollisionShapes().size());
return -1;
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -314,7 +304,7 @@ namespace SHADE
for (const auto& collider : GetNativeComponent()->GetCollisionShapes()) for (const auto& collider : GetNativeComponent()->GetCollisionShapes())
{ {
CollisionShape^ bound = nullptr; CollisionShape^ bound = nullptr;
switch (collider.GetType()) switch (collider->GetType())
{ {
case SHCollisionShape::Type::BOX: case SHCollisionShape::Type::BOX:
bound = gcnew BoxCollider(i, Owner.GetEntity()); bound = gcnew BoxCollider(i, Owner.GetEntity());
@ -322,9 +312,9 @@ namespace SHADE
case SHCollisionShape::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
bound = gcnew SphereCollider(i, Owner.GetEntity()); bound = gcnew SphereCollider(i, Owner.GetEntity());
break; break;
case SHCollisionShape::Type::CAPSULE: //case SHCollisionShape::Type::CAPSULE:
// TODO // // TODO
break; // break;
default: default:
Debug::LogWarning("[Collider] An invalid Collider Type was detected. Skipping."); Debug::LogWarning("[Collider] An invalid Collider Type was detected. Skipping.");
break; break;

View File

@ -31,7 +31,7 @@ namespace SHADE
if (shape.GetType() != SHCollisionShape::Type::BOX) if (shape.GetType() != SHCollisionShape::Type::BOX)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape.");
return reinterpret_cast<CollisionShapeType&>(shape); return dynamic_cast<CollisionShapeType&>(shape);
} }
catch (std::invalid_argument&) catch (std::invalid_argument&)
{ {

View File

@ -1,7 +1,9 @@
/************************************************************************************//*! /************************************************************************************//*!
\file Collider.hxx \file Collider.hxx
\author Tng Kah Wei, kahwei.tng, 390009620 \author Tng Kah Wei, kahwei.tng, 390009620
Diren D Bharwani, diren.dbharwani, 390002520
\par email: kahwei.tng\@digipen.edu \par email: kahwei.tng\@digipen.edu
email: diren.dbharwani\@digipen.edu
\date Oct 20, 2022 \date Oct 20, 2022
\brief Contains the definition of the managed Collider class with the \brief Contains the definition of the managed Collider class with the
declaration of functions for working with it. declaration of functions for working with it.
@ -142,15 +144,14 @@ namespace SHADE
/* Properties */ /* Properties */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Center of the Bounding Box formed by this bound. /// Center of the box collider.
/// </summary> /// </summary>
property Vector3 Center property Vector3 Center
{ {
Vector3 get(); Vector3 get();
void set(Vector3 value);
} }
/// <summary> /// <summary>
/// Half of the scale of the Bounding Box formed by this bound. /// Half of the scale of the box collider.
/// </summary> /// </summary>
property Vector3 HalfExtents property Vector3 HalfExtents
{ {
@ -158,22 +159,11 @@ namespace SHADE
void set(Vector3 value); void set(Vector3 value);
} }
/// <summary> /// <summary>
/// Position of the bottom left back corner of the Bounding Box formed by this /// The orientation of the box.
/// bound.
/// </summary> /// </summary>
property Vector3 Min property Quaternion Orientation
{ {
Vector3 get(); Quaternion get();
void set(Vector3 value);
}
/// <summary>
/// Position of the top right front corner of the Bounding Box formed by this
/// bound.
/// </summary>
property Vector3 Max
{
Vector3 get();
void set(Vector3 value);
} }
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -201,12 +191,11 @@ namespace SHADE
/* Properties */ /* Properties */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Center of the Bounding Sphere formed by this bound. /// Center of the sphere.
/// </summary> /// </summary>
property Vector3 Center property Vector3 Center
{ {
Vector3 get(); Vector3 get();
void set(Vector3 value);
} }
/// <summary> /// <summary>
/// Radius of the Bounding Sphere formed by this bound. /// Radius of the Bounding Sphere formed by this bound.

View File

@ -15,10 +15,14 @@
// External Dependencies // External Dependencies
#include "Physics/System/SHPhysicsSystemInterface.h" #include "Physics/System/SHPhysicsSystemInterface.h"
// Project Header // Project Header
#include "Components/Collider.hxx"
#include "Components/Transform.hxx"
#include "Engine/GameObject.hxx" #include "Engine/GameObject.hxx"
#include "Utility/Convert.hxx" #include "Utility/Convert.hxx"
#include "Utility/Debug.hxx" #include "Utility/Debug.hxx"
using namespace System::Collections::Generic;
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -41,49 +45,262 @@ namespace SHADE
/* Raycast Function Member Definitions */ /* Raycast Function Member Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
RaycastHit Physics::Raycast(Ray ray) List<RaycastHit>^ Physics::Raycast(Ray ray, bool continuous)
{ {
return Convert::ToCLI(SHPhysicsSystemInterface::Raycast(Convert::ToNative(ray))); List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Cast natively
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.continuous = continuous;
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
} }
RaycastHit Physics::Raycast(Ray ray, float distance) return results;
{
return Convert::ToCLI(SHPhysicsSystemInterface::Raycast(Convert::ToNative(ray), distance));
} }
RaycastHit Physics::Linecast(Vector3 start, Vector3 end) List<RaycastHit>^ Physics::Raycast(Ray ray, float distance, bool continuous)
{ {
return Convert::ToCLI(SHPhysicsSystemInterface::Linecast(Convert::ToNative(start), Convert::ToNative(end))); List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Cast natively
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.distance = distance;
raycastInfo.continuous = continuous;
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
} }
RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray) return results;
{
return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, Convert::ToNative(ray)));
} }
RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray, float distance) List<RaycastHit>^ Physics::Linecast(Vector3 start, Vector3 end, bool continuous)
{ {
return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, Convert::ToNative(ray), distance)); List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Cast natively
Vector3 direction = end - start;
direction.Normalise();
const Ray CLI_RAY( start, direction );
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(CLI_RAY);
raycastInfo.distance = (end - start).GetMagnitude();
raycastInfo.continuous = continuous;
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
} }
RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray) return results;
{
return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, shapeIndex, Convert::ToNative(ray)));
} }
RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance) List<RaycastHit>^ Physics::ColliderRaycast(GameObject object, Ray ray, bool continuous)
{ {
return Convert::ToCLI(SHPhysicsSystemInterface::ColliderRaycast(object.EntityId, shapeIndex, Convert::ToNative(ray), distance)); List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position (same as the transform)
Transform^ managedTransform = object.GetComponent<Transform^>();
if (!managedTransform)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform.");
const Vector3 COLLIDER_POS = managedTransform->GlobalPosition;
ray.Position += COLLIDER_POS;
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.continuous = continuous;
raycastInfo.SetColliderID(object.EntityId);
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
} }
RaycastHit Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end) return results;
{
return Convert::ToCLI(SHPhysicsSystemInterface::ColliderLinecast(object.EntityId, Convert::ToNative(start), Convert::ToNative(end)));
} }
RaycastHit Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end) List<RaycastHit>^ Physics::ColliderRaycast(GameObject object, Ray ray, float distance, bool continuous)
{ {
return Convert::ToCLI(SHPhysicsSystemInterface::ColliderLinecast(object.EntityId, shapeIndex, Convert::ToNative(start), Convert::ToNative(end))); List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position (same as the transform)
Transform^ managedTransform = object.GetComponent<Transform^>();
if (!managedTransform)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform.");
const Vector3 COLLIDER_POS = managedTransform->GlobalPosition;
ray.Position += COLLIDER_POS;
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.distance = distance;
raycastInfo.continuous = continuous;
raycastInfo.SetColliderID(object.EntityId);
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
List<RaycastHit>^ Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, bool continuous)
{
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position
Vector3 shapePos = Vector3::Zero;
Collider^ managedCollider = object.GetComponent<Collider^>();
if (!managedCollider)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Collider.");
CollisionShape^ managedShape = managedCollider->GetCollisionShape(shapeIndex);
if (!managedShape)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape.");
const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape();
shapePos = Convert::ToCLI(NATIVE_SHAPE.GetWorldCentroid());
ray.Position += shapePos;
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.continuous = continuous;
raycastInfo.SetColliderID(object.EntityId);
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
List<RaycastHit>^ Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance, bool continuous)
{
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position
Vector3 shapePos = Vector3::Zero;
Collider^ managedCollider = object.GetComponent<Collider^>();
if (!managedCollider)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Collider.");
CollisionShape^ managedShape = managedCollider->GetCollisionShape(shapeIndex);
if (!managedShape)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape.");
const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape();
shapePos = Convert::ToCLI(NATIVE_SHAPE.GetWorldCentroid());
ray.Position += shapePos;
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.continuous = continuous;
raycastInfo.distance = distance;
raycastInfo.SetColliderID(object.EntityId);
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
List<RaycastHit>^ Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end, bool continuous)
{
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position (same as the transform)
Transform^ managedTransform = object.GetComponent<Transform^>();
if (!managedTransform)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform.");
const Vector3 COLLIDER_POS = managedTransform->GlobalPosition;
start += COLLIDER_POS;
Vector3 direction = end - start;
direction.Normalise();
const Ray CLI_RAY( start, direction );
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(CLI_RAY);
raycastInfo.distance = (end - start).GetMagnitude();
raycastInfo.continuous = continuous;
raycastInfo.SetColliderID(object.EntityId);
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
List<RaycastHit>^ Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end, bool continuous)
{
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position
Vector3 shapePos = Vector3::Zero;
Collider^ managedCollider = object.GetComponent<Collider^>();
if (!managedCollider)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Collider.");
CollisionShape^ managedShape = managedCollider->GetCollisionShape(shapeIndex);
if (!managedShape)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape.");
const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape();
shapePos = Convert::ToCLI(NATIVE_SHAPE.GetWorldCentroid());
start += shapePos;
Vector3 direction = end - start;
direction.Normalise();
const Ray CLI_RAY( start, direction );
SHPhysicsSystemInterface::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(CLI_RAY);
raycastInfo.continuous = continuous;
raycastInfo.distance = (end - start).GetMagnitude();
raycastInfo.SetColliderID(object.EntityId);
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/

View File

@ -40,82 +40,143 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Casts an infinite ray into the world. /// Casts an infinite ray into the world. <br/>
/// This raycast will stop at the first object hit.
/// </summary> /// </summary>
/// <param name="ray">The ray to cast.</param> /// <param name="ray">The ray to cast.</param>
/// <returns>The result of the raycast.</returns> /// <param name="continuous">
static RaycastHit Raycast (Ray ray); /// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ Raycast (Ray ray, bool continuous);
/// <summary> /// <summary>
/// Casts a ray for a given distance into the world. /// Casts a ray for a given distance into the world.
/// </summary> /// </summary>
/// <param name="ray">The ray to cast.</param> /// <param name="ray">The ray to cast.</param>
/// <param name="distance">The distance to cast the ray.</param> /// <param name="distance">The distance to cast the ray.</param>
/// <returns>The result of the raycast.</returns> /// <param name="continuous">
static RaycastHit Raycast (Ray ray, float distance); /// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ Raycast (Ray ray, float distance, bool continuous);
/// <summary> /// <summary>
/// Casts a bounded ray into the world. /// Casts a bounded ray into the world.
/// </summary> /// </summary>
/// <param name="start">The start of the bounded ray.</param> /// <param name="start">The start of the bounded ray.</param>
/// <param name="end">The end of the bounded ray.</param> /// <param name="end">The end of the bounded ray.</param>
/// <returns>The result of the raycast.</returns> /// <param name="continuous">
static RaycastHit Linecast (Vector3 start, Vector3 end); /// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ Linecast (Vector3 start, Vector3 end, bool continuous);
/// <summary> /// <summary>
/// Casts an infinite ray w.r.t a GameObject. /// Casts an infinite ray w.r.t a GameObject.
/// </summary> /// </summary>
/// <param name="object">The GameObject to cast the ray to.</param> /// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="ray">The ray to cast.</param> /// <param name="ray">
/// <returns>The result of the raycast.</returns> /// The ray to cast. <br/>
static RaycastHit ColliderRaycast (GameObject object, Ray ray); /// The position of the ray is offset from the collider's position.
/// </param>
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderRaycast (GameObject object, Ray ray, bool continuous);
/// <summary> /// <summary>
/// Casts a ray for a given distance w.r.t a GameObject. /// Casts a ray for a given distance w.r.t a GameObject.
/// </summary> /// </summary>
/// <param name="object">The GameObject to cast the ray to.</param> /// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="ray">The ray to cast.</param> /// <param name="ray">
/// The ray to cast. <br/>
/// The position of the ray is offset from the collider's position.
/// </param>
/// <param name="distance">The distance to cast the ray.</param> /// <param name="distance">The distance to cast the ray.</param>
/// <returns>The result of the raycast.</returns> /// <param name="continuous">
static RaycastHit ColliderRaycast (GameObject object, Ray ray, float distance); /// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderRaycast (GameObject object, Ray ray, float distance, bool continuous);
/// <summary> /// <summary>
/// Casts an infinite ray w.r.t a specific collider on a GameObject. /// Casts an infinite ray w.r.t a specific collider on a GameObject.
/// </summary> /// </summary>
/// <param name="object">The GameObject to cast the ray to.</param> /// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="shapeIndex">The collision shape index on the collider to cast to.</param> /// <param name="shapeIndex">The collision shape index on the collider to cast to.</param>
/// <param name="ray">The ray to cast.</param> /// <param name="ray">
/// <returns>The result of the raycast.</returns> /// The ray to cast. <br/>
static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray); /// The position of the ray is offset from the collider's position.
/// </param>
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderRaycast (GameObject object, int shapeIndex, Ray ray, bool continuous);
/// <summary> /// <summary>
/// Casts a ray for a given distance w.r.t a specific collider on a GameObject. /// Casts a ray for a given distance w.r.t a specific collider on a GameObject.
/// </summary> /// </summary>
/// <param name="object">The GameObject to cast the ray to.</param> /// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="shapeIndex">The collision shape index on the collider to cast to.</param> /// <param name="shapeIndex">The collision shape index on the collider to cast to.</param>
/// <param name="ray">The ray to cast.</param> /// <param name="ray">
/// The ray to cast. <br/>
/// The position of the ray is offset from the collider's position.
/// </param>
/// <param name="distance">The distance to cast the ray.</param> /// <param name="distance">The distance to cast the ray.</param>
/// <returns>The result of the raycast.</returns> /// <param name="continuous">
static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance); /// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance, bool continuous);
/// <summary> /// <summary>
/// Casts a bounded ray w.r.t a GameObject. /// Casts a bounded ray w.r.t a GameObject.
/// </summary> /// </summary>
/// <param name="object">The GameObject to cast the ray to.</param> /// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="start">The start of the bounded ray.</param> /// <param name="start">
/// The start of the bounded ray. <br/>
/// The start of the ray is offset from the collider's position. </param>
/// <param name="end"></param> /// <param name="end"></param>
/// <returns>The result of the raycast.</returns> /// <param name="continuous">
static RaycastHit ColliderLineCast (GameObject object, Vector3 start, Vector3 end); /// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderLineCast (GameObject object, Vector3 start, Vector3 end, bool continuous);
/// <summary> /// <summary>
/// Casts a bounded ray w.r.t a specific collider on a GameObject. /// Casts a bounded ray w.r.t a specific collider on a GameObject.
/// </summary> /// </summary>
/// <param name="object">The GameObject to cast the ray to.</param> /// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="shapeIndex">The collision shape index on the collider to cast to.</param> /// <param name="shapeIndex">The collision shape index on the collider to cast to.</param>
/// <param name="start">The start of the bounded ray.</param> /// <param name="start">
/// The start of the bounded ray. <br/>
/// The start of the ray is offset from the collider's position. </param>
/// <param name="end">The end of the bounded ray.</param> /// <param name="end">The end of the bounded ray.</param>
/// <returns>The result of the raycast.</returns> /// <param name="continuous">
static RaycastHit ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end); /// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned./// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end, bool continuous);
private: private:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/