Implemented a custom physics engine #316
|
@ -55,6 +55,8 @@ namespace SHADE
|
||||||
static constexpr float HALF_PI = PI * 0.5f;
|
static constexpr float HALF_PI = PI * 0.5f;
|
||||||
static constexpr float TWO_PI = 2.0f * PI;
|
static constexpr float TWO_PI = 2.0f * PI;
|
||||||
|
|
||||||
|
static constexpr float EULER_CONSTANT = std::numbers::egamma_v<float>;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Static Function Members */
|
/* Static Function Members */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -122,7 +122,7 @@ namespace SHADE
|
||||||
/* Data Members */
|
/* Data Members */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
static constexpr float AABB_EXTENSION = 0.1f;
|
static constexpr float AABB_EXTENSION = 0.2f;
|
||||||
|
|
||||||
// For quick access
|
// For quick access
|
||||||
std::unordered_map<SHCollisionShapeID, int32_t, SHCollisionShapeIDHash> nodeMap;
|
std::unordered_map<SHCollisionShapeID, int32_t, SHCollisionShapeIDHash> nodeMap;
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace SHADE
|
||||||
friend class SHCollider;
|
friend class SHCollider;
|
||||||
friend class SHColliderComponent;
|
friend class SHColliderComponent;
|
||||||
friend class SHCollisionShapeFactory;
|
friend class SHCollisionShapeFactory;
|
||||||
friend class SHPhysicsWorld;
|
friend class SHCollisionSpace;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace SHADE
|
||||||
|
|
||||||
SHCollider::SHCollider(EntityID eid, const SHTransform& worldTransform) noexcept
|
SHCollider::SHCollider(EntityID eid, const SHTransform& worldTransform) noexcept
|
||||||
: entityID { eid }
|
: entityID { eid }
|
||||||
|
, active { true }
|
||||||
, debugDraw { false }
|
, debugDraw { false }
|
||||||
, hasMoved { true }
|
, hasMoved { true }
|
||||||
, rigidBody { nullptr }
|
, rigidBody { nullptr }
|
||||||
|
@ -39,6 +40,7 @@ namespace SHADE
|
||||||
|
|
||||||
SHCollider::SHCollider(const SHCollider& rhs) noexcept
|
SHCollider::SHCollider(const SHCollider& rhs) noexcept
|
||||||
: entityID { rhs.entityID }
|
: entityID { rhs.entityID }
|
||||||
|
, active { rhs.active }
|
||||||
, debugDraw { rhs.debugDraw }
|
, debugDraw { rhs.debugDraw }
|
||||||
, hasMoved { rhs.hasMoved }
|
, hasMoved { rhs.hasMoved }
|
||||||
, rigidBody { rhs.rigidBody }
|
, rigidBody { rhs.rigidBody }
|
||||||
|
@ -57,6 +59,7 @@ namespace SHADE
|
||||||
|
|
||||||
SHCollider::SHCollider(SHCollider&& rhs) noexcept
|
SHCollider::SHCollider(SHCollider&& rhs) noexcept
|
||||||
: entityID { rhs.entityID }
|
: entityID { rhs.entityID }
|
||||||
|
, active { rhs.active }
|
||||||
, debugDraw { rhs.debugDraw }
|
, debugDraw { rhs.debugDraw }
|
||||||
, hasMoved { rhs.hasMoved }
|
, hasMoved { rhs.hasMoved }
|
||||||
, rigidBody { rhs.rigidBody }
|
, rigidBody { rhs.rigidBody }
|
||||||
|
@ -101,6 +104,7 @@ namespace SHADE
|
||||||
}
|
}
|
||||||
|
|
||||||
entityID = rhs.entityID;
|
entityID = rhs.entityID;
|
||||||
|
active = rhs.active;
|
||||||
debugDraw = rhs.debugDraw;
|
debugDraw = rhs.debugDraw;
|
||||||
hasMoved = rhs.hasMoved;
|
hasMoved = rhs.hasMoved;
|
||||||
rigidBody = rhs.rigidBody;
|
rigidBody = rhs.rigidBody;
|
||||||
|
@ -122,6 +126,7 @@ namespace SHADE
|
||||||
}
|
}
|
||||||
|
|
||||||
entityID = rhs.entityID;
|
entityID = rhs.entityID;
|
||||||
|
active = rhs.active;
|
||||||
debugDraw = rhs.debugDraw;
|
debugDraw = rhs.debugDraw;
|
||||||
hasMoved = rhs.hasMoved;
|
hasMoved = rhs.hasMoved;
|
||||||
rigidBody = rhs.rigidBody;
|
rigidBody = rhs.rigidBody;
|
||||||
|
@ -138,6 +143,16 @@ namespace SHADE
|
||||||
/* Getter Function Definitions */
|
/* Getter Function Definitions */
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
EntityID SHCollider::GetEntityID() const noexcept
|
||||||
|
{
|
||||||
|
return entityID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHCollider::IsActive() const noexcept
|
||||||
|
{
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
bool SHCollider::GetDebugDrawState() const noexcept
|
bool SHCollider::GetDebugDrawState() const noexcept
|
||||||
{
|
{
|
||||||
return debugDraw;
|
return debugDraw;
|
||||||
|
@ -182,6 +197,25 @@ namespace SHADE
|
||||||
/* Setter Function Definitions */
|
/* 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
|
void SHCollider::SetDebugDrawState(bool state) noexcept
|
||||||
{
|
{
|
||||||
debugDraw = state;
|
debugDraw = state;
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace SHADE
|
||||||
/* Friends */
|
/* Friends */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
friend class SHPhysicsWorld;
|
friend class SHCollisionSpace;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
@ -79,6 +79,8 @@ namespace SHADE
|
||||||
/* Getter Functions */
|
/* Getter Functions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
[[nodiscard]] EntityID GetEntityID () const noexcept;
|
||||||
|
[[nodiscard]] bool IsActive () const noexcept;
|
||||||
[[nodiscard]] bool GetDebugDrawState () const noexcept;
|
[[nodiscard]] bool GetDebugDrawState () const noexcept;
|
||||||
|
|
||||||
[[nodiscard]] const SHTransform& GetTransform () const noexcept;
|
[[nodiscard]] const SHTransform& GetTransform () const noexcept;
|
||||||
|
@ -93,6 +95,7 @@ namespace SHADE
|
||||||
/* Setter Functions */
|
/* Setter Functions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void SetIsActive (bool state) noexcept;
|
||||||
void SetDebugDrawState (bool state) noexcept;
|
void SetDebugDrawState (bool state) noexcept;
|
||||||
|
|
||||||
void SetRigidBody (SHRigidBody* rb) noexcept;
|
void SetRigidBody (SHRigidBody* rb) noexcept;
|
||||||
|
@ -157,6 +160,7 @@ namespace SHADE
|
||||||
|
|
||||||
EntityID entityID;
|
EntityID entityID;
|
||||||
|
|
||||||
|
bool active;
|
||||||
bool debugDraw;
|
bool debugDraw;
|
||||||
bool hasMoved;
|
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
|
// Primary Header
|
||||||
#include "SHPhysicsWorld.h"
|
#include "SHPhysicsWorld.h"
|
||||||
|
|
||||||
// Project Headers
|
|
||||||
#include "Physics/Collision/Narrowphase/SHCollision.h"
|
|
||||||
#include "Physics/Collision/Narrowphase/SHCollisionDispatch.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
@ -26,58 +21,38 @@ namespace SHADE
|
||||||
|
|
||||||
SHPhysicsWorld::SHPhysicsWorld(const WorldSettings& worldSettings) noexcept
|
SHPhysicsWorld::SHPhysicsWorld(const WorldSettings& worldSettings) noexcept
|
||||||
: settings { worldSettings }
|
: settings { worldSettings }
|
||||||
|
, collisionSpace { nullptr }
|
||||||
{
|
{
|
||||||
SHLOG_INFO_D("Creating Physics World")
|
SHLOG_INFO_D("Creating Physics World")
|
||||||
}
|
}
|
||||||
|
|
||||||
SHPhysicsWorld::~SHPhysicsWorld() noexcept
|
SHPhysicsWorld::~SHPhysicsWorld() noexcept
|
||||||
{
|
{
|
||||||
|
collisionSpace = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
/* Getter Functions Definitions */
|
/* 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;
|
return contactManager.GetCollisionEvents();
|
||||||
|
|
||||||
triggerEvents.clear();
|
|
||||||
|
|
||||||
for (auto& [id, state] : triggers)
|
|
||||||
triggerEvents.emplace_back(SHTriggerEvent{ id, state });
|
|
||||||
|
|
||||||
return triggerEvents;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SHPhysicsWorld::CollisionEvents& SHPhysicsWorld::GetCollisionEvents() const noexcept
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
/* Setter Functions Definitions */
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void SHPhysicsWorld::SetCollisionSpace(SHCollisionSpace* _collisionSpace) noexcept
|
||||||
{
|
{
|
||||||
static CollisionEvents collisionEvents;
|
collisionSpace = _collisionSpace;
|
||||||
|
_collisionSpace->SetContactManager(&contactManager);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
@ -97,94 +72,55 @@ namespace SHADE
|
||||||
{
|
{
|
||||||
rigidBodies.erase(rigidBody->entityID);
|
rigidBodies.erase(rigidBody->entityID);
|
||||||
|
|
||||||
// Attempt to remove any invalidated manifolds
|
// Contact manager to remove invalidated contacts
|
||||||
if (manifolds.empty())
|
contactManager.RemoveInvalidatedManifold(rigidBody->entityID);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep
|
// 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)
|
void SHPhysicsWorld::Step(float dt)
|
||||||
{
|
{
|
||||||
// Clear containers of exit state collisions
|
// Contact manager to clear expired contacts
|
||||||
updateEvents();
|
contactManager.Update();
|
||||||
|
|
||||||
// TODO: Profile each of these
|
/*
|
||||||
runBroadphase ();
|
* Detect Collisions
|
||||||
runNarrowphase();
|
*/
|
||||||
|
|
||||||
|
if (collisionSpace)
|
||||||
|
collisionSpace->DetectCollisions();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Integrate Forces
|
||||||
|
*/
|
||||||
|
|
||||||
for (auto* rigidBody : rigidBodies | std::views::values)
|
for (auto* rigidBody : rigidBodies | std::views::values)
|
||||||
{
|
{
|
||||||
|
if (!rigidBody->IsActive())
|
||||||
|
continue;
|
||||||
|
|
||||||
rigidBody->ComputeWorldData();
|
rigidBody->ComputeWorldData();
|
||||||
integrateForces(*rigidBody, dt);
|
integrateForces(*rigidBody, dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Resolve Contacts
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Integrate Velocities
|
||||||
|
*/
|
||||||
|
|
||||||
for (auto* rigidBody : rigidBodies | std::views::values)
|
for (auto* rigidBody : rigidBodies | std::views::values)
|
||||||
|
{
|
||||||
|
if (!rigidBody->IsActive())
|
||||||
|
continue;
|
||||||
|
|
||||||
integrateVelocities(*rigidBody, dt);
|
integrateVelocities(*rigidBody, dt);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
/* Private Member Functions Definitions */
|
/* Private Member Functions Definitions */
|
||||||
|
@ -262,275 +198,4 @@ namespace SHADE
|
||||||
rigidBody.ClearForces();
|
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
|
} // namespace SHADE
|
|
@ -13,10 +13,8 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
// Project Headers
|
// Project Headers
|
||||||
#include "Physics/Collision/Broadphase/SHDynamicAABBTree.h"
|
#include "Physics/Collision/SHCollisionSpace.h"
|
||||||
#include "Physics/Collision/Contacts/SHCollisionEvents.h"
|
#include "SHContactManager.h"
|
||||||
#include "Physics/Collision/Contacts/SHManifold.h"
|
|
||||||
#include "Physics/Collision/SHCollider.h"
|
|
||||||
#include "SHRigidBody.h"
|
#include "SHRigidBody.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,10 +24,15 @@ namespace SHADE
|
||||||
/* Type Definitions */
|
/* 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
|
class SH_API SHPhysicsWorld
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Type Definitions */
|
/* Type Definitions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
@ -47,9 +50,6 @@ namespace SHADE
|
||||||
bool sleepingEnabled = true;
|
bool sleepingEnabled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
using TriggerEvents = std::vector<SHTriggerEvent>;
|
|
||||||
using CollisionEvents = std::vector<SHCollisionEvent>;
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Constructors & Destructor */
|
/* Constructors & Destructor */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
@ -71,29 +71,44 @@ namespace SHADE
|
||||||
/* Getter Functions */
|
/* 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 */
|
/* 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 AddRigidBody (SHRigidBody* rigidBody) noexcept;
|
||||||
void RemoveRigidBody (SHRigidBody* rigidBody) noexcept;
|
|
||||||
|
|
||||||
void AddCollider (SHCollider* collider) noexcept;
|
|
||||||
void RemoveCollider (SHCollider* collider) noexcept;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Invoke this method to update the broadphase of a collider while the simulation
|
* Removes a rigid body from the world. It's motion will not be affected unless
|
||||||
* is not running.
|
* explicitly modified.
|
||||||
* @param collider
|
* @param rigidBody
|
||||||
* The collider to update.
|
* 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);
|
void Step (float dt);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -101,42 +116,18 @@ namespace SHADE
|
||||||
/* Type Definitions */
|
/* Type Definitions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
struct NarrowphasePair
|
|
||||||
{
|
|
||||||
SHCollisionShape* A = nullptr;
|
|
||||||
SHCollisionShape* B = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
// EntityIDs are used to map resolved contraints back to bodies
|
// EntityIDs are used to map resolved contraints back to bodies
|
||||||
using RigidBodies = std::unordered_map<EntityID, SHRigidBody*>;
|
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 */
|
/* Data Members */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
WorldSettings settings;
|
WorldSettings settings;
|
||||||
|
SHCollisionSpace* collisionSpace;
|
||||||
// Containers
|
|
||||||
|
|
||||||
RigidBodies rigidBodies;
|
RigidBodies rigidBodies;
|
||||||
Colliders colliders;
|
SHContactManager contactManager;
|
||||||
|
|
||||||
NarrowphaseBatch narrowphaseBatch;
|
|
||||||
Manifolds manifolds;
|
|
||||||
Triggers triggers;
|
|
||||||
|
|
||||||
// World components
|
|
||||||
|
|
||||||
SHAABBTree broadphase;
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Function Members */
|
/* Function Members */
|
||||||
|
@ -146,22 +137,8 @@ namespace SHADE
|
||||||
void integrateForces (SHRigidBody& rigidBody, float dt) const noexcept;
|
void integrateForces (SHRigidBody& rigidBody, float dt) const noexcept;
|
||||||
void integrateVelocities (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)];
|
const SHColour& AABB_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::BROADPHASE)];
|
||||||
|
|
||||||
auto& broadphaseAABBs = physicsSystem->GetWorld()->GetBroadphaseAABBs();
|
const auto& BROADPHASE_AABBS = physicsSystem->collisionSpace->GetBroadphaseAABBs();
|
||||||
|
for (auto& aabb : BROADPHASE_AABBS)
|
||||||
for (auto& aabb : broadphaseAABBs)
|
|
||||||
{
|
{
|
||||||
// Compute AABB Transform
|
// Compute AABB Transform
|
||||||
const SHMatrix TRS = SHMatrix::Transform(aabb.GetCenter(), SHQuaternion::Identity, aabb.GetWorldExtents() * 2.0f);
|
const SHMatrix TRS = SHMatrix::Transform(aabb.GetCenter(), SHQuaternion::Identity, aabb.GetWorldExtents() * 2.0f);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
// Project Headers
|
// Project Headers
|
||||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||||
#include "Math/Transform/SHTransformComponent.h"
|
#include "Math/Transform/SHTransformComponent.h"
|
||||||
|
#include "Scene/SHSceneManager.h"
|
||||||
#include "Scripting/SHScriptEngine.h"
|
#include "Scripting/SHScriptEngine.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,15 +51,25 @@ namespace SHADE
|
||||||
const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense<SHRigidBodyComponent>();
|
const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense<SHRigidBodyComponent>();
|
||||||
for (auto& rigidBodyComponent : RIGIDBODY_DENSE)
|
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)
|
if (!transformComponent)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Skip invalid bodies (Should not occur)
|
||||||
if (!rigidBodyComponent.rigidBody)
|
if (!rigidBodyComponent.rigidBody)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Skip inactive bodies
|
||||||
|
const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(EID);
|
||||||
|
if (!IS_ACTIVE)
|
||||||
|
continue;
|
||||||
|
|
||||||
const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState();
|
const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState();
|
||||||
|
|
||||||
|
// Skip objects that have not moved
|
||||||
if (!MOTION_STATE)
|
if (!MOTION_STATE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
// Project Headers
|
// Project Headers
|
||||||
#include "ECS_Base/Managers/SHComponentManager.h"
|
#include "ECS_Base/Managers/SHComponentManager.h"
|
||||||
#include "Math/Transform/SHTransformComponent.h"
|
#include "Math/Transform/SHTransformComponent.h"
|
||||||
|
#include "Scene/SHSceneManager.h"
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
|
@ -40,35 +41,54 @@ namespace SHADE
|
||||||
for (auto& [entityID, physicsObject] : physicsObjects)
|
for (auto& [entityID, physicsObject] : physicsObjects)
|
||||||
{
|
{
|
||||||
const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
|
const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
|
||||||
|
// Assume transform is always active
|
||||||
if (!TRANSFORM_COMPONENT || !TRANSFORM_COMPONENT->HasChanged())
|
const bool UPDATE_TRANSFORM = 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();
|
|
||||||
|
|
||||||
// We assume that all engine components and physics object components have been successfully linked
|
// We assume that all engine components and physics object components have been successfully linked
|
||||||
|
|
||||||
if (physicsObject.rigidBody)
|
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());
|
if (IS_ACTIVE != RIGIDBODY_ACTIVE)
|
||||||
motionState.ForceOrientation(TRANSFORM_COMPONENT->GetWorldOrientation());
|
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)
|
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->SetPosition(WORLD_POS);
|
||||||
physicsObject.collider->SetOrientation(WORLD_ROT);
|
physicsObject.collider->SetOrientation(WORLD_ROT);
|
||||||
physicsObject.collider->SetScale(WORLD_SCL);
|
physicsObject.collider->SetScale(WORLD_SCL);
|
||||||
|
|
||||||
physicsObject.collider->RecomputeShapes();
|
physicsObject.collider->RecomputeShapes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
physicsSystem->physicsWorld->UpdateBroadphase(physicsObject.collider);
|
physicsSystem->collisionSpace->UpdateBroadphase();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace SHADE
|
} // namespace SHADE
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "Editor/SHEditor.h"
|
#include "Editor/SHEditor.h"
|
||||||
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
|
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
|
||||||
#include "Physics/Interface/SHColliderComponent.h"
|
#include "Physics/Interface/SHColliderComponent.h"
|
||||||
|
#include "Scripting/SHScriptEngine.h"
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
|
@ -33,6 +34,7 @@ namespace SHADE
|
||||||
, interpolationFactor { 0.0 }
|
, interpolationFactor { 0.0 }
|
||||||
, fixedDT { DEFAULT_FIXED_STEP }
|
, fixedDT { DEFAULT_FIXED_STEP }
|
||||||
, physicsWorld { nullptr }
|
, physicsWorld { nullptr }
|
||||||
|
, collisionSpace { nullptr }
|
||||||
{
|
{
|
||||||
// Add more events here to register them
|
// Add more events here to register them
|
||||||
|
|
||||||
|
@ -44,6 +46,7 @@ namespace SHADE
|
||||||
|
|
||||||
SHPhysicsSystem::~SHPhysicsSystem() noexcept
|
SHPhysicsSystem::~SHPhysicsSystem() noexcept
|
||||||
{
|
{
|
||||||
|
delete collisionSpace;
|
||||||
delete physicsWorld;
|
delete physicsWorld;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,11 +54,6 @@ namespace SHADE
|
||||||
/* Getter Function Definitions */
|
/* Getter Function Definitions */
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
const SHPhysicsWorld* SHPhysicsSystem::GetWorld() const noexcept
|
|
||||||
{
|
|
||||||
return physicsWorld;
|
|
||||||
}
|
|
||||||
|
|
||||||
double SHPhysicsSystem::GetFixedUpdateRate() const noexcept
|
double SHPhysicsSystem::GetFixedUpdateRate() const noexcept
|
||||||
{
|
{
|
||||||
return 1.0 / fixedDT;
|
return 1.0 / fixedDT;
|
||||||
|
@ -66,6 +64,16 @@ namespace SHADE
|
||||||
return fixedDT;
|
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 */
|
/* Setter Function Definitions */
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
@ -137,7 +145,48 @@ namespace SHADE
|
||||||
|
|
||||||
void SHPhysicsSystem::ForceUpdate()
|
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)
|
if (PHYSICS_OBJECT.rigidBody)
|
||||||
physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody);
|
physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody);
|
||||||
|
|
||||||
if (PHYSICS_OBJECT.collider)
|
|
||||||
physicsWorld->RemoveCollider(PHYSICS_OBJECT.collider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete physicsWorld;
|
delete physicsWorld;
|
||||||
physicsWorld = nullptr;
|
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;
|
physicsWorld = new SHPhysicsWorld;
|
||||||
|
collisionSpace = new SHCollisionSpace;
|
||||||
|
|
||||||
|
physicsWorld->SetCollisionSpace(collisionSpace);
|
||||||
|
|
||||||
// Immediately add all existing bodies and colliders to the world.
|
// 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.
|
// 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);
|
physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody);
|
||||||
|
|
||||||
if (PHYSICS_OBJECT.collider)
|
if (PHYSICS_OBJECT.collider)
|
||||||
physicsWorld->AddCollider(PHYSICS_OBJECT.collider);
|
collisionSpace->AddCollider(PHYSICS_OBJECT.collider);
|
||||||
}
|
}
|
||||||
|
|
||||||
return onSceneInitEvent.get()->handle;
|
return onSceneInitEvent.get()->handle;
|
||||||
|
@ -203,9 +264,12 @@ namespace SHADE
|
||||||
physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody);
|
physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody);
|
||||||
|
|
||||||
if (PHYSICS_OBJECT.collider)
|
if (PHYSICS_OBJECT.collider)
|
||||||
physicsWorld->RemoveCollider(PHYSICS_OBJECT.collider);
|
collisionSpace->RemoveCollider(PHYSICS_OBJECT.collider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete collisionSpace;
|
||||||
|
collisionSpace = nullptr;
|
||||||
|
|
||||||
delete physicsWorld;
|
delete physicsWorld;
|
||||||
physicsWorld = nullptr;
|
physicsWorld = nullptr;
|
||||||
|
|
||||||
|
@ -247,10 +311,10 @@ namespace SHADE
|
||||||
{
|
{
|
||||||
physicsObjectManager.AddCollider(EID);
|
physicsObjectManager.AddCollider(EID);
|
||||||
|
|
||||||
if (physicsWorld)
|
if (collisionSpace)
|
||||||
{
|
{
|
||||||
auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider;
|
auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider;
|
||||||
physicsWorld->AddCollider(collider);
|
collisionSpace->AddCollider(collider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,16 +353,15 @@ namespace SHADE
|
||||||
|
|
||||||
if (IS_COLLIDER)
|
if (IS_COLLIDER)
|
||||||
{
|
{
|
||||||
if (physicsWorld)
|
if (collisionSpace)
|
||||||
{
|
{
|
||||||
auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider;
|
auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider;
|
||||||
physicsWorld->RemoveCollider(collider);
|
collisionSpace->RemoveCollider(collider);
|
||||||
}
|
}
|
||||||
|
|
||||||
physicsObjectManager.RemoveCollider(EID);
|
physicsObjectManager.RemoveCollider(EID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return onComponentRemovedEvent.get()->handle;
|
return onComponentRemovedEvent.get()->handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,13 @@ namespace SHADE
|
||||||
*/
|
*/
|
||||||
class SH_API SHPhysicsSystem final : public SHSystem
|
class SH_API SHPhysicsSystem final : public SHSystem
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Friends */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
friend class SHPhysicsDebugDrawSystem;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Constructors & Destructor */
|
/* Constructors & Destructor */
|
||||||
|
@ -45,7 +52,6 @@ namespace SHADE
|
||||||
/* Getter Functions */
|
/* Getter Functions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
[[nodiscard]] const SHPhysicsWorld* GetWorld () const noexcept;
|
|
||||||
[[nodiscard]] double GetFixedUpdateRate() const noexcept;
|
[[nodiscard]] double GetFixedUpdateRate() const noexcept;
|
||||||
[[nodiscard]] double GetFixedDT () const noexcept;
|
[[nodiscard]] double GetFixedDT () const noexcept;
|
||||||
|
|
||||||
|
@ -56,6 +62,9 @@ namespace SHADE
|
||||||
void SetFixedUpdateRate(double fixedUpdateRate) noexcept;
|
void SetFixedUpdateRate(double fixedUpdateRate) noexcept;
|
||||||
void SetFixedDT(double fixedDt) noexcept;
|
void SetFixedDT(double fixedDt) noexcept;
|
||||||
|
|
||||||
|
const std::vector<SHTriggerEvent>& GetTriggerInfo () const noexcept;
|
||||||
|
const std::vector<SHCollisionEvent>& GetCollisionInfo () const noexcept;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Member Functions */
|
/* Member Functions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
@ -137,6 +146,7 @@ namespace SHADE
|
||||||
// Sub-systems / managers
|
// Sub-systems / managers
|
||||||
|
|
||||||
SHPhysicsWorld* physicsWorld;
|
SHPhysicsWorld* physicsWorld;
|
||||||
|
SHCollisionSpace* collisionSpace;
|
||||||
SHPhysicsObjectManager physicsObjectManager;
|
SHPhysicsObjectManager physicsObjectManager;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
/************************************************************************************//*!
|
/************************************************************************************//*!
|
||||||
\file SHPhysicsSystemInterface.cpp
|
\file SHPhysicsSystemInterface.cpp
|
||||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
\author Diren D Bharwani, diren.dbharwani, 390002520
|
||||||
\par email: kahwei.tng\@digipen.edu
|
|
||||||
\date Oct 31, 2022
|
|
||||||
\brief Contains the definitions of the functions of the static
|
\brief Contains the definitions of the functions of the static
|
||||||
SHPhysicsSystemInterface class.
|
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
|
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||||
of DigiPen Institute of Technology is prohibited.
|
of DigiPen Institute of Technology is prohibited.
|
||||||
*//*************************************************************************************/
|
*//*************************************************************************************/
|
||||||
// Precompiled Headers
|
|
||||||
|
|
||||||
#include "SHpch.h"
|
#include "SHpch.h"
|
||||||
|
|
||||||
// Primary Header
|
// Primary Header
|
||||||
#include "SHPhysicsSystemInterface.h"
|
#include "SHPhysicsSystemInterface.h"
|
||||||
|
|
||||||
// Project Includes
|
// Project Includes
|
||||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||||
#include "Physics/System/SHPhysicsSystem.h"
|
#include "Physics/System/SHPhysicsSystem.h"
|
||||||
|
@ -23,42 +24,47 @@ namespace SHADE
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
/* Static Usage Functions */
|
/* 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>();
|
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
|
||||||
//if (phySystem)
|
if (physicsSystem)
|
||||||
//{
|
return physicsSystem->GetCollisionInfo();
|
||||||
// return phySystem->GetAllCollisionInfo();
|
|
||||||
//}
|
|
||||||
|
|
||||||
//SHLOGV_WARNING("Failed to get collision events. Empty vector returned instead.");
|
SHLOGV_WARNING("Failed to get collision events. Empty vector returned instead.");
|
||||||
return emptyVec;
|
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>();
|
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
|
||||||
//if (phySystem)
|
if (physicsSystem)
|
||||||
//{
|
return physicsSystem->GetTriggerInfo();
|
||||||
// return phySystem->GetAllTriggerInfo();
|
|
||||||
//}
|
|
||||||
|
|
||||||
//SHLOGV_WARNING("Failed to get trigger events. Empty vector returned instead.");
|
SHLOGV_WARNING("Failed to get trigger events. Empty vector returned instead.");
|
||||||
return emptyVec;
|
return emptyVec;
|
||||||
}
|
}
|
||||||
|
|
||||||
double SHPhysicsSystemInterface::GetFixedDT() noexcept
|
double SHPhysicsSystemInterface::GetFixedDT() noexcept
|
||||||
{
|
{
|
||||||
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
|
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
|
||||||
if (phySystem)
|
if (physicsSystem)
|
||||||
{
|
return physicsSystem->GetFixedDT();
|
||||||
return 1.0 / phySystem->GetFixedUpdateRate();
|
|
||||||
}
|
|
||||||
|
|
||||||
SHLOGV_WARNING("Failed to get fixed delta time. 0.0 returned instead.");
|
SHLOGV_WARNING("Failed to get fixed delta time. 0.0 returned instead.");
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
\file SHPhysicsSystemInterface.h
|
||||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
\author Diren D Bharwani, diren.dbharwani, 390002520
|
||||||
\par email: kahwei.tng\@digipen.edu
|
|
||||||
\date Oct 31, 2022
|
|
||||||
\brief Contains the definition of the SHGraphicsSystemInterface static class.
|
\brief Contains the definition of the SHGraphicsSystemInterface static class.
|
||||||
|
|
||||||
Copyright (C) 2022 DigiPen Institute of Technology.
|
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||||
of DigiPen Institute of Technology is prohibited.
|
of DigiPen Institute of Technology is prohibited.
|
||||||
*//*************************************************************************************/
|
*//*************************************************************************************/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// STL Includes
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// Project Headers
|
// Project Headers
|
||||||
#include "ECS_Base/Entity/SHEntity.h"
|
#include "ECS_Base/Entity/SHEntity.h"
|
||||||
#include "Physics/Collision/SHCollisionInfo.h"
|
#include "Physics/Collision/Contacts/SHCollisionEvents.h"
|
||||||
|
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
|
@ -49,8 +47,8 @@ namespace SHADE
|
||||||
/* Static Usage Functions */
|
/* Static Usage Functions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
[[nodiscard]] static const std::vector<SHCollisionInfo>& GetCollisionInfo () noexcept;
|
[[nodiscard]] static const std::vector<SHCollisionEvent>& GetCollisionInfo () noexcept;
|
||||||
[[nodiscard]] static const std::vector<SHCollisionInfo>& GetTriggerInfo () noexcept;
|
[[nodiscard]] static const std::vector<SHTriggerEvent>& GetTriggerInfo () noexcept;
|
||||||
[[nodiscard]] static double GetFixedDT () noexcept;
|
[[nodiscard]] static double GetFixedDT () noexcept;
|
||||||
[[nodiscard]] static int GetFixedUpdateRate () noexcept;
|
[[nodiscard]] static int GetFixedUpdateRate () noexcept;
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,7 +30,6 @@ of DigiPen Institute of Technology is prohibited.
|
||||||
#include "Engine/Application.hxx"
|
#include "Engine/Application.hxx"
|
||||||
#include "Physics/System/SHPhysicsSystemInterface.h"
|
#include "Physics/System/SHPhysicsSystemInterface.h"
|
||||||
#include "Physics/SHPhysicsEvents.h"
|
#include "Physics/SHPhysicsEvents.h"
|
||||||
#include "Physics/Collision/SHCollisionInfo.h"
|
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
|
@ -605,8 +604,8 @@ namespace SHADE
|
||||||
{
|
{
|
||||||
auto entities =
|
auto entities =
|
||||||
{
|
{
|
||||||
std::make_pair(collisionInfo.GetEntityA(), collisionInfo.GetEntityB()),
|
std::make_pair(collisionInfo.info.GetEntityA(), collisionInfo.info.GetEntityB()),
|
||||||
std::make_pair(collisionInfo.GetEntityB(), collisionInfo.GetEntityA())
|
std::make_pair(collisionInfo.info.GetEntityB(), collisionInfo.info.GetEntityA())
|
||||||
};
|
};
|
||||||
for (auto entity : entities)
|
for (auto entity : entities)
|
||||||
{
|
{
|
||||||
|
@ -625,15 +624,15 @@ namespace SHADE
|
||||||
for (int i = 0; i < entityScripts->Count; ++i)
|
for (int i = 0; i < entityScripts->Count; ++i)
|
||||||
{
|
{
|
||||||
Script^ script = entityScripts[i];
|
Script^ script = entityScripts[i];
|
||||||
switch (collisionInfo.GetCollisionState())
|
switch (collisionInfo.state)
|
||||||
{
|
{
|
||||||
case SHCollisionInfo::State::ENTER:
|
case SHCollisionState::ENTER:
|
||||||
script->OnCollisionEnter(info);
|
script->OnCollisionEnter(info);
|
||||||
break;
|
break;
|
||||||
case SHCollisionInfo::State::STAY:
|
case SHCollisionState::STAY:
|
||||||
script->OnCollisionStay(info);
|
script->OnCollisionStay(info);
|
||||||
break;
|
break;
|
||||||
case SHCollisionInfo::State::EXIT:
|
case SHCollisionState::EXIT:
|
||||||
script->OnCollisionExit(info);
|
script->OnCollisionExit(info);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -647,8 +646,8 @@ namespace SHADE
|
||||||
{
|
{
|
||||||
auto entities =
|
auto entities =
|
||||||
{
|
{
|
||||||
std::make_pair(triggerInfo.GetEntityA(), triggerInfo.GetEntityB()),
|
std::make_pair(triggerInfo.info.GetEntityA(), triggerInfo.info.GetEntityB()),
|
||||||
std::make_pair(triggerInfo.GetEntityB(), triggerInfo.GetEntityA())
|
std::make_pair(triggerInfo.info.GetEntityB(), triggerInfo.info.GetEntityA())
|
||||||
};
|
};
|
||||||
for (auto entity : entities)
|
for (auto entity : entities)
|
||||||
{
|
{
|
||||||
|
@ -667,15 +666,15 @@ namespace SHADE
|
||||||
for (int i = 0; i < entityScripts->Count; ++i)
|
for (int i = 0; i < entityScripts->Count; ++i)
|
||||||
{
|
{
|
||||||
Script^ script = entityScripts[i];
|
Script^ script = entityScripts[i];
|
||||||
switch (triggerInfo.GetCollisionState())
|
switch (triggerInfo.state)
|
||||||
{
|
{
|
||||||
case SHCollisionInfo::State::ENTER:
|
case SHCollisionState::ENTER:
|
||||||
script->OnTriggerEnter(info);
|
script->OnTriggerEnter(info);
|
||||||
break;
|
break;
|
||||||
case SHCollisionInfo::State::STAY:
|
case SHCollisionState::STAY:
|
||||||
script->OnTriggerStay(info);
|
script->OnTriggerStay(info);
|
||||||
break;
|
break;
|
||||||
case SHCollisionInfo::State::EXIT:
|
case SHCollisionState::EXIT:
|
||||||
script->OnTriggerExit(info);
|
script->OnTriggerExit(info);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue