Implemented a custom physics engine #316

Merged
direnbharwani merged 95 commits from SHPhysics into main 2023-01-23 15:55:45 +08:00
9 changed files with 66 additions and 110 deletions
Showing only changes of commit 5def5392a1 - Show all commits

View File

@ -1,5 +1,5 @@
/****************************************************************************************
* \file SHCollisionID.h
* \file SHCollisionKey.h
* \author Diren D Bharwani, diren.dbharwani, 390002520
* \brief Interface for Collision Information for Collision & Triggers.
*
@ -11,7 +11,7 @@
#pragma once
// Project Headers
#include "SHCollisionID.h"
#include "SHCollisionKey.h"
namespace SHADE
{
@ -37,7 +37,7 @@ namespace SHADE
struct SH_API SHTriggerEvent
{
public:
SHCollisionID info;
SHCollisionKey info;
SHCollisionState state;
};
@ -51,7 +51,7 @@ namespace SHADE
public:
static constexpr int MAX_NUM_CONTACTS = 4;
SHCollisionID info;
SHCollisionKey info;
SHCollisionState state;
SHVec3 normal;
SHVec3 contactPoints[MAX_NUM_CONTACTS];

View File

@ -11,7 +11,7 @@
#include <SHpch.h>
// Primary Header
#include "SHCollisionID.h"
#include "SHCollisionKey.h"
// Project Headers
#include "Physics/Collision/SHCollider.h"
@ -24,7 +24,7 @@ namespace SHADE
/* Constructors & Destructor Definitions */
/*-----------------------------------------------------------------------------------*/
SHCollisionID::SHCollisionID() noexcept
SHCollisionKey::SHCollisionKey() noexcept
{
ids[ENTITY_A] = MAX_EID;
ids[ENTITY_B] = MAX_EID;
@ -32,13 +32,13 @@ namespace SHADE
ids[SHAPE_INDEX_B] = std::numeric_limits<uint32_t>::max();
}
SHCollisionID::SHCollisionID(const SHCollisionID& rhs) noexcept
SHCollisionKey::SHCollisionKey(const SHCollisionKey& rhs) noexcept
{
value[0] = rhs.value[0];
value[1] = rhs.value[1];
}
SHCollisionID::SHCollisionID(SHCollisionID&& rhs) noexcept
SHCollisionKey::SHCollisionKey(SHCollisionKey&& rhs) noexcept
{
value[0] = rhs.value[0];
value[1] = rhs.value[1];
@ -48,7 +48,7 @@ namespace SHADE
/* Operator Overload Definitions */
/*-----------------------------------------------------------------------------------*/
SHCollisionID& SHCollisionID::operator=(const SHCollisionID& rhs) noexcept
SHCollisionKey& SHCollisionKey::operator=(const SHCollisionKey& rhs) noexcept
{
if (this == &rhs)
return *this;
@ -59,7 +59,7 @@ namespace SHADE
return *this;
}
SHCollisionID& SHCollisionID::operator=(SHCollisionID&& rhs) noexcept
SHCollisionKey& SHCollisionKey::operator=(SHCollisionKey&& rhs) noexcept
{
value[0] = rhs.value[0];
value[1] = rhs.value[1];
@ -67,7 +67,7 @@ namespace SHADE
return *this;
}
bool SHCollisionID::operator==(const SHCollisionID& rhs) const
bool SHCollisionKey::operator==(const SHCollisionKey& rhs) const
{
// When checking for equal, check both ways.
// Exact Match (A, idxA, B, idxB)
@ -83,43 +83,43 @@ namespace SHADE
/* Getter Function Definitions */
/*-----------------------------------------------------------------------------------*/
EntityID SHCollisionID::GetEntityA() const noexcept
EntityID SHCollisionKey::GetEntityA() const noexcept
{
return ids[ENTITY_A];
}
EntityID SHCollisionID::GetEntityB() const noexcept
EntityID SHCollisionKey::GetEntityB() const noexcept
{
return ids[ENTITY_B];
}
uint32_t SHCollisionID::GetShapeIndexA() const noexcept
uint32_t SHCollisionKey::GetShapeIndexA() const noexcept
{
return ids[SHAPE_INDEX_A];
}
uint32_t SHCollisionID::GetShapeIndexB() const noexcept
uint32_t SHCollisionKey::GetShapeIndexB() const noexcept
{
return ids[SHAPE_INDEX_B];
}
const SHRigidBodyComponent* SHCollisionID::GetRigidBodyA() const noexcept
const SHRigidBodyComponent* SHCollisionKey::GetRigidBodyA() const noexcept
{
return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_A]);
}
const SHRigidBodyComponent* SHCollisionID::GetRigidBodyB() const noexcept
const SHRigidBodyComponent* SHCollisionKey::GetRigidBodyB() const noexcept
{
return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_B]);
}
const SHCollisionShape* SHCollisionID::GetCollisionShapeA() const noexcept
const SHCollisionShape* SHCollisionKey::GetCollisionShapeA() const noexcept
{
const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_A]);
return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[SHAPE_INDEX_A]);
}
const SHCollisionShape* SHCollisionID::GetCollisionShapeB() const noexcept
const SHCollisionShape* SHCollisionKey::GetCollisionShapeB() const noexcept
{
const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_B]);
return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[SHAPE_INDEX_B]);
@ -129,24 +129,38 @@ namespace SHADE
/* Setter Function Definitions */
/*-----------------------------------------------------------------------------------*/
void SHCollisionID::SetEntityA(EntityID entityID) noexcept
void SHCollisionKey::SetEntityA(EntityID entityID) noexcept
{
ids[ENTITY_A] = entityID;
}
void SHCollisionID::SetEntityB(EntityID entityID) noexcept
void SHCollisionKey::SetEntityB(EntityID entityID) noexcept
{
ids[ENTITY_B] = entityID;
}
void SHCollisionID::SetCollisionShapeA(uint32_t shapeIndexA) noexcept
void SHCollisionKey::SetCollisionShapeA(uint32_t shapeIndexA) noexcept
{
ids[SHAPE_INDEX_A] = shapeIndexA;
}
void SHCollisionID::SetCollisionShapeB(uint32_t shapeIndexB) noexcept
void SHCollisionKey::SetCollisionShapeB(uint32_t shapeIndexB) noexcept
{
ids[SHAPE_INDEX_B] = shapeIndexB;
}
/*-----------------------------------------------------------------------------------*/
/* Public Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
std::size_t SHCollisionKeyHash::operator()(const SHCollisionKey& id) const
{
static constexpr int NUM_IDS = ARRAYSIZE(id.ids);
// Hashable is not a word. Sue me.
auto hashablePtr = reinterpret_cast<std::basic_string_view<char32_t>::const_pointer>(id.ids);
return std::hash<std::u32string_view>{}(std::u32string_view(hashablePtr, NUM_IDS));
}
} // namespace SHADE

View File

@ -21,7 +21,7 @@ namespace SHADE
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
struct SHCollisionIDHash;
struct SHCollisionKeyHash;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
@ -29,37 +29,36 @@ namespace SHADE
/**
* @brief
* Encapsulates the information when two colliders intersect and do not have physical
* resolution.
* Encapsulates the information when two collision shapes intersect.
*/
class SH_API SHCollisionID
class SH_API SHCollisionKey
{
private:
/*---------------------------------------------------------------------------------*/
/* Friends */
/*---------------------------------------------------------------------------------*/
friend struct SHCollisionIDHash;
friend struct SHCollisionKeyHash;
public:
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
/*---------------------------------------------------------------------------------*/
SHCollisionID () noexcept;
SHCollisionID (const SHCollisionID& rhs) noexcept;
SHCollisionID (SHCollisionID&& rhs) noexcept;
SHCollisionKey () noexcept;
SHCollisionKey (const SHCollisionKey& rhs) noexcept;
SHCollisionKey (SHCollisionKey&& rhs) noexcept;
~SHCollisionID () noexcept = default;
~SHCollisionKey () noexcept = default;
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
SHCollisionID& operator= (const SHCollisionID& rhs) noexcept;
SHCollisionID& operator= (SHCollisionID&& rhs) noexcept;
SHCollisionKey& operator= (const SHCollisionKey& rhs) noexcept;
SHCollisionKey& operator= (SHCollisionKey&& rhs) noexcept;
bool operator==(const SHCollisionID& rhs) const;
bool operator==(const SHCollisionKey& rhs) const;
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
@ -103,19 +102,16 @@ namespace SHADE
/**
* @brief
* Encapsulates a functor to hash a CollisionID
* Encapsulates a functor to hash a CollisionKey
*/
struct SHCollisionIDHash
struct SHCollisionKeyHash
{
public:
/*---------------------------------------------------------------------------------*/
/* Member Functions */
/*---------------------------------------------------------------------------------*/
inline std::size_t operator()(const SHCollisionID& id) const
{
return std::hash<std::u32string_view>{}(std::u32string_view(reinterpret_cast<std::basic_string_view<char32_t>::const_pointer>(id.ids), 4));
}
std::size_t operator()(const SHCollisionKey& id) const;
};
} // namespace SHADE

View File

@ -13,7 +13,7 @@
// Project Headers
#include "Physics/Collision/CollisionShapes/SHCollisionShape.h"
#include "Physics/Collision/Contacts/SHManifold.h"
#include "Physics/Collision/Contacts/SHCollisionID.h"
#include "Physics/Collision/Contacts/SHCollisionKey.h"
namespace SHADE

View File

@ -12,7 +12,7 @@
// Project Headers
#include "Physics/Collision/Contacts/SHManifold.h"
#include "Physics/Collision/Contacts/SHCollisionID.h"
#include "Physics/Collision/Contacts/SHCollisionKey.h"
namespace SHADE
{

View File

@ -326,7 +326,7 @@ namespace SHADE
auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B);
// Build collision ID
SHCollisionID collisionKey;
SHCollisionKey collisionKey;
collisionKey.SetEntityA(ID_A);
collisionKey.SetEntityB(ID_B);
collisionKey.SetCollisionShapeA(INDEX_A);
@ -361,7 +361,7 @@ namespace SHADE
auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B);
// Build collision ID
SHCollisionID collisionKey;
SHCollisionKey collisionKey;
collisionKey.SetEntityA(ID_A);
collisionKey.SetEntityB(ID_B);
collisionKey.SetCollisionShapeA(INDEX_A);
@ -396,7 +396,7 @@ namespace SHADE
narrowphaseBatch.clear();
}
void SHPhysicsWorld::collideTriggers(const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept
void SHPhysicsWorld::collideTriggers(const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept
{
const auto* A = narrowphasePair.A;
const auto* B = narrowphasePair.B;
@ -419,7 +419,7 @@ namespace SHADE
trigger = triggers.erase(trigger);
}
void SHPhysicsWorld::collideManifolds(const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept
void SHPhysicsWorld::collideManifolds(const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept
{
auto* A = narrowphasePair.A;
auto* B = narrowphasePair.B;

View File

@ -113,9 +113,9 @@ namespace SHADE
// Collisions
using NarrowphaseBatch = std::unordered_map<SHCollisionID, NarrowphasePair, SHCollisionIDHash>;
using Manifolds = std::unordered_map<SHCollisionID, SHManifold, SHCollisionIDHash>;
using Triggers = std::unordered_map<SHCollisionID, SHCollisionState, SHCollisionIDHash>;
using NarrowphaseBatch = std::unordered_map<SHCollisionKey, NarrowphasePair, SHCollisionKeyHash>;
using Manifolds = std::unordered_map<SHCollisionKey, SHManifold, SHCollisionKeyHash>;
using Triggers = std::unordered_map<SHCollisionKey, SHCollisionState, SHCollisionKeyHash>;
@ -155,8 +155,8 @@ namespace SHADE
// Narrowphase helpers
void runNarrowphase () noexcept;
void collideTriggers (const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept;
void collideManifolds (const SHCollisionID& id, NarrowphasePair& narrowphasePair) noexcept;
void collideTriggers (const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept;
void collideManifolds (const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept;
void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept;
void updateEvents () noexcept;

View File

@ -40,10 +40,6 @@ namespace SHADE
eventFunctions[1] = { &SHPhysicsSystem::onComponentRemoved, SH_COMPONENT_REMOVED_EVENT };
eventFunctions[2] = { &SHPhysicsSystem::onSceneInit , SH_SCENE_INIT_POST };
eventFunctions[3] = { &SHPhysicsSystem::onSceneExit , SH_SCENE_EXIT_POST };
//#ifdef SHEDITOR
// eventFunctions[4] = { &SHPhysicsSystem::onEditorPlay , SH_EDITOR_ON_PLAY_EVENT };
//#endif
}
SHPhysicsSystem::~SHPhysicsSystem() noexcept
@ -178,6 +174,10 @@ namespace SHADE
// Create the physics world
physicsWorld = new SHPhysicsWorld;
// Immediately add all existing bodies and colliders to the world.
// Since we recreated the scene and the world, the initial data has been reset and determinism is guaranteed.
// Only if the current scene data changes, then so would the results of the simulation.
for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values)
{
if (PHYSICS_OBJECT.rigidBody)
@ -187,26 +187,6 @@ namespace SHADE
physicsWorld->AddCollider(PHYSICS_OBJECT.collider);
}
//#ifdef SHEDITOR
// // Link all entities with the world if editor is already playing.
// // This is for handling scene changes while the editor is active.
//
// const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
// if (!EDITOR || EDITOR->editorState != SHEditor::State::PLAY)
// return onSceneInitEvent.get()->handle;
// for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values)
// {
// if (PHYSICS_OBJECT.rigidBody)
// physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody);
// if (PHYSICS_OBJECT.collider)
// physicsWorld->AddCollider(PHYSICS_OBJECT.collider);
// }
//#endif
return onSceneInitEvent.get()->handle;
}
@ -262,7 +242,6 @@ namespace SHADE
physicsWorld->AddRigidBody(rigidBody);
}
}
if (IS_COLLIDER)
{
@ -323,24 +302,4 @@ namespace SHADE
return onComponentRemovedEvent.get()->handle;
}
#ifdef SHEDITOR
SHEventHandle SHPhysicsSystem::onEditorPlay(SHEventPtr onEditorPlayEvent)
{
// Add all physics components to the physics world
for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values)
{
// Add rigid body if it exists
if (PHYSICS_OBJECT.rigidBody)
physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody);
if (PHYSICS_OBJECT.collider)
physicsWorld->AddCollider(PHYSICS_OBJECT.collider);
}
return onEditorPlayEvent.get()->handle;
}
#endif
} // namespace SHADE

View File

@ -124,11 +124,7 @@ namespace SHADE
/* Data Members */
/*---------------------------------------------------------------------------------*/
//#ifdef SHEDITOR
// static constexpr int NUM_EVENT_FUNCTIONS = 5;
//#else
static constexpr int NUM_EVENT_FUNCTIONS = 4;
//#endif
// Event function container for cleanly registering to events
EventFunctionPair eventFunctions[NUM_EVENT_FUNCTIONS];
@ -152,14 +148,5 @@ namespace SHADE
SHEventHandle onComponentAdded (SHEventPtr onComponentAddedEvent);
SHEventHandle onComponentRemoved (SHEventPtr onComponentRemovedEvent);
#ifdef SHEDITOR
SHEventHandle onEditorPlay (SHEventPtr onEditorPlayEvent);
// We don't need an onEditorStop because on stop exits the scene, which is already handled above.
#endif
};
} // namespace SHADE