Implemented a custom physics engine #316
|
@ -55,6 +55,8 @@ namespace SHADE
|
|||
static constexpr float HALF_PI = PI * 0.5f;
|
||||
static constexpr float TWO_PI = 2.0f * PI;
|
||||
|
||||
static constexpr float EULER_CONSTANT = std::numbers::egamma_v<float>;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Static Function Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
|
|
@ -122,7 +122,7 @@ namespace SHADE
|
|||
/* Data Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
static constexpr float AABB_EXTENSION = 0.1f;
|
||||
static constexpr float AABB_EXTENSION = 0.2f;
|
||||
|
||||
// For quick access
|
||||
std::unordered_map<SHCollisionShapeID, int32_t, SHCollisionShapeIDHash> nodeMap;
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace SHADE
|
|||
friend class SHCollider;
|
||||
friend class SHColliderComponent;
|
||||
friend class SHCollisionShapeFactory;
|
||||
friend class SHPhysicsWorld;
|
||||
friend class SHCollisionSpace;
|
||||
|
||||
public:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace SHADE
|
|||
|
||||
SHCollider::SHCollider(EntityID eid, const SHTransform& worldTransform) noexcept
|
||||
: entityID { eid }
|
||||
, active { true }
|
||||
, debugDraw { false }
|
||||
, hasMoved { true }
|
||||
, rigidBody { nullptr }
|
||||
|
@ -39,6 +40,7 @@ namespace SHADE
|
|||
|
||||
SHCollider::SHCollider(const SHCollider& rhs) noexcept
|
||||
: entityID { rhs.entityID }
|
||||
, active { rhs.active }
|
||||
, debugDraw { rhs.debugDraw }
|
||||
, hasMoved { rhs.hasMoved }
|
||||
, rigidBody { rhs.rigidBody }
|
||||
|
@ -57,6 +59,7 @@ namespace SHADE
|
|||
|
||||
SHCollider::SHCollider(SHCollider&& rhs) noexcept
|
||||
: entityID { rhs.entityID }
|
||||
, active { rhs.active }
|
||||
, debugDraw { rhs.debugDraw }
|
||||
, hasMoved { rhs.hasMoved }
|
||||
, rigidBody { rhs.rigidBody }
|
||||
|
@ -101,6 +104,7 @@ namespace SHADE
|
|||
}
|
||||
|
||||
entityID = rhs.entityID;
|
||||
active = rhs.active;
|
||||
debugDraw = rhs.debugDraw;
|
||||
hasMoved = rhs.hasMoved;
|
||||
rigidBody = rhs.rigidBody;
|
||||
|
@ -122,6 +126,7 @@ namespace SHADE
|
|||
}
|
||||
|
||||
entityID = rhs.entityID;
|
||||
active = rhs.active;
|
||||
debugDraw = rhs.debugDraw;
|
||||
hasMoved = rhs.hasMoved;
|
||||
rigidBody = rhs.rigidBody;
|
||||
|
@ -138,6 +143,16 @@ namespace SHADE
|
|||
/* Getter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
EntityID SHCollider::GetEntityID() const noexcept
|
||||
{
|
||||
return entityID;
|
||||
}
|
||||
|
||||
bool SHCollider::IsActive() const noexcept
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
bool SHCollider::GetDebugDrawState() const noexcept
|
||||
{
|
||||
return debugDraw;
|
||||
|
@ -182,6 +197,25 @@ namespace SHADE
|
|||
/* Setter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHCollider::SetIsActive(bool state) noexcept
|
||||
{
|
||||
if (active == state)
|
||||
return;
|
||||
|
||||
active = state;
|
||||
|
||||
if (!broadphase)
|
||||
return;
|
||||
|
||||
for (auto* shape : shapes)
|
||||
{
|
||||
if (active) // Previously inactive
|
||||
broadphase->Insert(shape->id, shape->ComputeAABB());
|
||||
else // Previously active
|
||||
broadphase->Remove(shape->id);
|
||||
}
|
||||
}
|
||||
|
||||
void SHCollider::SetDebugDrawState(bool state) noexcept
|
||||
{
|
||||
debugDraw = state;
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace SHADE
|
|||
/* Friends */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
friend class SHPhysicsWorld;
|
||||
friend class SHCollisionSpace;
|
||||
|
||||
public:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -79,6 +79,8 @@ namespace SHADE
|
|||
/* Getter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] EntityID GetEntityID () const noexcept;
|
||||
[[nodiscard]] bool IsActive () const noexcept;
|
||||
[[nodiscard]] bool GetDebugDrawState () const noexcept;
|
||||
|
||||
[[nodiscard]] const SHTransform& GetTransform () const noexcept;
|
||||
|
@ -93,6 +95,7 @@ namespace SHADE
|
|||
/* Setter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
void SetIsActive (bool state) noexcept;
|
||||
void SetDebugDrawState (bool state) noexcept;
|
||||
|
||||
void SetRigidBody (SHRigidBody* rb) noexcept;
|
||||
|
@ -157,6 +160,7 @@ namespace SHADE
|
|||
|
||||
EntityID entityID;
|
||||
|
||||
bool active;
|
||||
bool debugDraw;
|
||||
bool hasMoved;
|
||||
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
/****************************************************************************************
|
||||
* \file SHCollisionInfo.cpp
|
||||
* \author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
* \brief Implementation for Collision Info.
|
||||
*
|
||||
* \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 "SHCollisionInfo.h"
|
||||
|
||||
// Project Headers
|
||||
#include "Physics/Collision/SHCollider.h"
|
||||
#include "Physics/Interface/SHColliderComponent.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Constructors & Destructor Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHCollisionInfo::SHCollisionInfo() noexcept
|
||||
: collisionState { State::INVALID }
|
||||
{
|
||||
ids[ENTITY_A] = MAX_EID;
|
||||
ids[ENTITY_B] = MAX_EID;
|
||||
ids[COLLIDER_A] = std::numeric_limits<uint32_t>::max();
|
||||
ids[COLLIDER_B] = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
SHCollisionInfo::SHCollisionInfo(EntityID entityA, EntityID entityB) noexcept
|
||||
: collisionState { State::INVALID }
|
||||
{
|
||||
ids[ENTITY_A] = entityA;
|
||||
ids[ENTITY_B] = entityB;
|
||||
ids[COLLIDER_A] = std::numeric_limits<uint32_t>::max();
|
||||
ids[COLLIDER_B] = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Operator Overload Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
bool SHCollisionInfo::operator==(const SHCollisionInfo& rhs) const noexcept
|
||||
{
|
||||
return value[0] == rhs.value[0] && value[1] == rhs.value[1];
|
||||
}
|
||||
|
||||
bool SHCollisionInfo::operator!=(const SHCollisionInfo& rhs) const noexcept
|
||||
{
|
||||
return value[0] != rhs.value[0] || value[1] != rhs.value[1];
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Getter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
EntityID SHCollisionInfo::GetEntityA() const noexcept
|
||||
{
|
||||
return ids[ENTITY_A];
|
||||
}
|
||||
|
||||
EntityID SHCollisionInfo::GetEntityB() const noexcept
|
||||
{
|
||||
return ids[ENTITY_B];
|
||||
}
|
||||
|
||||
const SHRigidBodyComponent* SHCollisionInfo::GetRigidBodyA() const noexcept
|
||||
{
|
||||
return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_A]);
|
||||
}
|
||||
|
||||
const SHRigidBodyComponent* SHCollisionInfo::GetRigidBodyB() const noexcept
|
||||
{
|
||||
return SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ids[ENTITY_B]);
|
||||
}
|
||||
|
||||
const SHCollisionShape* SHCollisionInfo::GetColliderA() const noexcept
|
||||
{
|
||||
const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_A]);
|
||||
return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[COLLIDER_A]);
|
||||
}
|
||||
|
||||
const SHCollisionShape* SHCollisionInfo::GetColliderB() const noexcept
|
||||
{
|
||||
const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent<SHColliderComponent>(ids[ENTITY_B]);
|
||||
return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[COLLIDER_B]);
|
||||
}
|
||||
|
||||
SHCollisionInfo::State SHCollisionInfo::GetCollisionState() const noexcept
|
||||
{
|
||||
return collisionState;
|
||||
}
|
||||
|
||||
} // namespace SHADE
|
|
@ -1,102 +0,0 @@
|
|||
/****************************************************************************************
|
||||
* \file SHCollisionInfo.h
|
||||
* \author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
* \brief Interface for Collision Information for Collision & Triggers.
|
||||
*
|
||||
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
|
||||
* disclosure of this file or its contents without the prior written consent
|
||||
* of DigiPen Institute of Technology is prohibited.
|
||||
****************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Project Headers
|
||||
#include "Physics/Interface/SHColliderComponent.h"
|
||||
#include "Physics/Interface/SHRigidBodyComponent.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
class SH_API SHCollisionInfo
|
||||
{
|
||||
private:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Friends */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
friend class SHCollisionListener;
|
||||
|
||||
public:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
enum class State
|
||||
{
|
||||
ENTER
|
||||
, STAY
|
||||
, EXIT
|
||||
|
||||
, TOTAL
|
||||
, INVALID = -1
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Constructors & Destructor */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
SHCollisionInfo () noexcept;
|
||||
SHCollisionInfo (EntityID entityA, EntityID entityB) noexcept;
|
||||
|
||||
|
||||
SHCollisionInfo (const SHCollisionInfo& rhs) = default;
|
||||
SHCollisionInfo (SHCollisionInfo&& rhs) = default;
|
||||
~SHCollisionInfo () = default;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Operator Overloads */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
bool operator== (const SHCollisionInfo& rhs) const noexcept;
|
||||
bool operator!= (const SHCollisionInfo& rhs) const noexcept;
|
||||
|
||||
SHCollisionInfo& operator= (const SHCollisionInfo& rhs) = default;
|
||||
SHCollisionInfo& operator= (SHCollisionInfo&& rhs) = default;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Getter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] EntityID GetEntityA () const noexcept;
|
||||
[[nodiscard]] EntityID GetEntityB () const noexcept;
|
||||
[[nodiscard]] const SHRigidBodyComponent* GetRigidBodyA () const noexcept;
|
||||
[[nodiscard]] const SHRigidBodyComponent* GetRigidBodyB () const noexcept;
|
||||
[[nodiscard]] const SHCollisionShape* GetColliderA () const noexcept;
|
||||
[[nodiscard]] const SHCollisionShape* GetColliderB () const noexcept;
|
||||
[[nodiscard]] State GetCollisionState () const noexcept;
|
||||
|
||||
private:
|
||||
|
||||
static constexpr uint32_t ENTITY_A = 0;
|
||||
static constexpr uint32_t ENTITY_B = 1;
|
||||
static constexpr uint32_t COLLIDER_A = 2;
|
||||
static constexpr uint32_t COLLIDER_B = 3;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Data Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
union
|
||||
{
|
||||
uint64_t value[2]; // EntityValue, ColliderIndexValue
|
||||
uint32_t ids [4]; // EntityA, EntityB, ColliderIndexA, ColliderIndexB
|
||||
};
|
||||
|
||||
State collisionState;
|
||||
};
|
||||
|
||||
} // namespace SHADE
|
|
@ -0,0 +1,223 @@
|
|||
/****************************************************************************************
|
||||
* \file SHCollisionSpace.cpp
|
||||
* \author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
* \brief Implementation for a Collision Space that handles collision detetction.
|
||||
*
|
||||
* \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 "SHCollisionSpace.h"
|
||||
|
||||
#include "Narrowphase/SHCollisionDispatch.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Getter Functions Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
const SHAABBTree::AABBs& SHCollisionSpace::GetBroadphaseAABBs() const noexcept
|
||||
{
|
||||
return broadphase.GetAABBs();
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Setter Functions Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHCollisionSpace::SetContactManager(SHContactManager* _contactManager) noexcept
|
||||
{
|
||||
contactManager = _contactManager;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Public Member Functions Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHCollisionSpace::AddCollider(SHCollider* collider) noexcept
|
||||
{
|
||||
const bool INSERTED = colliders.emplace(collider->entityID, collider).second;
|
||||
if (!INSERTED)
|
||||
{
|
||||
SHLOG_WARNING_D("Attempting to add duplicate collider {} to the Physics World!", collider->entityID)
|
||||
return;
|
||||
}
|
||||
|
||||
collider->broadphase = &broadphase;
|
||||
|
||||
// Add all existing shapes to the broadphase
|
||||
for (const auto* shape : collider->shapes)
|
||||
broadphase.Insert(shape->id, shape->ComputeAABB());
|
||||
}
|
||||
|
||||
void SHCollisionSpace::RemoveCollider(SHCollider* collider) noexcept
|
||||
{
|
||||
colliders.erase(collider->entityID);
|
||||
|
||||
const uint32_t NUM_SHAPES = static_cast<uint32_t>(collider->shapes.size());
|
||||
if (NUM_SHAPES == 0)
|
||||
return;
|
||||
|
||||
for (uint32_t i = 0; i < NUM_SHAPES; ++i)
|
||||
broadphase.Remove(collider->shapes[i]->id);
|
||||
|
||||
if (contactManager)
|
||||
{
|
||||
contactManager->RemoveInvalidatedTrigger(collider->entityID);
|
||||
contactManager->RemoveInvalidatedManifold(collider->entityID);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* Get collider's rigid body
|
||||
* Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep
|
||||
*/
|
||||
}
|
||||
|
||||
void SHCollisionSpace::UpdateBroadphase() noexcept
|
||||
{
|
||||
// Update any colliders that have moved
|
||||
for (auto& collider : colliders | std::views::values)
|
||||
{
|
||||
const bool IS_ACTIVE = collider->active;
|
||||
const bool HAS_MOVED = collider->hasMoved;
|
||||
|
||||
if (!IS_ACTIVE || !HAS_MOVED)
|
||||
continue;
|
||||
|
||||
// Clear hasMoved flag here
|
||||
collider->hasMoved = false;
|
||||
|
||||
// Update moved shapes in broadphase
|
||||
for (auto* shape : collider->shapes)
|
||||
broadphase.Update(shape->id, shape->ComputeAABB());
|
||||
}
|
||||
}
|
||||
|
||||
void SHCollisionSpace::DetectCollisions() noexcept
|
||||
{
|
||||
/*
|
||||
* Broad-phase
|
||||
*/
|
||||
|
||||
// Broadphase Queries: Kinematic Triggers, Awake Dynamic Bodies & Dynamic Triggers
|
||||
for (auto& collider : colliders | std::views::values)
|
||||
{
|
||||
// Colliders without bodies are considered to be static bodies
|
||||
// This is specific to this engine because of Unity's stupid convention.
|
||||
const bool IS_IMPLICIT_STATIC = !collider->rigidBody;
|
||||
const bool IS_EXPLICIT_STATIC = collider->rigidBody->GetType() == SHRigidBody::Type::STATIC;
|
||||
const bool IS_ACTIVE = collider->active;
|
||||
|
||||
// Skip inactive colliders
|
||||
if (!IS_ACTIVE || IS_IMPLICIT_STATIC || IS_EXPLICIT_STATIC)
|
||||
continue;
|
||||
|
||||
// All remaining are kinematic or dynamic
|
||||
// Iterate through shapes: if kinematic / dynamic trigger, else if dynamic & awake
|
||||
// Results are loaded into the narrowphase batch
|
||||
broadphaseQuery(collider->rigidBody->GetType(), collider);
|
||||
}
|
||||
|
||||
/*
|
||||
* Narrow-phase
|
||||
*/
|
||||
|
||||
// If no potential collisions, we can skip the entire narrow phase. No further updates necessary.
|
||||
// All contact / trigger states persist in this step.
|
||||
if (narrowphaseBatch.empty())
|
||||
return;
|
||||
|
||||
// All narrowphase IDs are unique, there should be no duplicate collision checks.
|
||||
// This applies both ways: A -> B and B -> A.
|
||||
for (auto& [key, narrowphasePair] : narrowphaseBatch)
|
||||
{
|
||||
const bool IS_A_TRIGGER = narrowphasePair.A->IsTrigger();
|
||||
const bool IS_B_TRIGGER = narrowphasePair.B->IsTrigger();
|
||||
|
||||
if (IS_A_TRIGGER || IS_B_TRIGGER)
|
||||
collideTriggers(key, narrowphasePair);
|
||||
else
|
||||
collideManifolds(key, narrowphasePair);
|
||||
}
|
||||
|
||||
// Clear every frame
|
||||
narrowphaseBatch.clear();
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Private Member Functions Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHCollisionSpace::broadphaseQuery(SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept
|
||||
{
|
||||
for (auto* shape : collider->shapes)
|
||||
{
|
||||
// For kinematic shapes, we only query triggers against everything else
|
||||
if (rigidBodyType == SHRigidBody::Type::KINEMATIC && !shape->IsTrigger())
|
||||
continue;
|
||||
|
||||
auto& potentialCollisions = broadphase.Query(shape->id, shape->ComputeAABB());
|
||||
|
||||
// Build narrow-phase pairs
|
||||
auto* shapeA = shape;
|
||||
|
||||
const EntityID ID_A = shape->id.GetEntityID();
|
||||
const uint32_t INDEX_A = shape->id.GetShapeIndex();
|
||||
|
||||
for (auto& id : potentialCollisions)
|
||||
{
|
||||
// Get corresponding shape
|
||||
const EntityID ID_B = id.GetEntityID();
|
||||
const uint32_t INDEX_B = id.GetShapeIndex();
|
||||
|
||||
auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B);
|
||||
|
||||
// Build collision ID
|
||||
SHCollisionKey collisionKey;
|
||||
collisionKey.SetEntityA(ID_A);
|
||||
collisionKey.SetEntityB(ID_B);
|
||||
collisionKey.SetCollisionShapeA(INDEX_A);
|
||||
collisionKey.SetCollisionShapeB(INDEX_B);
|
||||
|
||||
// Check if it already exists. If it doesn't, put into batch.
|
||||
// The overloaded equality operator ensures no duplicate collision tests are performed.
|
||||
auto narrowphasePair = narrowphaseBatch.find(collisionKey);
|
||||
if (narrowphasePair == narrowphaseBatch.end())
|
||||
narrowphaseBatch.emplace(collisionKey, NarrowphasePair{ shapeA, shapeB });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SHCollisionSpace::collideTriggers(const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept
|
||||
{
|
||||
const auto* A = narrowphasePair.A;
|
||||
const auto* B = narrowphasePair.B;
|
||||
|
||||
const bool COLLIDING = SHCollisionDispatcher::Collide(*A, *B);
|
||||
|
||||
// Send results to contact manager
|
||||
if (contactManager)
|
||||
contactManager->AddTrigger(COLLIDING, key);
|
||||
}
|
||||
|
||||
void SHCollisionSpace::collideManifolds(const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept
|
||||
{
|
||||
auto* A = narrowphasePair.A;
|
||||
auto* B = narrowphasePair.B;
|
||||
|
||||
SHManifold newManifold { .A = A, .B = B };
|
||||
const bool COLLIDING = SHCollisionDispatcher::Collide(newManifold, *A, *B);
|
||||
|
||||
// Send results to contact manager
|
||||
if (contactManager)
|
||||
contactManager->AddManifold(COLLIDING, key, newManifold);
|
||||
}
|
||||
} // namespace SHADE
|
|
@ -0,0 +1,131 @@
|
|||
/****************************************************************************************
|
||||
* \file SHCollisionSpace.h
|
||||
* \author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
* \brief Interface for a Collision Space that handles collision detetction.
|
||||
* This is to separate the logic between dynamics and collision detection,
|
||||
* but the collision space does send information to the contact manager
|
||||
* for dynamic resolution and collision state reporting.
|
||||
*
|
||||
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
|
||||
* disclosure of this file or its contents without the prior written consent
|
||||
* of DigiPen Institute of Technology is prohibited.
|
||||
****************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Project Headers
|
||||
#include "Broadphase/SHDynamicAABBTree.h"
|
||||
#include "Contacts/SHCollisionEvents.h"
|
||||
#include "Physics/Dynamics/SHContactManager.h"
|
||||
#include "SHCollider.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Allows collision detection to be performed with the use of colliders & collision shapes.
|
||||
* The space will generate manifold data for resolution when needed.
|
||||
*/
|
||||
class SH_API SHCollisionSpace
|
||||
{
|
||||
public:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Constructors & Destructor */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
SHCollisionSpace () noexcept = default;
|
||||
~SHCollisionSpace () noexcept = default;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Getter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
const SHAABBTree::AABBs& GetBroadphaseAABBs () const noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Setter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
void SetContactManager(SHContactManager* contactManager) noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Member Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Adds a collider to the collision space for it to be tested for collision with
|
||||
* other colliders.
|
||||
* @param collider
|
||||
* A collider to add. Duplicates will be ignored.
|
||||
*/
|
||||
void AddCollider (SHCollider* collider) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Removes a collider from the collision space. This will prevent any collisions
|
||||
* being detected between it and other colliders unless manually tested.
|
||||
* @param collider
|
||||
* A collider to remove. If a reference to it doesn't exist, it will be ignored.
|
||||
*/
|
||||
void RemoveCollider (SHCollider* collider) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Invoke this method to update the broadphase of colliders that have been moved since
|
||||
* the last frame.
|
||||
*/
|
||||
void UpdateBroadphase () noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Detects collisions between all colliders. Results are sent to the attached contact
|
||||
* manager for resolution.
|
||||
*/
|
||||
void DetectCollisions () noexcept;
|
||||
|
||||
private:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
struct NarrowphasePair
|
||||
{
|
||||
SHCollisionShape* A = nullptr;
|
||||
SHCollisionShape* B = nullptr;
|
||||
};
|
||||
|
||||
using Colliders = std::unordered_map<EntityID, SHCollider*>;
|
||||
using NarrowphaseBatch = std::unordered_map<SHCollisionKey, NarrowphasePair, SHCollisionKeyHash>;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Data Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
SHContactManager* contactManager = nullptr;
|
||||
|
||||
Colliders colliders;
|
||||
NarrowphaseBatch narrowphaseBatch;
|
||||
|
||||
SHAABBTree broadphase;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Member Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
// Broadphase helpers
|
||||
|
||||
void broadphaseQuery (SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept;
|
||||
|
||||
// Narrowphase helpers
|
||||
|
||||
void collideTriggers (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept;
|
||||
void collideManifolds (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept;
|
||||
|
||||
};
|
||||
|
||||
} // namespace SHADE
|
|
@ -0,0 +1,173 @@
|
|||
/****************************************************************************************
|
||||
* \file SHContactManager.h
|
||||
* \author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
* \brief Implementation for a Contact Manager that stores collision information and
|
||||
* resolves contact constraints.
|
||||
*
|
||||
* \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 "SHContactManager.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Getter Functions Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
const SHContactManager::TriggerEvents& SHContactManager::GetTriggerEvents() const noexcept
|
||||
{
|
||||
static TriggerEvents triggerEvents;
|
||||
|
||||
triggerEvents.clear();
|
||||
|
||||
for (auto& [id, state] : triggers)
|
||||
triggerEvents.emplace_back(SHTriggerEvent{ id, state });
|
||||
|
||||
return triggerEvents;
|
||||
}
|
||||
|
||||
const SHContactManager::CollisionEvents& SHContactManager::GetCollisionEvents() const noexcept
|
||||
{
|
||||
static CollisionEvents collisionEvents;
|
||||
|
||||
collisionEvents.clear();
|
||||
|
||||
for (auto& [id, manifold] : manifolds)
|
||||
{
|
||||
SHCollisionEvent collisionEvent
|
||||
{
|
||||
.info = id
|
||||
, .state = manifold.state
|
||||
, .normal = manifold.normal
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < manifold.numContacts; ++i)
|
||||
collisionEvent.contactPoints[i] = manifold.contacts[i].position;
|
||||
|
||||
collisionEvents.emplace_back(collisionEvent);
|
||||
}
|
||||
|
||||
return collisionEvents;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Public Member Functions Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHContactManager::Update() noexcept
|
||||
{
|
||||
// Clear expired or invalid collisions
|
||||
for (auto manifold = manifolds.begin(); manifold != manifolds.end();)
|
||||
{
|
||||
const auto COLLISION_STATE = manifold->second.state;
|
||||
|
||||
const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT;
|
||||
const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID;
|
||||
|
||||
if (IS_EXIT || IS_INVALID)
|
||||
manifold = manifolds.erase(manifold);
|
||||
else
|
||||
++manifold;
|
||||
}
|
||||
|
||||
// Clear expired or invalid triggers
|
||||
for (auto trigger = triggers.begin(); trigger != triggers.end();)
|
||||
{
|
||||
const auto COLLISION_STATE = trigger->second;
|
||||
|
||||
const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT;
|
||||
const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID;
|
||||
|
||||
if (IS_EXIT || IS_INVALID)
|
||||
trigger = triggers.erase(trigger);
|
||||
else
|
||||
++trigger;
|
||||
}
|
||||
}
|
||||
|
||||
void SHContactManager::AddTrigger(bool isColliding, const SHCollisionKey& key) noexcept
|
||||
{
|
||||
auto trigger = triggers.find(key);
|
||||
|
||||
// If id not found, emplace new object.
|
||||
// New object is in the invalid state
|
||||
if (trigger == triggers.end())
|
||||
trigger = triggers.emplace(key, SHCollisionState::INVALID).first;
|
||||
|
||||
SHCollisionState& state = trigger->second;
|
||||
updateCollisionState(isColliding, state);
|
||||
|
||||
// If it was a false positive, remove the manifold immediately.
|
||||
// Remove using iterator as it is on average faster.
|
||||
if (state == SHCollisionState::INVALID)
|
||||
trigger = triggers.erase(trigger);
|
||||
}
|
||||
|
||||
void SHContactManager::AddManifold(bool isColliding, const SHCollisionKey& key, const SHManifold& newManifold) noexcept
|
||||
{
|
||||
auto manifold = manifolds.find(key);
|
||||
|
||||
// If id not found, emplace new manifold
|
||||
if (manifold == manifolds.end())
|
||||
manifold = manifolds.emplace(key, newManifold).first;
|
||||
else
|
||||
{
|
||||
// TODO: Update existing manifolds with new data
|
||||
}
|
||||
|
||||
SHCollisionState& state = manifold->second.state;
|
||||
updateCollisionState(isColliding, state);
|
||||
|
||||
// If it was a false positive, remove the manifold immediately.
|
||||
// Remove using iterator as it is on average faster.
|
||||
if (state == SHCollisionState::INVALID)
|
||||
manifold = manifolds.erase(manifold);
|
||||
}
|
||||
|
||||
void SHContactManager::RemoveInvalidatedTrigger(EntityID eid) noexcept
|
||||
{
|
||||
remove(triggers, eid);
|
||||
}
|
||||
|
||||
void SHContactManager::RemoveInvalidatedTrigger(EntityID eid, uint32_t shapeIndex) noexcept
|
||||
{
|
||||
remove(triggers, eid, shapeIndex);
|
||||
}
|
||||
|
||||
void SHContactManager::RemoveInvalidatedManifold(EntityID eid) noexcept
|
||||
{
|
||||
remove(manifolds, eid);
|
||||
}
|
||||
|
||||
void SHContactManager::RemoveInvalidatedManifold(EntityID eid, uint32_t shapeIndex) noexcept
|
||||
{
|
||||
remove(manifolds, eid, shapeIndex);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Private Member Functions Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHContactManager::updateCollisionState(bool isColliding, SHCollisionState& state) noexcept
|
||||
{
|
||||
if (isColliding)
|
||||
{
|
||||
// New states start at invalid. In the first frame of collision, move to enter.
|
||||
// If it already in enter, move to stay
|
||||
state = state == SHCollisionState::INVALID ? SHCollisionState::ENTER : SHCollisionState::STAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
// New states start at invalid. In false positive, remain unchanged.
|
||||
// If previously colliding, move to exit.
|
||||
state = state == SHCollisionState::INVALID ? SHCollisionState::INVALID : SHCollisionState::EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SHADE
|
|
@ -0,0 +1,103 @@
|
|||
/****************************************************************************************
|
||||
* \file SHContactManager.h
|
||||
* \author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
* \brief Interface for a Contact Manager that stores collision information and
|
||||
* resolves contact constraints.
|
||||
*
|
||||
* \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>
|
||||
|
||||
// Project Headers
|
||||
#include "Physics/Collision/Contacts/SHCollisionEvents.h"
|
||||
#include "Physics/Collision/Contacts/SHCollisionKey.h"
|
||||
#include "Physics/Collision/Contacts/SHManifold.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
class SH_API SHContactManager
|
||||
{
|
||||
public:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
using TriggerEvents = std::vector<SHTriggerEvent>;
|
||||
using CollisionEvents = std::vector<SHCollisionEvent>;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Constructors & Destructor */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
SHContactManager () noexcept = default;
|
||||
~SHContactManager () noexcept = default;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Operator Overloads */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
const TriggerEvents& GetTriggerEvents () const noexcept;
|
||||
const CollisionEvents& GetCollisionEvents () const noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Member Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Removes any invalidated contacts and triggers.
|
||||
* @return
|
||||
*/
|
||||
void Update () noexcept;
|
||||
|
||||
void AddTrigger (bool isColliding, const SHCollisionKey& key) noexcept;
|
||||
void AddManifold (bool isColliding, const SHCollisionKey& key, const SHManifold& newManifold) noexcept;
|
||||
|
||||
void RemoveInvalidatedTrigger (EntityID eid) noexcept;
|
||||
void RemoveInvalidatedTrigger (EntityID eid, uint32_t shapeIndex) noexcept;
|
||||
void RemoveInvalidatedManifold (EntityID eid) noexcept;
|
||||
void RemoveInvalidatedManifold (EntityID eid, uint32_t shapeIndex) noexcept;
|
||||
|
||||
private:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
using Manifolds = std::unordered_map<SHCollisionKey, SHManifold, SHCollisionKeyHash>;
|
||||
using Triggers = std::unordered_map<SHCollisionKey, SHCollisionState, SHCollisionKeyHash>;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Data Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
Manifolds manifolds;
|
||||
Triggers triggers;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Member Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept;
|
||||
|
||||
// Removal Helpers
|
||||
|
||||
template <typename T>
|
||||
void remove (std::unordered_map<SHCollisionKey, T, SHCollisionKeyHash>& container, EntityID eid);
|
||||
template <typename T>
|
||||
void remove (std::unordered_map<SHCollisionKey, T, SHCollisionKeyHash>& container, EntityID eid, uint32_t shapeIndex);
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace SHADE
|
||||
|
||||
#include "SHContactManager.hpp"
|
|
@ -0,0 +1,61 @@
|
|||
/****************************************************************************************
|
||||
* \file SHContactManager.hpp
|
||||
* \author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
* \brief Implementation for templated methods of the Contact 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
|
||||
|
||||
// Primary Header
|
||||
#include "SHContactManager.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Private Member Functions Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
template <typename T>
|
||||
void SHContactManager::remove(std::unordered_map<SHCollisionKey, T, SHCollisionKeyHash>& container, EntityID eid)
|
||||
{
|
||||
if (container.empty())
|
||||
return;
|
||||
|
||||
for (auto invalidated = container.begin(); invalidated != container.end();)
|
||||
{
|
||||
const auto& ID = invalidated->first;
|
||||
|
||||
const bool MATCHES_A = ID.GetEntityA() == eid;
|
||||
const bool MATCHES_B = ID.GetEntityB() == eid;
|
||||
|
||||
if (MATCHES_A || MATCHES_B)
|
||||
invalidated = container.erase(invalidated);
|
||||
else
|
||||
++invalidated;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void SHContactManager::remove(std::unordered_map<SHCollisionKey, T, SHCollisionKeyHash>& container, EntityID eid, uint32_t shapeIndex)
|
||||
{
|
||||
if (container.empty())
|
||||
return;
|
||||
|
||||
for (auto invalidated = container.begin(); invalidated != container.end();)
|
||||
{
|
||||
const auto& ID = invalidated->first;
|
||||
|
||||
const bool MATCHES_A = ID.GetEntityA() == eid && ID.GetShapeIndexA() == shapeIndex;
|
||||
const bool MATCHES_B = ID.GetEntityB() == eid && ID.GetShapeIndexB() == shapeIndex;
|
||||
|
||||
if (MATCHES_A || MATCHES_B)
|
||||
invalidated = container.erase(invalidated);
|
||||
else
|
||||
++invalidated;
|
||||
}
|
||||
}
|
||||
} // namespace SHADE
|
|
@ -13,11 +13,6 @@
|
|||
// Primary Header
|
||||
#include "SHPhysicsWorld.h"
|
||||
|
||||
// Project Headers
|
||||
#include "Physics/Collision/Narrowphase/SHCollision.h"
|
||||
#include "Physics/Collision/Narrowphase/SHCollisionDispatch.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -26,58 +21,38 @@ namespace SHADE
|
|||
|
||||
SHPhysicsWorld::SHPhysicsWorld(const WorldSettings& worldSettings) noexcept
|
||||
: settings { worldSettings }
|
||||
, collisionSpace { nullptr }
|
||||
{
|
||||
SHLOG_INFO_D("Creating Physics World")
|
||||
}
|
||||
|
||||
SHPhysicsWorld::~SHPhysicsWorld() noexcept
|
||||
{
|
||||
|
||||
collisionSpace = nullptr;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Getter Functions Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
const SHAABBTree::AABBs& SHPhysicsWorld::GetBroadphaseAABBs() const noexcept
|
||||
const SHContactManager::TriggerEvents& SHPhysicsWorld::GetTriggerEvents() const noexcept
|
||||
{
|
||||
return broadphase.GetAABBs();
|
||||
return contactManager.GetTriggerEvents();
|
||||
}
|
||||
|
||||
const SHPhysicsWorld::TriggerEvents& SHPhysicsWorld::GetTriggerEvents() const noexcept
|
||||
const SHContactManager::CollisionEvents& SHPhysicsWorld::GetCollisionEvents() const noexcept
|
||||
{
|
||||
static TriggerEvents triggerEvents;
|
||||
|
||||
triggerEvents.clear();
|
||||
|
||||
for (auto& [id, state] : triggers)
|
||||
triggerEvents.emplace_back(SHTriggerEvent{ id, state });
|
||||
|
||||
return triggerEvents;
|
||||
return contactManager.GetCollisionEvents();
|
||||
}
|
||||
|
||||
const SHPhysicsWorld::CollisionEvents& SHPhysicsWorld::GetCollisionEvents() const noexcept
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Setter Functions Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHPhysicsWorld::SetCollisionSpace(SHCollisionSpace* _collisionSpace) noexcept
|
||||
{
|
||||
static CollisionEvents collisionEvents;
|
||||
|
||||
collisionEvents.clear();
|
||||
|
||||
for (auto& [id, manifold] : manifolds)
|
||||
{
|
||||
SHCollisionEvent collisionEvent
|
||||
{
|
||||
.info = id
|
||||
, .state = manifold.state
|
||||
, .normal = manifold.normal
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < manifold.numContacts; ++i)
|
||||
collisionEvent.contactPoints[i] = manifold.contacts[i].position;
|
||||
|
||||
collisionEvents.emplace_back(collisionEvent);
|
||||
}
|
||||
|
||||
return collisionEvents;
|
||||
collisionSpace = _collisionSpace;
|
||||
_collisionSpace->SetContactManager(&contactManager);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -97,94 +72,55 @@ namespace SHADE
|
|||
{
|
||||
rigidBodies.erase(rigidBody->entityID);
|
||||
|
||||
// Attempt to remove any invalidated manifolds
|
||||
if (manifolds.empty())
|
||||
return;
|
||||
|
||||
for (auto manifoldPair = manifolds.begin(); manifoldPair != manifolds.end();)
|
||||
{
|
||||
const auto& ID = manifoldPair->first;
|
||||
|
||||
const bool MATCHES_A = ID.GetEntityA() == rigidBody->entityID;
|
||||
const bool MATCHES_B = ID.GetEntityB() == rigidBody->entityID;
|
||||
|
||||
if (MATCHES_A || MATCHES_B)
|
||||
manifoldPair = manifolds.erase(manifoldPair);
|
||||
else
|
||||
++manifoldPair;
|
||||
}
|
||||
// Contact manager to remove invalidated contacts
|
||||
contactManager.RemoveInvalidatedManifold(rigidBody->entityID);
|
||||
|
||||
// TODO: Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::AddCollider(SHCollider* collider) noexcept
|
||||
{
|
||||
const bool INSERTED = colliders.emplace(collider->entityID, collider).second;
|
||||
if (!INSERTED)
|
||||
{
|
||||
SHLOG_WARNING_D("Attempting to add duplicate collider {} to the Physics World!", collider->entityID)
|
||||
return;
|
||||
}
|
||||
|
||||
collider->broadphase = &broadphase;
|
||||
|
||||
// Add all existing shapes to the broadphase
|
||||
for (const auto* shape : collider->shapes)
|
||||
broadphase.Insert(shape->id, shape->ComputeAABB());
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::RemoveCollider(SHCollider* collider) noexcept
|
||||
{
|
||||
colliders.erase(collider->entityID);
|
||||
|
||||
const uint32_t NUM_SHAPES = static_cast<uint32_t>(collider->shapes.size());
|
||||
if (NUM_SHAPES == 0)
|
||||
return;
|
||||
|
||||
for (uint32_t i = 0; i < NUM_SHAPES; ++i)
|
||||
{
|
||||
const SHCollisionShape* SHAPE = collider->shapes[i];
|
||||
|
||||
broadphase.Remove(SHAPE->id);
|
||||
|
||||
if (SHAPE->IsTrigger())
|
||||
removeInvalidatedTrigger(collider->entityID, i);
|
||||
else
|
||||
removeInvalidatedManifold(collider->entityID, i);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* Get collider's rigid body
|
||||
* Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep
|
||||
*/
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::UpdateBroadphase(SHCollider* collider) noexcept
|
||||
{
|
||||
auto& shapes = collider->GetCollisionShapes();
|
||||
for (auto* shape : shapes)
|
||||
broadphase.Update(shape->id, shape->ComputeAABB());
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::Step(float dt)
|
||||
{
|
||||
// Clear containers of exit state collisions
|
||||
updateEvents();
|
||||
// Contact manager to clear expired contacts
|
||||
contactManager.Update();
|
||||
|
||||
// TODO: Profile each of these
|
||||
runBroadphase ();
|
||||
runNarrowphase();
|
||||
/*
|
||||
* Detect Collisions
|
||||
*/
|
||||
|
||||
if (collisionSpace)
|
||||
collisionSpace->DetectCollisions();
|
||||
|
||||
/*
|
||||
* Integrate Forces
|
||||
*/
|
||||
|
||||
for (auto* rigidBody : rigidBodies | std::views::values)
|
||||
{
|
||||
if (!rigidBody->IsActive())
|
||||
continue;
|
||||
|
||||
rigidBody->ComputeWorldData();
|
||||
integrateForces(*rigidBody, dt);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* TODO: Resolve Contacts
|
||||
*/
|
||||
|
||||
/*
|
||||
* Integrate Velocities
|
||||
*/
|
||||
|
||||
for (auto* rigidBody : rigidBodies | std::views::values)
|
||||
{
|
||||
if (!rigidBody->IsActive())
|
||||
continue;
|
||||
|
||||
integrateVelocities(*rigidBody, dt);
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Private Member Functions Definitions */
|
||||
|
@ -262,275 +198,4 @@ namespace SHADE
|
|||
rigidBody.ClearForces();
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::runBroadphase() noexcept
|
||||
{
|
||||
// Update any colliders that have moved
|
||||
for (auto& collider : colliders | std::views::values)
|
||||
{
|
||||
if (!collider->hasMoved)
|
||||
continue;
|
||||
|
||||
// Clear hasMoved flag here
|
||||
collider->hasMoved = false;
|
||||
|
||||
// Update moved shapes in broadphase
|
||||
for (auto* shape : collider->shapes)
|
||||
broadphase.Update(shape->id, shape->ComputeAABB());
|
||||
}
|
||||
|
||||
// Query: Kinematic Triggers, Awake Dynamic Bodies & Dynamic Triggers
|
||||
for (auto& collider : colliders | std::views::values)
|
||||
{
|
||||
// Default static bodies
|
||||
if (!collider->rigidBody)
|
||||
continue;
|
||||
|
||||
// Explicit static bodies
|
||||
const bool IS_STATIC = collider->rigidBody->GetType() == SHRigidBody::Type::STATIC;
|
||||
if (IS_STATIC)
|
||||
continue;
|
||||
|
||||
// All remaining are kinematic or dynamic
|
||||
// Iterate through shapes: if kinematic / dynamic trigger, else if dynamic & awake
|
||||
if (collider->rigidBody->GetType() == SHRigidBody::Type::KINEMATIC)
|
||||
queryKinematic(collider);
|
||||
|
||||
if (collider->rigidBody->GetType() == SHRigidBody::Type::DYNAMIC)
|
||||
queryDynamic(collider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::queryKinematic(SHCollider* collider) noexcept
|
||||
{
|
||||
for (auto* shape : collider->shapes)
|
||||
{
|
||||
// For kinematic shapes, we only query triggers against everything else
|
||||
if (!shape->IsTrigger())
|
||||
continue;
|
||||
|
||||
auto& potentialCollisions = broadphase.Query(shape->id, shape->ComputeAABB());
|
||||
|
||||
// Build narrow-phase pairs
|
||||
auto* shapeA = shape;
|
||||
|
||||
const EntityID ID_A = shape->id.GetEntityID();
|
||||
const uint32_t INDEX_A = shape->id.GetShapeIndex();
|
||||
|
||||
for (auto& id : potentialCollisions)
|
||||
{
|
||||
// Get corresponding shape
|
||||
const EntityID ID_B = id.GetEntityID();
|
||||
const uint32_t INDEX_B = id.GetShapeIndex();
|
||||
|
||||
auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B);
|
||||
|
||||
// Build collision ID
|
||||
SHCollisionKey collisionKey;
|
||||
collisionKey.SetEntityA(ID_A);
|
||||
collisionKey.SetEntityB(ID_B);
|
||||
collisionKey.SetCollisionShapeA(INDEX_A);
|
||||
collisionKey.SetCollisionShapeB(INDEX_B);
|
||||
|
||||
// Check if it already exists. If it doesn't, put into batch.
|
||||
auto narrowphasePair = narrowphaseBatch.find(collisionKey);
|
||||
if (narrowphasePair == narrowphaseBatch.end())
|
||||
narrowphaseBatch.emplace(collisionKey, NarrowphasePair{ shapeA, shapeB });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::queryDynamic(SHCollider* collider) noexcept
|
||||
{
|
||||
for (auto* shape : collider->shapes)
|
||||
{
|
||||
auto& potentialCollisions = broadphase.Query(shape->id, shape->ComputeAABB());
|
||||
|
||||
// Build narrow-phase pairs
|
||||
auto* shapeA = shape;
|
||||
|
||||
const EntityID ID_A = shape->id.GetEntityID();
|
||||
const uint32_t INDEX_A = shape->id.GetShapeIndex();
|
||||
|
||||
for (auto& id : potentialCollisions)
|
||||
{
|
||||
// Get corresponding shape
|
||||
const EntityID ID_B = id.GetEntityID();
|
||||
const uint32_t INDEX_B = id.GetShapeIndex();
|
||||
|
||||
auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B);
|
||||
|
||||
// Build collision ID
|
||||
SHCollisionKey collisionKey;
|
||||
collisionKey.SetEntityA(ID_A);
|
||||
collisionKey.SetEntityB(ID_B);
|
||||
collisionKey.SetCollisionShapeA(INDEX_A);
|
||||
collisionKey.SetCollisionShapeB(INDEX_B);
|
||||
|
||||
// Check if it already exists. If it doesn't, put into batch.
|
||||
auto narrowphasePair = narrowphaseBatch.find(collisionKey);
|
||||
if (narrowphasePair == narrowphaseBatch.end())
|
||||
narrowphaseBatch.emplace(collisionKey, NarrowphasePair{ shapeA, shapeB });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::runNarrowphase() noexcept
|
||||
{
|
||||
if (narrowphaseBatch.empty())
|
||||
return;
|
||||
|
||||
for (auto& [id, narrowphasePair] : narrowphaseBatch)
|
||||
{
|
||||
const bool IS_A_TRIGGER = narrowphasePair.A->IsTrigger();
|
||||
const bool IS_B_TRIGGER = narrowphasePair.B->IsTrigger();
|
||||
|
||||
// Check if ID exists in trigger
|
||||
if (IS_A_TRIGGER || IS_B_TRIGGER)
|
||||
collideTriggers(id, narrowphasePair);
|
||||
else
|
||||
collideManifolds(id, narrowphasePair);
|
||||
}
|
||||
|
||||
// Clear every frame
|
||||
narrowphaseBatch.clear();
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::collideTriggers(const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept
|
||||
{
|
||||
const auto* A = narrowphasePair.A;
|
||||
const auto* B = narrowphasePair.B;
|
||||
|
||||
const bool COLLIDING = SHCollisionDispatcher::Collide(*A, *B);
|
||||
|
||||
auto trigger = triggers.find(id);
|
||||
|
||||
// If id not found, emplace new object.
|
||||
// New object is in the invalid state
|
||||
if (trigger == triggers.end())
|
||||
trigger = triggers.emplace(id, SHCollisionState::INVALID).first;
|
||||
|
||||
SHCollisionState& state = trigger->second;
|
||||
updateCollisionState(COLLIDING, state);
|
||||
|
||||
// If it was a false positive, remove the manifold immediately.
|
||||
// Remove using iterator as it is on average faster.
|
||||
if (state == SHCollisionState::INVALID)
|
||||
trigger = triggers.erase(trigger);
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::collideManifolds(const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept
|
||||
{
|
||||
auto* A = narrowphasePair.A;
|
||||
auto* B = narrowphasePair.B;
|
||||
|
||||
SHManifold newManifold { .A = A, .B = B };
|
||||
const bool COLLIDING = SHCollisionDispatcher::Collide(newManifold, *A, *B);
|
||||
|
||||
auto manifold = manifolds.find(id);
|
||||
|
||||
// If id not found, emplace new manifold
|
||||
if (manifold == manifolds.end())
|
||||
manifold = manifolds.emplace(id, newManifold).first;
|
||||
else
|
||||
{
|
||||
// TODO: Update existing manifolds with new data
|
||||
}
|
||||
|
||||
SHCollisionState& state = manifold->second.state;
|
||||
updateCollisionState(COLLIDING, state);
|
||||
|
||||
// If it was a false positive, remove the manifold immediately.
|
||||
// Remove using iterator as it is on average faster.
|
||||
if (state == SHCollisionState::INVALID)
|
||||
manifold = manifolds.erase(manifold);
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::updateCollisionState(bool isColliding, SHCollisionState& state) noexcept
|
||||
{
|
||||
if (isColliding)
|
||||
{
|
||||
// New states start at invalid. In the first frame of collision, move to enter.
|
||||
// If it already in enter, move to stay
|
||||
state = state == SHCollisionState::INVALID ? SHCollisionState::ENTER : SHCollisionState::STAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
// New states start at invalid. In false positive, remain unchanged.
|
||||
// If previously colliding, move to exit.
|
||||
state = state == SHCollisionState::INVALID ? SHCollisionState::INVALID : SHCollisionState::EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::updateEvents() noexcept
|
||||
{
|
||||
// Clear expired or invalid collisions
|
||||
for (auto manifold = manifolds.begin(); manifold != manifolds.end();)
|
||||
{
|
||||
const auto COLLISION_STATE = manifold->second.state;
|
||||
|
||||
const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT;
|
||||
const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID;
|
||||
|
||||
if (IS_EXIT || IS_INVALID)
|
||||
manifold = manifolds.erase(manifold);
|
||||
else
|
||||
++manifold;
|
||||
}
|
||||
|
||||
// Clear expired or invalid triggers
|
||||
for (auto trigger = triggers.begin(); trigger != triggers.end();)
|
||||
{
|
||||
const auto COLLISION_STATE = trigger->second;
|
||||
|
||||
const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT;
|
||||
const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID;
|
||||
|
||||
if (IS_EXIT || IS_INVALID)
|
||||
trigger = triggers.erase(trigger);
|
||||
else
|
||||
++trigger;
|
||||
}
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::removeInvalidatedTrigger(EntityID eid, uint32_t shapeIndex)
|
||||
{
|
||||
if (triggers.empty())
|
||||
return;
|
||||
|
||||
for (auto invalidatedTrigger = triggers.begin(); invalidatedTrigger != triggers.end();)
|
||||
{
|
||||
const auto& ID = invalidatedTrigger->first;
|
||||
|
||||
const bool MATCHES_A = ID.GetEntityA() == eid && ID.GetShapeIndexA() == shapeIndex;
|
||||
const bool MATCHES_B = ID.GetEntityB() == eid && ID.GetShapeIndexB() == shapeIndex;
|
||||
|
||||
if (MATCHES_A || MATCHES_B)
|
||||
invalidatedTrigger = triggers.erase(invalidatedTrigger);
|
||||
else
|
||||
++invalidatedTrigger;
|
||||
}
|
||||
}
|
||||
|
||||
void SHPhysicsWorld::removeInvalidatedManifold(EntityID eid, uint32_t shapeIndex)
|
||||
{
|
||||
if (manifolds.empty())
|
||||
return;
|
||||
|
||||
for (auto invalidatedManifold = manifolds.begin(); invalidatedManifold != manifolds.end();)
|
||||
{
|
||||
const auto& ID = invalidatedManifold->first;
|
||||
|
||||
const bool MATCHES_A = ID.GetEntityA() == eid && ID.GetShapeIndexA() == shapeIndex;
|
||||
const bool MATCHES_B = ID.GetEntityB() == eid && ID.GetShapeIndexB() == shapeIndex;
|
||||
|
||||
if (MATCHES_A || MATCHES_B)
|
||||
invalidatedManifold = manifolds.erase(invalidatedManifold);
|
||||
else
|
||||
++invalidatedManifold;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace SHADE
|
|
@ -13,10 +13,8 @@
|
|||
#include <unordered_map>
|
||||
|
||||
// Project Headers
|
||||
#include "Physics/Collision/Broadphase/SHDynamicAABBTree.h"
|
||||
#include "Physics/Collision/Contacts/SHCollisionEvents.h"
|
||||
#include "Physics/Collision/Contacts/SHManifold.h"
|
||||
#include "Physics/Collision/SHCollider.h"
|
||||
#include "Physics/Collision/SHCollisionSpace.h"
|
||||
#include "SHContactManager.h"
|
||||
#include "SHRigidBody.h"
|
||||
|
||||
|
||||
|
@ -26,10 +24,15 @@ namespace SHADE
|
|||
/* Type Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Encapsulates the overall simulation of physics. The bulk of dynamics are handled here,
|
||||
* with the collision detection handled by an attached collision space. <br/>
|
||||
* A collision space must be created separately and attached with the world.
|
||||
*/
|
||||
class SH_API SHPhysicsWorld
|
||||
{
|
||||
public:
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -47,9 +50,6 @@ namespace SHADE
|
|||
bool sleepingEnabled = true;
|
||||
};
|
||||
|
||||
using TriggerEvents = std::vector<SHTriggerEvent>;
|
||||
using CollisionEvents = std::vector<SHCollisionEvent>;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Constructors & Destructor */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -71,29 +71,44 @@ namespace SHADE
|
|||
/* Getter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
const SHAABBTree::AABBs& GetBroadphaseAABBs () const noexcept;
|
||||
const SHContactManager::TriggerEvents& GetTriggerEvents () const noexcept;
|
||||
const SHContactManager::CollisionEvents& GetCollisionEvents () const noexcept;
|
||||
|
||||
const TriggerEvents& GetTriggerEvents () const noexcept;
|
||||
const CollisionEvents& GetCollisionEvents () const noexcept;
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Setter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
void SetCollisionSpace(SHCollisionSpace* collisionSpace) noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Member Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Adds a rigid body to the world for it to be simulated using motion dynamics.
|
||||
* @param rigidBody
|
||||
* A rigid body to add. Duplicates will be ignored.
|
||||
*/
|
||||
void AddRigidBody (SHRigidBody* rigidBody) noexcept;
|
||||
void RemoveRigidBody (SHRigidBody* rigidBody) noexcept;
|
||||
|
||||
void AddCollider (SHCollider* collider) noexcept;
|
||||
void RemoveCollider (SHCollider* collider) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Invoke this method to update the broadphase of a collider while the simulation
|
||||
* is not running.
|
||||
* @param collider
|
||||
* The collider to update.
|
||||
* Removes a rigid body from the world. It's motion will not be affected unless
|
||||
* explicitly modified.
|
||||
* @param rigidBody
|
||||
* A rigid body to add. Duplicates will be ignored.
|
||||
*/
|
||||
void RemoveRigidBody (SHRigidBody* rigidBody) noexcept;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Performs a single simulation step. <br/>
|
||||
* Detect Collisions -> Integrate Forces -> Resolve Contacts -> Integrate Velocities
|
||||
* @param dt
|
||||
* A discrete time step for the simulation. This should be consistent for deteministic
|
||||
* behaviour.
|
||||
*/
|
||||
void UpdateBroadphase (SHCollider* collider) noexcept;
|
||||
void Step (float dt);
|
||||
|
||||
private:
|
||||
|
@ -101,42 +116,18 @@ namespace SHADE
|
|||
/* Type Definitions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
struct NarrowphasePair
|
||||
{
|
||||
SHCollisionShape* A = nullptr;
|
||||
SHCollisionShape* B = nullptr;
|
||||
};
|
||||
|
||||
// EntityIDs are used to map resolved contraints back to bodies
|
||||
using RigidBodies = std::unordered_map<EntityID, SHRigidBody*>;
|
||||
using Colliders = std::unordered_map<EntityID, SHCollider*>;
|
||||
|
||||
// Collisions
|
||||
|
||||
using NarrowphaseBatch = std::unordered_map<SHCollisionKey, NarrowphasePair, SHCollisionKeyHash>;
|
||||
using Manifolds = std::unordered_map<SHCollisionKey, SHManifold, SHCollisionKeyHash>;
|
||||
using Triggers = std::unordered_map<SHCollisionKey, SHCollisionState, SHCollisionKeyHash>;
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Data Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
WorldSettings settings;
|
||||
|
||||
// Containers
|
||||
SHCollisionSpace* collisionSpace;
|
||||
|
||||
RigidBodies rigidBodies;
|
||||
Colliders colliders;
|
||||
|
||||
NarrowphaseBatch narrowphaseBatch;
|
||||
Manifolds manifolds;
|
||||
Triggers triggers;
|
||||
|
||||
// World components
|
||||
|
||||
SHAABBTree broadphase;
|
||||
SHContactManager contactManager;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Function Members */
|
||||
|
@ -146,22 +137,8 @@ namespace SHADE
|
|||
void integrateForces (SHRigidBody& rigidBody, float dt) const noexcept;
|
||||
void integrateVelocities (SHRigidBody& rigidBody, float dt) const noexcept;
|
||||
|
||||
// Broadphase helpers
|
||||
|
||||
void runBroadphase () noexcept;
|
||||
void queryKinematic (SHCollider* collider) noexcept;
|
||||
void queryDynamic (SHCollider* collider) noexcept;
|
||||
|
||||
// Narrowphase helpers
|
||||
|
||||
void runNarrowphase () 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;
|
||||
void removeInvalidatedTrigger (EntityID eid, uint32_t shapeIndex);
|
||||
void removeInvalidatedManifold (EntityID eid, uint32_t shapeIndex);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -87,9 +87,8 @@ namespace SHADE
|
|||
{
|
||||
const SHColour& AABB_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::BROADPHASE)];
|
||||
|
||||
auto& broadphaseAABBs = physicsSystem->GetWorld()->GetBroadphaseAABBs();
|
||||
|
||||
for (auto& aabb : broadphaseAABBs)
|
||||
const auto& BROADPHASE_AABBS = physicsSystem->collisionSpace->GetBroadphaseAABBs();
|
||||
for (auto& aabb : BROADPHASE_AABBS)
|
||||
{
|
||||
// Compute AABB Transform
|
||||
const SHMatrix TRS = SHMatrix::Transform(aabb.GetCenter(), SHQuaternion::Identity, aabb.GetWorldExtents() * 2.0f);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
// Project Headers
|
||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||
#include "Math/Transform/SHTransformComponent.h"
|
||||
#include "Scene/SHSceneManager.h"
|
||||
#include "Scripting/SHScriptEngine.h"
|
||||
|
||||
|
||||
|
@ -50,15 +51,25 @@ namespace SHADE
|
|||
const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense<SHRigidBodyComponent>();
|
||||
for (auto& rigidBodyComponent : RIGIDBODY_DENSE)
|
||||
{
|
||||
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(rigidBodyComponent.GetEID());
|
||||
const EntityID EID = rigidBodyComponent.GetEID();
|
||||
|
||||
// Skip missing transforms
|
||||
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(EID);
|
||||
if (!transformComponent)
|
||||
continue;
|
||||
|
||||
// Skip invalid bodies (Should not occur)
|
||||
if (!rigidBodyComponent.rigidBody)
|
||||
continue;
|
||||
|
||||
// Skip inactive bodies
|
||||
const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(EID);
|
||||
if (!IS_ACTIVE)
|
||||
continue;
|
||||
|
||||
const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState();
|
||||
|
||||
// Skip objects that have not moved
|
||||
if (!MOTION_STATE)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
// Project Headers
|
||||
#include "ECS_Base/Managers/SHComponentManager.h"
|
||||
#include "Math/Transform/SHTransformComponent.h"
|
||||
#include "Scene/SHSceneManager.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -40,35 +41,54 @@ namespace SHADE
|
|||
for (auto& [entityID, physicsObject] : physicsObjects)
|
||||
{
|
||||
const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
|
||||
|
||||
if (!TRANSFORM_COMPONENT || !TRANSFORM_COMPONENT->HasChanged())
|
||||
continue;
|
||||
|
||||
const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition();
|
||||
const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation();
|
||||
const SHVec3& WORLD_SCL = TRANSFORM_COMPONENT->GetWorldScale();
|
||||
// Assume transform is always active
|
||||
const bool UPDATE_TRANSFORM = TRANSFORM_COMPONENT && TRANSFORM_COMPONENT->HasChanged();
|
||||
|
||||
// We assume that all engine components and physics object components have been successfully linked
|
||||
|
||||
if (physicsObject.rigidBody)
|
||||
{
|
||||
SHMotionState& motionState = physicsObject.rigidBody->GetMotionState();
|
||||
const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(entityID);
|
||||
const bool RIGIDBODY_ACTIVE = physicsObject.rigidBody->IsActive();
|
||||
|
||||
motionState.ForcePosition(TRANSFORM_COMPONENT->GetWorldPosition());
|
||||
motionState.ForceOrientation(TRANSFORM_COMPONENT->GetWorldOrientation());
|
||||
if (IS_ACTIVE != RIGIDBODY_ACTIVE)
|
||||
physicsObject.rigidBody->SetIsActive(IS_ACTIVE);
|
||||
|
||||
if (UPDATE_TRANSFORM)
|
||||
{
|
||||
const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition();
|
||||
const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation();
|
||||
|
||||
SHMotionState& motionState = physicsObject.rigidBody->GetMotionState();
|
||||
motionState.ForcePosition(WORLD_POS);
|
||||
motionState.ForceOrientation(WORLD_ROT);
|
||||
}
|
||||
}
|
||||
|
||||
if (physicsObject.collider)
|
||||
{
|
||||
const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(entityID);
|
||||
const bool COLLIDER_ACTIVE = physicsObject.collider->IsActive();
|
||||
|
||||
if (IS_ACTIVE != COLLIDER_ACTIVE)
|
||||
physicsObject.collider->SetIsActive(IS_ACTIVE);
|
||||
|
||||
if (UPDATE_TRANSFORM)
|
||||
{
|
||||
const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition();
|
||||
const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation();
|
||||
const SHVec3& WORLD_SCL = TRANSFORM_COMPONENT->GetWorldScale();
|
||||
|
||||
physicsObject.collider->SetPosition(WORLD_POS);
|
||||
physicsObject.collider->SetOrientation(WORLD_ROT);
|
||||
physicsObject.collider->SetScale(WORLD_SCL);
|
||||
|
||||
physicsObject.collider->RecomputeShapes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
physicsSystem->physicsWorld->UpdateBroadphase(physicsObject.collider);
|
||||
}
|
||||
}
|
||||
physicsSystem->collisionSpace->UpdateBroadphase();
|
||||
}
|
||||
|
||||
} // namespace SHADE
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "Editor/SHEditor.h"
|
||||
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
|
||||
#include "Physics/Interface/SHColliderComponent.h"
|
||||
#include "Scripting/SHScriptEngine.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -33,6 +34,7 @@ namespace SHADE
|
|||
, interpolationFactor { 0.0 }
|
||||
, fixedDT { DEFAULT_FIXED_STEP }
|
||||
, physicsWorld { nullptr }
|
||||
, collisionSpace { nullptr }
|
||||
{
|
||||
// Add more events here to register them
|
||||
|
||||
|
@ -44,6 +46,7 @@ namespace SHADE
|
|||
|
||||
SHPhysicsSystem::~SHPhysicsSystem() noexcept
|
||||
{
|
||||
delete collisionSpace;
|
||||
delete physicsWorld;
|
||||
}
|
||||
|
||||
|
@ -51,11 +54,6 @@ namespace SHADE
|
|||
/* Getter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
const SHPhysicsWorld* SHPhysicsSystem::GetWorld() const noexcept
|
||||
{
|
||||
return physicsWorld;
|
||||
}
|
||||
|
||||
double SHPhysicsSystem::GetFixedUpdateRate() const noexcept
|
||||
{
|
||||
return 1.0 / fixedDT;
|
||||
|
@ -66,6 +64,16 @@ namespace SHADE
|
|||
return fixedDT;
|
||||
}
|
||||
|
||||
const std::vector<SHTriggerEvent>& SHPhysicsSystem::GetTriggerInfo() const noexcept
|
||||
{
|
||||
return physicsWorld->GetTriggerEvents();
|
||||
}
|
||||
|
||||
const std::vector<SHCollisionEvent>& SHPhysicsSystem::GetCollisionInfo() const noexcept
|
||||
{
|
||||
return physicsWorld->GetCollisionEvents();
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Setter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -137,7 +145,48 @@ namespace SHADE
|
|||
|
||||
void SHPhysicsSystem::ForceUpdate()
|
||||
{
|
||||
if (!physicsWorld)
|
||||
return;
|
||||
|
||||
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
|
||||
|
||||
if (scriptingSystem == nullptr)
|
||||
{
|
||||
SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!");
|
||||
}
|
||||
|
||||
scriptingSystem->ExecuteFixedUpdates();
|
||||
physicsWorld->Step(static_cast<float>(fixedDT));
|
||||
|
||||
const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense<SHRigidBodyComponent>();
|
||||
for (auto& rigidBodyComponent : RIGIDBODY_DENSE)
|
||||
{
|
||||
const EntityID EID = rigidBodyComponent.GetEID();
|
||||
|
||||
// Skip missing transforms
|
||||
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(EID);
|
||||
if (!transformComponent)
|
||||
continue;
|
||||
|
||||
// Skip invalid bodies (Should not occur)
|
||||
if (!rigidBodyComponent.rigidBody)
|
||||
continue;
|
||||
|
||||
// Skip inactive bodies
|
||||
const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(EID);
|
||||
if (!IS_ACTIVE)
|
||||
continue;
|
||||
|
||||
const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState();
|
||||
|
||||
// Skip objects that have not moved
|
||||
if (!MOTION_STATE)
|
||||
continue;
|
||||
|
||||
// We ignore interpolations here because we are only stepping once
|
||||
transformComponent->SetWorldPosition(MOTION_STATE.position);
|
||||
transformComponent->SetWorldOrientation(MOTION_STATE.orientation);
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -162,17 +211,29 @@ namespace SHADE
|
|||
{
|
||||
if (PHYSICS_OBJECT.rigidBody)
|
||||
physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody);
|
||||
|
||||
if (PHYSICS_OBJECT.collider)
|
||||
physicsWorld->RemoveCollider(PHYSICS_OBJECT.collider);
|
||||
}
|
||||
|
||||
delete physicsWorld;
|
||||
physicsWorld = nullptr;
|
||||
}
|
||||
|
||||
// Create the physics world
|
||||
if (collisionSpace)
|
||||
{
|
||||
for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values)
|
||||
{
|
||||
if (PHYSICS_OBJECT.collider)
|
||||
collisionSpace->RemoveCollider(PHYSICS_OBJECT.collider);
|
||||
}
|
||||
|
||||
delete collisionSpace;
|
||||
collisionSpace = nullptr;
|
||||
}
|
||||
|
||||
// Create the physics world & collision space
|
||||
physicsWorld = new SHPhysicsWorld;
|
||||
collisionSpace = new SHCollisionSpace;
|
||||
|
||||
physicsWorld->SetCollisionSpace(collisionSpace);
|
||||
|
||||
// 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.
|
||||
|
@ -184,7 +245,7 @@ namespace SHADE
|
|||
physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody);
|
||||
|
||||
if (PHYSICS_OBJECT.collider)
|
||||
physicsWorld->AddCollider(PHYSICS_OBJECT.collider);
|
||||
collisionSpace->AddCollider(PHYSICS_OBJECT.collider);
|
||||
}
|
||||
|
||||
return onSceneInitEvent.get()->handle;
|
||||
|
@ -203,9 +264,12 @@ namespace SHADE
|
|||
physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody);
|
||||
|
||||
if (PHYSICS_OBJECT.collider)
|
||||
physicsWorld->RemoveCollider(PHYSICS_OBJECT.collider);
|
||||
collisionSpace->RemoveCollider(PHYSICS_OBJECT.collider);
|
||||
}
|
||||
|
||||
delete collisionSpace;
|
||||
collisionSpace = nullptr;
|
||||
|
||||
delete physicsWorld;
|
||||
physicsWorld = nullptr;
|
||||
|
||||
|
@ -247,10 +311,10 @@ namespace SHADE
|
|||
{
|
||||
physicsObjectManager.AddCollider(EID);
|
||||
|
||||
if (physicsWorld)
|
||||
if (collisionSpace)
|
||||
{
|
||||
auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider;
|
||||
physicsWorld->AddCollider(collider);
|
||||
collisionSpace->AddCollider(collider);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,16 +353,15 @@ namespace SHADE
|
|||
|
||||
if (IS_COLLIDER)
|
||||
{
|
||||
if (physicsWorld)
|
||||
if (collisionSpace)
|
||||
{
|
||||
auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider;
|
||||
physicsWorld->RemoveCollider(collider);
|
||||
collisionSpace->RemoveCollider(collider);
|
||||
}
|
||||
|
||||
physicsObjectManager.RemoveCollider(EID);
|
||||
}
|
||||
|
||||
|
||||
return onComponentRemovedEvent.get()->handle;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,13 @@ namespace SHADE
|
|||
*/
|
||||
class SH_API SHPhysicsSystem final : public SHSystem
|
||||
{
|
||||
private:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Friends */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
friend class SHPhysicsDebugDrawSystem;
|
||||
|
||||
public:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Constructors & Destructor */
|
||||
|
@ -45,7 +52,6 @@ namespace SHADE
|
|||
/* Getter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] const SHPhysicsWorld* GetWorld () const noexcept;
|
||||
[[nodiscard]] double GetFixedUpdateRate() const noexcept;
|
||||
[[nodiscard]] double GetFixedDT () const noexcept;
|
||||
|
||||
|
@ -56,6 +62,9 @@ namespace SHADE
|
|||
void SetFixedUpdateRate(double fixedUpdateRate) noexcept;
|
||||
void SetFixedDT(double fixedDt) noexcept;
|
||||
|
||||
const std::vector<SHTriggerEvent>& GetTriggerInfo () const noexcept;
|
||||
const std::vector<SHCollisionEvent>& GetCollisionInfo () const noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Member Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -137,6 +146,7 @@ namespace SHADE
|
|||
// Sub-systems / managers
|
||||
|
||||
SHPhysicsWorld* physicsWorld;
|
||||
SHCollisionSpace* collisionSpace;
|
||||
SHPhysicsObjectManager physicsObjectManager;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
/************************************************************************************//*!
|
||||
\file SHPhysicsSystemInterface.cpp
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\date Oct 31, 2022
|
||||
\author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
\brief Contains the definitions of the functions of the static
|
||||
SHPhysicsSystemInterface class.
|
||||
|
||||
|
@ -10,10 +8,13 @@ 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.
|
||||
*//*************************************************************************************/
|
||||
// Precompiled Headers
|
||||
|
||||
|
||||
#include "SHpch.h"
|
||||
|
||||
// Primary Header
|
||||
#include "SHPhysicsSystemInterface.h"
|
||||
|
||||
// Project Includes
|
||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||
#include "Physics/System/SHPhysicsSystem.h"
|
||||
|
@ -23,42 +24,47 @@ namespace SHADE
|
|||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Static Usage Functions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
const std::vector<SHCollisionInfo>& SHPhysicsSystemInterface::GetCollisionInfo() noexcept
|
||||
const std::vector<SHCollisionEvent>& SHPhysicsSystemInterface::GetCollisionInfo() noexcept
|
||||
{
|
||||
static std::vector<SHCollisionInfo> emptyVec;
|
||||
static std::vector<SHCollisionEvent> emptyVec;
|
||||
|
||||
//auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
|
||||
//if (phySystem)
|
||||
//{
|
||||
// return phySystem->GetAllCollisionInfo();
|
||||
//}
|
||||
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
|
||||
if (physicsSystem)
|
||||
return physicsSystem->GetCollisionInfo();
|
||||
|
||||
//SHLOGV_WARNING("Failed to get collision events. Empty vector returned instead.");
|
||||
SHLOGV_WARNING("Failed to get collision events. Empty vector returned instead.");
|
||||
return emptyVec;
|
||||
}
|
||||
const std::vector<SHCollisionInfo>& SHPhysicsSystemInterface::GetTriggerInfo() noexcept
|
||||
const std::vector<SHTriggerEvent>& SHPhysicsSystemInterface::GetTriggerInfo() noexcept
|
||||
{
|
||||
static std::vector<SHCollisionInfo> emptyVec;
|
||||
static std::vector<SHTriggerEvent> emptyVec;
|
||||
|
||||
//auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
|
||||
//if (phySystem)
|
||||
//{
|
||||
// return phySystem->GetAllTriggerInfo();
|
||||
//}
|
||||
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
|
||||
if (physicsSystem)
|
||||
return physicsSystem->GetTriggerInfo();
|
||||
|
||||
//SHLOGV_WARNING("Failed to get trigger events. Empty vector returned instead.");
|
||||
SHLOGV_WARNING("Failed to get trigger events. Empty vector returned instead.");
|
||||
return emptyVec;
|
||||
}
|
||||
|
||||
double SHPhysicsSystemInterface::GetFixedDT() noexcept
|
||||
{
|
||||
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
|
||||
if (phySystem)
|
||||
{
|
||||
return 1.0 / phySystem->GetFixedUpdateRate();
|
||||
}
|
||||
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
|
||||
if (physicsSystem)
|
||||
return physicsSystem->GetFixedDT();
|
||||
|
||||
SHLOGV_WARNING("Failed to get fixed delta time. 0.0 returned instead.");
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
int SHPhysicsSystemInterface::GetFixedUpdateRate() noexcept
|
||||
{
|
||||
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
|
||||
if (physicsSystem)
|
||||
return physicsSystem->GetFixedUpdateRate();
|
||||
|
||||
SHLOGV_WARNING("Failed to get fixed update rate. 0.0 returned instead.");
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,22 +1,20 @@
|
|||
/************************************************************************************//*!
|
||||
\file SHPhysicsSystemInterface.h
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\date Oct 31, 2022
|
||||
\author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
\brief Contains the definition of the SHGraphicsSystemInterface static class.
|
||||
|
||||
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
|
||||
|
||||
// STL Includes
|
||||
#include <vector>
|
||||
|
||||
// Project Headers
|
||||
#include "ECS_Base/Entity/SHEntity.h"
|
||||
#include "Physics/Collision/SHCollisionInfo.h"
|
||||
#include "Physics/Collision/Contacts/SHCollisionEvents.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
|
@ -49,8 +47,8 @@ namespace SHADE
|
|||
/* Static Usage Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] static const std::vector<SHCollisionInfo>& GetCollisionInfo () noexcept;
|
||||
[[nodiscard]] static const std::vector<SHCollisionInfo>& GetTriggerInfo () noexcept;
|
||||
[[nodiscard]] static const std::vector<SHCollisionEvent>& GetCollisionInfo () noexcept;
|
||||
[[nodiscard]] static const std::vector<SHTriggerEvent>& GetTriggerInfo () noexcept;
|
||||
[[nodiscard]] static double GetFixedDT () noexcept;
|
||||
[[nodiscard]] static int GetFixedUpdateRate () noexcept;
|
||||
};
|
||||
|
|
|
@ -30,7 +30,6 @@ of DigiPen Institute of Technology is prohibited.
|
|||
#include "Engine/Application.hxx"
|
||||
#include "Physics/System/SHPhysicsSystemInterface.h"
|
||||
#include "Physics/SHPhysicsEvents.h"
|
||||
#include "Physics/Collision/SHCollisionInfo.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -605,8 +604,8 @@ namespace SHADE
|
|||
{
|
||||
auto entities =
|
||||
{
|
||||
std::make_pair(collisionInfo.GetEntityA(), collisionInfo.GetEntityB()),
|
||||
std::make_pair(collisionInfo.GetEntityB(), collisionInfo.GetEntityA())
|
||||
std::make_pair(collisionInfo.info.GetEntityA(), collisionInfo.info.GetEntityB()),
|
||||
std::make_pair(collisionInfo.info.GetEntityB(), collisionInfo.info.GetEntityA())
|
||||
};
|
||||
for (auto entity : entities)
|
||||
{
|
||||
|
@ -625,15 +624,15 @@ namespace SHADE
|
|||
for (int i = 0; i < entityScripts->Count; ++i)
|
||||
{
|
||||
Script^ script = entityScripts[i];
|
||||
switch (collisionInfo.GetCollisionState())
|
||||
switch (collisionInfo.state)
|
||||
{
|
||||
case SHCollisionInfo::State::ENTER:
|
||||
case SHCollisionState::ENTER:
|
||||
script->OnCollisionEnter(info);
|
||||
break;
|
||||
case SHCollisionInfo::State::STAY:
|
||||
case SHCollisionState::STAY:
|
||||
script->OnCollisionStay(info);
|
||||
break;
|
||||
case SHCollisionInfo::State::EXIT:
|
||||
case SHCollisionState::EXIT:
|
||||
script->OnCollisionExit(info);
|
||||
break;
|
||||
}
|
||||
|
@ -647,8 +646,8 @@ namespace SHADE
|
|||
{
|
||||
auto entities =
|
||||
{
|
||||
std::make_pair(triggerInfo.GetEntityA(), triggerInfo.GetEntityB()),
|
||||
std::make_pair(triggerInfo.GetEntityB(), triggerInfo.GetEntityA())
|
||||
std::make_pair(triggerInfo.info.GetEntityA(), triggerInfo.info.GetEntityB()),
|
||||
std::make_pair(triggerInfo.info.GetEntityB(), triggerInfo.info.GetEntityA())
|
||||
};
|
||||
for (auto entity : entities)
|
||||
{
|
||||
|
@ -667,15 +666,15 @@ namespace SHADE
|
|||
for (int i = 0; i < entityScripts->Count; ++i)
|
||||
{
|
||||
Script^ script = entityScripts[i];
|
||||
switch (triggerInfo.GetCollisionState())
|
||||
switch (triggerInfo.state)
|
||||
{
|
||||
case SHCollisionInfo::State::ENTER:
|
||||
case SHCollisionState::ENTER:
|
||||
script->OnTriggerEnter(info);
|
||||
break;
|
||||
case SHCollisionInfo::State::STAY:
|
||||
case SHCollisionState::STAY:
|
||||
script->OnTriggerStay(info);
|
||||
break;
|
||||
case SHCollisionInfo::State::EXIT:
|
||||
case SHCollisionState::EXIT:
|
||||
script->OnTriggerExit(info);
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue