diff --git a/SHADE_Engine/src/Math/SHMathHelpers.h b/SHADE_Engine/src/Math/SHMathHelpers.h index 427011a6..b053beff 100644 --- a/SHADE_Engine/src/Math/SHMathHelpers.h +++ b/SHADE_Engine/src/Math/SHMathHelpers.h @@ -46,14 +46,16 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /** Standard Epsilon value for comparing Single-Precision Floating-Point values. */ - static constexpr float EPSILON = 0.001f; + static constexpr float EPSILON = 0.001f; /** Single-Precision Floating-Point value of infinity */ - static constexpr float INF = std::numeric_limits::infinity(); + static constexpr float INF = std::numeric_limits::infinity(); - static constexpr float PI = std::numbers::pi_v; - static constexpr float HALF_PI = PI * 0.5f; - static constexpr float TWO_PI = 2.0f * PI; + static constexpr float PI = std::numbers::pi_v; + static constexpr float HALF_PI = PI * 0.5f; + static constexpr float TWO_PI = 2.0f * PI; + + static constexpr float EULER_CONSTANT = std::numbers::egamma_v; /*---------------------------------------------------------------------------------*/ /* Static Function Members */ diff --git a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h index f23fd946..420f30e7 100644 --- a/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h +++ b/SHADE_Engine/src/Physics/Collision/Broadphase/SHDynamicAABBTree.h @@ -122,7 +122,7 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - static constexpr float AABB_EXTENSION = 0.1f; + static constexpr float AABB_EXTENSION = 0.2f; // For quick access std::unordered_map nodeMap; diff --git a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h index dad59881..6e779eea 100644 --- a/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h +++ b/SHADE_Engine/src/Physics/Collision/CollisionShapes/SHCollisionShape.h @@ -37,7 +37,7 @@ namespace SHADE friend class SHCollider; friend class SHColliderComponent; friend class SHCollisionShapeFactory; - friend class SHPhysicsWorld; + friend class SHCollisionSpace; public: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp index 24ba26b7..928945c9 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.cpp @@ -29,6 +29,7 @@ namespace SHADE SHCollider::SHCollider(EntityID eid, const SHTransform& worldTransform) noexcept : entityID { eid } + , active { true } , debugDraw { false } , hasMoved { true } , rigidBody { nullptr } @@ -39,6 +40,7 @@ namespace SHADE SHCollider::SHCollider(const SHCollider& rhs) noexcept : entityID { rhs.entityID } + , active { rhs.active } , debugDraw { rhs.debugDraw } , hasMoved { rhs.hasMoved } , rigidBody { rhs.rigidBody } @@ -57,6 +59,7 @@ namespace SHADE SHCollider::SHCollider(SHCollider&& rhs) noexcept : entityID { rhs.entityID } + , active { rhs.active } , debugDraw { rhs.debugDraw } , hasMoved { rhs.hasMoved } , rigidBody { rhs.rigidBody } @@ -101,6 +104,7 @@ namespace SHADE } entityID = rhs.entityID; + active = rhs.active; debugDraw = rhs.debugDraw; hasMoved = rhs.hasMoved; rigidBody = rhs.rigidBody; @@ -122,6 +126,7 @@ namespace SHADE } entityID = rhs.entityID; + active = rhs.active; debugDraw = rhs.debugDraw; hasMoved = rhs.hasMoved; rigidBody = rhs.rigidBody; @@ -138,6 +143,16 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ + EntityID SHCollider::GetEntityID() const noexcept + { + return entityID; + } + + bool SHCollider::IsActive() const noexcept + { + return active; + } + bool SHCollider::GetDebugDrawState() const noexcept { return debugDraw; @@ -182,6 +197,25 @@ namespace SHADE /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ + void SHCollider::SetIsActive(bool state) noexcept + { + if (active == state) + return; + + active = state; + + if (!broadphase) + return; + + for (auto* shape : shapes) + { + if (active) // Previously inactive + broadphase->Insert(shape->id, shape->ComputeAABB()); + else // Previously active + broadphase->Remove(shape->id); + } + } + void SHCollider::SetDebugDrawState(bool state) noexcept { debugDraw = state; diff --git a/SHADE_Engine/src/Physics/Collision/SHCollider.h b/SHADE_Engine/src/Physics/Collision/SHCollider.h index 89ba5ff2..c31be5eb 100644 --- a/SHADE_Engine/src/Physics/Collision/SHCollider.h +++ b/SHADE_Engine/src/Physics/Collision/SHCollider.h @@ -40,7 +40,7 @@ namespace SHADE /* Friends */ /*---------------------------------------------------------------------------------*/ - friend class SHPhysicsWorld; + friend class SHCollisionSpace; public: /*---------------------------------------------------------------------------------*/ @@ -79,6 +79,8 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ + [[nodiscard]] EntityID GetEntityID () const noexcept; + [[nodiscard]] bool IsActive () const noexcept; [[nodiscard]] bool GetDebugDrawState () const noexcept; [[nodiscard]] const SHTransform& GetTransform () const noexcept; @@ -93,6 +95,7 @@ namespace SHADE /* Setter Functions */ /*---------------------------------------------------------------------------------*/ + void SetIsActive (bool state) noexcept; void SetDebugDrawState (bool state) noexcept; void SetRigidBody (SHRigidBody* rb) noexcept; @@ -157,6 +160,7 @@ namespace SHADE EntityID entityID; + bool active; bool debugDraw; bool hasMoved; diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp deleted file mode 100644 index a28686e0..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.cpp +++ /dev/null @@ -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 - -// 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::max(); - ids[COLLIDER_B] = std::numeric_limits::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::max(); - ids[COLLIDER_B] = std::numeric_limits::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(ids[ENTITY_A]); - } - - const SHRigidBodyComponent* SHCollisionInfo::GetRigidBodyB() const noexcept - { - return SHComponentManager::GetComponent_s(ids[ENTITY_B]); - } - - const SHCollisionShape* SHCollisionInfo::GetColliderA() const noexcept - { - const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent(ids[ENTITY_A]); - return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[COLLIDER_A]); - } - - const SHCollisionShape* SHCollisionInfo::GetColliderB() const noexcept - { - const auto* COLLIDER_COMPONENT = SHComponentManager::GetComponent(ids[ENTITY_B]); - return COLLIDER_COMPONENT->GetCollider()->GetCollisionShape(ids[COLLIDER_B]); - } - - SHCollisionInfo::State SHCollisionInfo::GetCollisionState() const noexcept - { - return collisionState; - } - -} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h b/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h deleted file mode 100644 index d2dad647..00000000 --- a/SHADE_Engine/src/Physics/Collision/SHCollisionInfo.h +++ /dev/null @@ -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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp new file mode 100644 index 00000000..bc76d14a --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.cpp @@ -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 + +// 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(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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h new file mode 100644 index 00000000..d89404dd --- /dev/null +++ b/SHADE_Engine/src/Physics/Collision/SHCollisionSpace.h @@ -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; + using NarrowphaseBatch = std::unordered_map; + + /*---------------------------------------------------------------------------------*/ + /* 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp new file mode 100644 index 00000000..be65128d --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.cpp @@ -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 + +// 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h new file mode 100644 index 00000000..06a03a6a --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.h @@ -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 + +// 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; + using CollisionEvents = std::vector; + + /*---------------------------------------------------------------------------------*/ + /* 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; + using Triggers = std::unordered_map; + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + Manifolds manifolds; + Triggers triggers; + + /*---------------------------------------------------------------------------------*/ + /* Member Functions */ + /*---------------------------------------------------------------------------------*/ + + void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept; + + // Removal Helpers + + template + void remove (std::unordered_map& container, EntityID eid); + template + void remove (std::unordered_map& container, EntityID eid, uint32_t shapeIndex); + + }; + + +} // namespace SHADE + +#include "SHContactManager.hpp" \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHContactManager.hpp b/SHADE_Engine/src/Physics/Dynamics/SHContactManager.hpp new file mode 100644 index 00000000..1403cd79 --- /dev/null +++ b/SHADE_Engine/src/Physics/Dynamics/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 + void SHContactManager::remove(std::unordered_map& 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 + void SHContactManager::remove(std::unordered_map& 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 \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp index 8d0b69f8..b5dba378 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.cpp @@ -13,11 +13,6 @@ // Primary Header #include "SHPhysicsWorld.h" -// Project Headers -#include "Physics/Collision/Narrowphase/SHCollision.h" -#include "Physics/Collision/Narrowphase/SHCollisionDispatch.h" - - namespace SHADE { /*-----------------------------------------------------------------------------------*/ @@ -25,59 +20,39 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ SHPhysicsWorld::SHPhysicsWorld(const WorldSettings& worldSettings) noexcept - : settings { worldSettings } + : settings { worldSettings } + , collisionSpace { nullptr } { SHLOG_INFO_D("Creating Physics World") } SHPhysicsWorld::~SHPhysicsWorld() noexcept { - + collisionSpace = nullptr; } /*-----------------------------------------------------------------------------------*/ /* Getter Functions Definitions */ /*-----------------------------------------------------------------------------------*/ - const SHAABBTree::AABBs& SHPhysicsWorld::GetBroadphaseAABBs() const noexcept + const SHContactManager::TriggerEvents& SHPhysicsWorld::GetTriggerEvents() const noexcept { - return broadphase.GetAABBs(); + return contactManager.GetTriggerEvents(); } - const SHPhysicsWorld::TriggerEvents& SHPhysicsWorld::GetTriggerEvents() const noexcept + const SHContactManager::CollisionEvents& SHPhysicsWorld::GetCollisionEvents() const noexcept { - static TriggerEvents triggerEvents; - - triggerEvents.clear(); - - for (auto& [id, state] : triggers) - triggerEvents.emplace_back(SHTriggerEvent{ id, state }); - - return triggerEvents; + return contactManager.GetCollisionEvents(); } - const SHPhysicsWorld::CollisionEvents& SHPhysicsWorld::GetCollisionEvents() const noexcept + /*-----------------------------------------------------------------------------------*/ + /* Setter Functions Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsWorld::SetCollisionSpace(SHCollisionSpace* _collisionSpace) noexcept { - static CollisionEvents collisionEvents; - - collisionEvents.clear(); - - for (auto& [id, manifold] : manifolds) - { - SHCollisionEvent collisionEvent - { - .info = id - , .state = manifold.state - , .normal = manifold.normal - }; - - for (uint32_t i = 0; i < manifold.numContacts; ++i) - collisionEvent.contactPoints[i] = manifold.contacts[i].position; - - collisionEvents.emplace_back(collisionEvent); - } - - return collisionEvents; + collisionSpace = _collisionSpace; + _collisionSpace->SetContactManager(&contactManager); } /*-----------------------------------------------------------------------------------*/ @@ -97,93 +72,54 @@ namespace SHADE { rigidBodies.erase(rigidBody->entityID); - // Attempt to remove any invalidated manifolds - if (manifolds.empty()) - return; - - for (auto manifoldPair = manifolds.begin(); manifoldPair != manifolds.end();) - { - const auto& ID = manifoldPair->first; - - const bool MATCHES_A = ID.GetEntityA() == rigidBody->entityID; - const bool MATCHES_B = ID.GetEntityB() == rigidBody->entityID; - - if (MATCHES_A || MATCHES_B) - manifoldPair = manifolds.erase(manifoldPair); - else - ++manifoldPair; - } + // Contact manager to remove invalidated contacts + contactManager.RemoveInvalidatedManifold(rigidBody->entityID); // TODO: Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep } - void SHPhysicsWorld::AddCollider(SHCollider* collider) noexcept - { - const bool INSERTED = colliders.emplace(collider->entityID, collider).second; - if (!INSERTED) - { - SHLOG_WARNING_D("Attempting to add duplicate collider {} to the Physics World!", collider->entityID) - return; - } - - collider->broadphase = &broadphase; - - // Add all existing shapes to the broadphase - for (const auto* shape : collider->shapes) - broadphase.Insert(shape->id, shape->ComputeAABB()); - } - - void SHPhysicsWorld::RemoveCollider(SHCollider* collider) noexcept - { - colliders.erase(collider->entityID); - - const uint32_t NUM_SHAPES = static_cast(collider->shapes.size()); - if (NUM_SHAPES == 0) - return; - - for (uint32_t i = 0; i < NUM_SHAPES; ++i) - { - const SHCollisionShape* SHAPE = collider->shapes[i]; - - broadphase.Remove(SHAPE->id); - - if (SHAPE->IsTrigger()) - removeInvalidatedTrigger(collider->entityID, i); - else - removeInvalidatedManifold(collider->entityID, i); - } - - /* - * TODO: - * Get collider's rigid body - * Run through the rigid body's contact graph and wake all of its non-static bodies that are asleep - */ - } - - void SHPhysicsWorld::UpdateBroadphase(SHCollider* collider) noexcept - { - auto& shapes = collider->GetCollisionShapes(); - for (auto* shape : shapes) - broadphase.Update(shape->id, shape->ComputeAABB()); - } void SHPhysicsWorld::Step(float dt) { - // Clear containers of exit state collisions - updateEvents(); + // Contact manager to clear expired contacts + contactManager.Update(); - // TODO: Profile each of these - runBroadphase (); - runNarrowphase(); + /* + * Detect Collisions + */ + + if (collisionSpace) + collisionSpace->DetectCollisions(); + + /* + * Integrate Forces + */ for (auto* rigidBody : rigidBodies | std::views::values) { + if (!rigidBody->IsActive()) + continue; + rigidBody->ComputeWorldData(); integrateForces(*rigidBody, dt); } + + /* + * TODO: Resolve Contacts + */ + + /* + * Integrate Velocities + */ + for (auto* rigidBody : rigidBodies | std::views::values) + { + if (!rigidBody->IsActive()) + continue; + integrateVelocities(*rigidBody, dt); + } } /*-----------------------------------------------------------------------------------*/ @@ -262,275 +198,4 @@ namespace SHADE rigidBody.ClearForces(); } - void SHPhysicsWorld::runBroadphase() noexcept - { - // Update any colliders that have moved - for (auto& collider : colliders | std::views::values) - { - if (!collider->hasMoved) - continue; - - // Clear hasMoved flag here - collider->hasMoved = false; - - // Update moved shapes in broadphase - for (auto* shape : collider->shapes) - broadphase.Update(shape->id, shape->ComputeAABB()); - } - - // Query: Kinematic Triggers, Awake Dynamic Bodies & Dynamic Triggers - for (auto& collider : colliders | std::views::values) - { - // Default static bodies - if (!collider->rigidBody) - continue; - - // Explicit static bodies - const bool IS_STATIC = collider->rigidBody->GetType() == SHRigidBody::Type::STATIC; - if (IS_STATIC) - continue; - - // All remaining are kinematic or dynamic - // Iterate through shapes: if kinematic / dynamic trigger, else if dynamic & awake - if (collider->rigidBody->GetType() == SHRigidBody::Type::KINEMATIC) - queryKinematic(collider); - - if (collider->rigidBody->GetType() == SHRigidBody::Type::DYNAMIC) - queryDynamic(collider); - } - - } - - void SHPhysicsWorld::queryKinematic(SHCollider* collider) noexcept - { - for (auto* shape : collider->shapes) - { - // For kinematic shapes, we only query triggers against everything else - if (!shape->IsTrigger()) - continue; - - auto& potentialCollisions = broadphase.Query(shape->id, shape->ComputeAABB()); - - // Build narrow-phase pairs - auto* shapeA = shape; - - const EntityID ID_A = shape->id.GetEntityID(); - const uint32_t INDEX_A = shape->id.GetShapeIndex(); - - for (auto& id : potentialCollisions) - { - // Get corresponding shape - const EntityID ID_B = id.GetEntityID(); - const uint32_t INDEX_B = id.GetShapeIndex(); - - auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B); - - // Build collision ID - SHCollisionKey collisionKey; - collisionKey.SetEntityA(ID_A); - collisionKey.SetEntityB(ID_B); - collisionKey.SetCollisionShapeA(INDEX_A); - collisionKey.SetCollisionShapeB(INDEX_B); - - // Check if it already exists. If it doesn't, put into batch. - auto narrowphasePair = narrowphaseBatch.find(collisionKey); - if (narrowphasePair == narrowphaseBatch.end()) - narrowphaseBatch.emplace(collisionKey, NarrowphasePair{ shapeA, shapeB }); - } - } - } - - void SHPhysicsWorld::queryDynamic(SHCollider* collider) noexcept - { - for (auto* shape : collider->shapes) - { - auto& potentialCollisions = broadphase.Query(shape->id, shape->ComputeAABB()); - - // Build narrow-phase pairs - auto* shapeA = shape; - - const EntityID ID_A = shape->id.GetEntityID(); - const uint32_t INDEX_A = shape->id.GetShapeIndex(); - - for (auto& id : potentialCollisions) - { - // Get corresponding shape - const EntityID ID_B = id.GetEntityID(); - const uint32_t INDEX_B = id.GetShapeIndex(); - - auto* shapeB = colliders[ID_B]->GetCollisionShape(INDEX_B); - - // Build collision ID - SHCollisionKey collisionKey; - collisionKey.SetEntityA(ID_A); - collisionKey.SetEntityB(ID_B); - collisionKey.SetCollisionShapeA(INDEX_A); - collisionKey.SetCollisionShapeB(INDEX_B); - - // Check if it already exists. If it doesn't, put into batch. - auto narrowphasePair = narrowphaseBatch.find(collisionKey); - if (narrowphasePair == narrowphaseBatch.end()) - narrowphaseBatch.emplace(collisionKey, NarrowphasePair{ shapeA, shapeB }); - } - } - } - - void SHPhysicsWorld::runNarrowphase() noexcept - { - if (narrowphaseBatch.empty()) - return; - - for (auto& [id, narrowphasePair] : narrowphaseBatch) - { - const bool IS_A_TRIGGER = narrowphasePair.A->IsTrigger(); - const bool IS_B_TRIGGER = narrowphasePair.B->IsTrigger(); - - // Check if ID exists in trigger - if (IS_A_TRIGGER || IS_B_TRIGGER) - collideTriggers(id, narrowphasePair); - else - collideManifolds(id, narrowphasePair); - } - - // Clear every frame - narrowphaseBatch.clear(); - } - - void SHPhysicsWorld::collideTriggers(const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept - { - const auto* A = narrowphasePair.A; - const auto* B = narrowphasePair.B; - - const bool COLLIDING = SHCollisionDispatcher::Collide(*A, *B); - - auto trigger = triggers.find(id); - - // If id not found, emplace new object. - // New object is in the invalid state - if (trigger == triggers.end()) - trigger = triggers.emplace(id, SHCollisionState::INVALID).first; - - SHCollisionState& state = trigger->second; - updateCollisionState(COLLIDING, state); - - // If it was a false positive, remove the manifold immediately. - // Remove using iterator as it is on average faster. - if (state == SHCollisionState::INVALID) - trigger = triggers.erase(trigger); - } - - void SHPhysicsWorld::collideManifolds(const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept - { - auto* A = narrowphasePair.A; - auto* B = narrowphasePair.B; - - SHManifold newManifold { .A = A, .B = B }; - const bool COLLIDING = SHCollisionDispatcher::Collide(newManifold, *A, *B); - - auto manifold = manifolds.find(id); - - // If id not found, emplace new manifold - if (manifold == manifolds.end()) - manifold = manifolds.emplace(id, newManifold).first; - else - { - // TODO: Update existing manifolds with new data - } - - SHCollisionState& state = manifold->second.state; - updateCollisionState(COLLIDING, state); - - // If it was a false positive, remove the manifold immediately. - // Remove using iterator as it is on average faster. - if (state == SHCollisionState::INVALID) - manifold = manifolds.erase(manifold); - } - - void SHPhysicsWorld::updateCollisionState(bool isColliding, SHCollisionState& state) noexcept - { - if (isColliding) - { - // New states start at invalid. In the first frame of collision, move to enter. - // If it already in enter, move to stay - state = state == SHCollisionState::INVALID ? SHCollisionState::ENTER : SHCollisionState::STAY; - } - else - { - // New states start at invalid. In false positive, remain unchanged. - // If previously colliding, move to exit. - state = state == SHCollisionState::INVALID ? SHCollisionState::INVALID : SHCollisionState::EXIT; - } - } - - void SHPhysicsWorld::updateEvents() noexcept - { - // Clear expired or invalid collisions - for (auto manifold = manifolds.begin(); manifold != manifolds.end();) - { - const auto COLLISION_STATE = manifold->second.state; - - const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT; - const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID; - - if (IS_EXIT || IS_INVALID) - manifold = manifolds.erase(manifold); - else - ++manifold; - } - - // Clear expired or invalid triggers - for (auto trigger = triggers.begin(); trigger != triggers.end();) - { - const auto COLLISION_STATE = trigger->second; - - const bool IS_EXIT = COLLISION_STATE == SHCollisionState::EXIT; - const bool IS_INVALID = COLLISION_STATE == SHCollisionState::INVALID; - - if (IS_EXIT || IS_INVALID) - trigger = triggers.erase(trigger); - else - ++trigger; - } - } - - void SHPhysicsWorld::removeInvalidatedTrigger(EntityID eid, uint32_t shapeIndex) - { - if (triggers.empty()) - return; - - for (auto invalidatedTrigger = triggers.begin(); invalidatedTrigger != triggers.end();) - { - const auto& ID = invalidatedTrigger->first; - - const bool MATCHES_A = ID.GetEntityA() == eid && ID.GetShapeIndexA() == shapeIndex; - const bool MATCHES_B = ID.GetEntityB() == eid && ID.GetShapeIndexB() == shapeIndex; - - if (MATCHES_A || MATCHES_B) - invalidatedTrigger = triggers.erase(invalidatedTrigger); - else - ++invalidatedTrigger; - } - } - - void SHPhysicsWorld::removeInvalidatedManifold(EntityID eid, uint32_t shapeIndex) - { - if (manifolds.empty()) - return; - - for (auto invalidatedManifold = manifolds.begin(); invalidatedManifold != manifolds.end();) - { - const auto& ID = invalidatedManifold->first; - - const bool MATCHES_A = ID.GetEntityA() == eid && ID.GetShapeIndexA() == shapeIndex; - const bool MATCHES_B = ID.GetEntityB() == eid && ID.GetShapeIndexB() == shapeIndex; - - if (MATCHES_A || MATCHES_B) - invalidatedManifold = manifolds.erase(invalidatedManifold); - else - ++invalidatedManifold; - } - } - - - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h index a0743a30..8248299a 100644 --- a/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h +++ b/SHADE_Engine/src/Physics/Dynamics/SHPhysicsWorld.h @@ -13,10 +13,8 @@ #include // Project Headers -#include "Physics/Collision/Broadphase/SHDynamicAABBTree.h" -#include "Physics/Collision/Contacts/SHCollisionEvents.h" -#include "Physics/Collision/Contacts/SHManifold.h" -#include "Physics/Collision/SHCollider.h" +#include "Physics/Collision/SHCollisionSpace.h" +#include "SHContactManager.h" #include "SHRigidBody.h" @@ -26,10 +24,15 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ + /** + * @brief + * Encapsulates the overall simulation of physics. The bulk of dynamics are handled here, + * with the collision detection handled by an attached collision space.
+ * A collision space must be created separately and attached with the world. + */ class SH_API SHPhysicsWorld { public: - /*---------------------------------------------------------------------------------*/ /* Type Definitions */ /*---------------------------------------------------------------------------------*/ @@ -47,9 +50,6 @@ namespace SHADE bool sleepingEnabled = true; }; - using TriggerEvents = std::vector; - using CollisionEvents = std::vector; - /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ @@ -71,29 +71,44 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - const SHAABBTree::AABBs& GetBroadphaseAABBs () const noexcept; + const SHContactManager::TriggerEvents& GetTriggerEvents () const noexcept; + const SHContactManager::CollisionEvents& GetCollisionEvents () const noexcept; - const TriggerEvents& GetTriggerEvents () const noexcept; - const CollisionEvents& GetCollisionEvents () const noexcept; + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + void SetCollisionSpace(SHCollisionSpace* collisionSpace) noexcept; /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ + /** + * @brief + * Adds a rigid body to the world for it to be simulated using motion dynamics. + * @param rigidBody + * A rigid body to add. Duplicates will be ignored. + */ void AddRigidBody (SHRigidBody* rigidBody) noexcept; - void RemoveRigidBody (SHRigidBody* rigidBody) noexcept; - - void AddCollider (SHCollider* collider) noexcept; - void RemoveCollider (SHCollider* collider) noexcept; /** * @brief - * Invoke this method to update the broadphase of a collider while the simulation - * is not running. - * @param collider - * The collider to update. + * Removes a rigid body from the world. It's motion will not be affected unless + * explicitly modified. + * @param rigidBody + * A rigid body to add. Duplicates will be ignored. + */ + void RemoveRigidBody (SHRigidBody* rigidBody) noexcept; + + /** + * @brief + * Performs a single simulation step.
+ * Detect Collisions -> Integrate Forces -> Resolve Contacts -> Integrate Velocities + * @param dt + * A discrete time step for the simulation. This should be consistent for deteministic + * behaviour. */ - void UpdateBroadphase (SHCollider* collider) noexcept; void Step (float dt); private: @@ -101,42 +116,18 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - struct NarrowphasePair - { - SHCollisionShape* A = nullptr; - SHCollisionShape* B = nullptr; - }; - // EntityIDs are used to map resolved contraints back to bodies using RigidBodies = std::unordered_map; - using Colliders = std::unordered_map; - - // Collisions - - using NarrowphaseBatch = std::unordered_map; - using Manifolds = std::unordered_map; - using Triggers = std::unordered_map; - - /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ WorldSettings settings; - - // Containers + SHCollisionSpace* collisionSpace; RigidBodies rigidBodies; - Colliders colliders; - - NarrowphaseBatch narrowphaseBatch; - Manifolds manifolds; - Triggers triggers; - - // World components - - SHAABBTree broadphase; + SHContactManager contactManager; /*---------------------------------------------------------------------------------*/ /* Function Members */ @@ -146,22 +137,8 @@ namespace SHADE void integrateForces (SHRigidBody& rigidBody, float dt) const noexcept; void integrateVelocities (SHRigidBody& rigidBody, float dt) const noexcept; - // Broadphase helpers - - void runBroadphase () noexcept; - void queryKinematic (SHCollider* collider) noexcept; - void queryDynamic (SHCollider* collider) noexcept; - - // Narrowphase helpers - - void runNarrowphase () noexcept; - void collideTriggers (const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept; - void collideManifolds (const SHCollisionKey& id, NarrowphasePair& narrowphasePair) noexcept; - void updateCollisionState (bool isColliding, SHCollisionState& state) noexcept; - void updateEvents () noexcept; - void removeInvalidatedTrigger (EntityID eid, uint32_t shapeIndex); - void removeInvalidatedManifold (EntityID eid, uint32_t shapeIndex); + }; diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp index b43b5b77..9bf43115 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsDebugDrawRoutine.cpp @@ -87,9 +87,8 @@ namespace SHADE { const SHColour& AABB_COLOUR = physicsDebugDrawSystem->DEBUG_DRAW_COLOURS[SHUtilities::ConvertEnum(Colours::BROADPHASE)]; - auto& broadphaseAABBs = physicsSystem->GetWorld()->GetBroadphaseAABBs(); - - for (auto& aabb : broadphaseAABBs) + const auto& BROADPHASE_AABBS = physicsSystem->collisionSpace->GetBroadphaseAABBs(); + for (auto& aabb : BROADPHASE_AABBS) { // Compute AABB Transform const SHMatrix TRS = SHMatrix::Transform(aabb.GetCenter(), SHQuaternion::Identity, aabb.GetWorldExtents() * 2.0f); diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp index 200642e1..5b0e5563 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPostUpdateRoutine.cpp @@ -16,6 +16,7 @@ // Project Headers #include "ECS_Base/Managers/SHSystemManager.h" #include "Math/Transform/SHTransformComponent.h" +#include "Scene/SHSceneManager.h" #include "Scripting/SHScriptEngine.h" @@ -50,15 +51,25 @@ namespace SHADE const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense(); for (auto& rigidBodyComponent : RIGIDBODY_DENSE) { - auto* transformComponent = SHComponentManager::GetComponent_s(rigidBodyComponent.GetEID()); + const EntityID EID = rigidBodyComponent.GetEID(); + + // Skip missing transforms + auto* transformComponent = SHComponentManager::GetComponent_s(EID); if (!transformComponent) continue; + // Skip invalid bodies (Should not occur) if (!rigidBodyComponent.rigidBody) continue; + // Skip inactive bodies + const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(EID); + if (!IS_ACTIVE) + continue; + const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState(); + // Skip objects that have not moved if (!MOTION_STATE) continue; diff --git a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp index 178a6120..17f3f83d 100644 --- a/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp +++ b/SHADE_Engine/src/Physics/System/Routines/SHPhysicsPreUpdateRoutine.cpp @@ -16,6 +16,7 @@ // Project Headers #include "ECS_Base/Managers/SHComponentManager.h" #include "Math/Transform/SHTransformComponent.h" +#include "Scene/SHSceneManager.h" namespace SHADE { @@ -40,35 +41,54 @@ namespace SHADE for (auto& [entityID, physicsObject] : physicsObjects) { const auto* TRANSFORM_COMPONENT = SHComponentManager::GetComponent_s(entityID); - - if (!TRANSFORM_COMPONENT || !TRANSFORM_COMPONENT->HasChanged()) - continue; - - const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); - const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation(); - const SHVec3& WORLD_SCL = TRANSFORM_COMPONENT->GetWorldScale(); + // Assume transform is always active + const bool UPDATE_TRANSFORM = TRANSFORM_COMPONENT && TRANSFORM_COMPONENT->HasChanged(); // We assume that all engine components and physics object components have been successfully linked if (physicsObject.rigidBody) { - SHMotionState& motionState = physicsObject.rigidBody->GetMotionState(); + const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(entityID); + const bool RIGIDBODY_ACTIVE = physicsObject.rigidBody->IsActive(); - motionState.ForcePosition(TRANSFORM_COMPONENT->GetWorldPosition()); - motionState.ForceOrientation(TRANSFORM_COMPONENT->GetWorldOrientation()); + if (IS_ACTIVE != RIGIDBODY_ACTIVE) + physicsObject.rigidBody->SetIsActive(IS_ACTIVE); + + if (UPDATE_TRANSFORM) + { + const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); + const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation(); + + SHMotionState& motionState = physicsObject.rigidBody->GetMotionState(); + motionState.ForcePosition(WORLD_POS); + motionState.ForceOrientation(WORLD_ROT); + } } if (physicsObject.collider) { - physicsObject.collider->SetPosition(WORLD_POS); - physicsObject.collider->SetOrientation(WORLD_ROT); - physicsObject.collider->SetScale(WORLD_SCL); + const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(entityID); + const bool COLLIDER_ACTIVE = physicsObject.collider->IsActive(); - physicsObject.collider->RecomputeShapes(); + if (IS_ACTIVE != COLLIDER_ACTIVE) + physicsObject.collider->SetIsActive(IS_ACTIVE); - physicsSystem->physicsWorld->UpdateBroadphase(physicsObject.collider); + if (UPDATE_TRANSFORM) + { + const SHVec3& WORLD_POS = TRANSFORM_COMPONENT->GetWorldPosition(); + const SHQuaternion& WORLD_ROT = TRANSFORM_COMPONENT->GetWorldOrientation(); + const SHVec3& WORLD_SCL = TRANSFORM_COMPONENT->GetWorldScale(); + + physicsObject.collider->SetPosition(WORLD_POS); + physicsObject.collider->SetOrientation(WORLD_ROT); + physicsObject.collider->SetScale(WORLD_SCL); + + physicsObject.collider->RecomputeShapes(); + } } } + + physicsSystem->collisionSpace->UpdateBroadphase(); } } // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp index 65bbc5d4..508c19ad 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.cpp @@ -21,6 +21,7 @@ #include "Editor/SHEditor.h" #include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h" #include "Physics/Interface/SHColliderComponent.h" +#include "Scripting/SHScriptEngine.h" namespace SHADE { @@ -33,6 +34,7 @@ namespace SHADE , interpolationFactor { 0.0 } , fixedDT { DEFAULT_FIXED_STEP } , physicsWorld { nullptr } + , collisionSpace { nullptr } { // Add more events here to register them @@ -44,6 +46,7 @@ namespace SHADE SHPhysicsSystem::~SHPhysicsSystem() noexcept { + delete collisionSpace; delete physicsWorld; } @@ -51,11 +54,6 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - const SHPhysicsWorld* SHPhysicsSystem::GetWorld() const noexcept - { - return physicsWorld; - } - double SHPhysicsSystem::GetFixedUpdateRate() const noexcept { return 1.0 / fixedDT; @@ -66,6 +64,16 @@ namespace SHADE return fixedDT; } + const std::vector& SHPhysicsSystem::GetTriggerInfo() const noexcept + { + return physicsWorld->GetTriggerEvents(); + } + + const std::vector& SHPhysicsSystem::GetCollisionInfo() const noexcept + { + return physicsWorld->GetCollisionEvents(); + } + /*-----------------------------------------------------------------------------------*/ /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ @@ -137,7 +145,48 @@ namespace SHADE void SHPhysicsSystem::ForceUpdate() { + if (!physicsWorld) + return; + auto* scriptingSystem = SHSystemManager::GetSystem(); + + if (scriptingSystem == nullptr) + { + SHLOGV_ERROR("Unable to invoke collision and trigger script events due to missing SHScriptEngine!"); + } + + scriptingSystem->ExecuteFixedUpdates(); + physicsWorld->Step(static_cast(fixedDT)); + + const auto& RIGIDBODY_DENSE = SHComponentManager::GetDense(); + for (auto& rigidBodyComponent : RIGIDBODY_DENSE) + { + const EntityID EID = rigidBodyComponent.GetEID(); + + // Skip missing transforms + auto* transformComponent = SHComponentManager::GetComponent_s(EID); + if (!transformComponent) + continue; + + // Skip invalid bodies (Should not occur) + if (!rigidBodyComponent.rigidBody) + continue; + + // Skip inactive bodies + const bool IS_ACTIVE = SHSceneManager::CheckNodeAndComponentsActive(EID); + if (!IS_ACTIVE) + continue; + + const SHMotionState& MOTION_STATE = rigidBodyComponent.rigidBody->GetMotionState(); + + // Skip objects that have not moved + if (!MOTION_STATE) + continue; + + // We ignore interpolations here because we are only stepping once + transformComponent->SetWorldPosition(MOTION_STATE.position); + transformComponent->SetWorldOrientation(MOTION_STATE.orientation); + } } /*-----------------------------------------------------------------------------------*/ @@ -162,17 +211,29 @@ namespace SHADE { if (PHYSICS_OBJECT.rigidBody) physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody); - - if (PHYSICS_OBJECT.collider) - physicsWorld->RemoveCollider(PHYSICS_OBJECT.collider); } delete physicsWorld; physicsWorld = nullptr; } - // Create the physics world - physicsWorld = new SHPhysicsWorld; + if (collisionSpace) + { + for (const auto& PHYSICS_OBJECT : physicsObjectManager.GetPhysicsObjects() | std::views::values) + { + if (PHYSICS_OBJECT.collider) + collisionSpace->RemoveCollider(PHYSICS_OBJECT.collider); + } + + delete collisionSpace; + collisionSpace = nullptr; + } + + // Create the physics world & collision space + physicsWorld = new SHPhysicsWorld; + collisionSpace = new SHCollisionSpace; + + physicsWorld->SetCollisionSpace(collisionSpace); // Immediately add all existing bodies and colliders to the world. // Since we recreated the scene and the world, the initial data has been reset and determinism is guaranteed. @@ -184,7 +245,7 @@ namespace SHADE physicsWorld->AddRigidBody(PHYSICS_OBJECT.rigidBody); if (PHYSICS_OBJECT.collider) - physicsWorld->AddCollider(PHYSICS_OBJECT.collider); + collisionSpace->AddCollider(PHYSICS_OBJECT.collider); } return onSceneInitEvent.get()->handle; @@ -203,9 +264,12 @@ namespace SHADE physicsWorld->RemoveRigidBody(PHYSICS_OBJECT.rigidBody); if (PHYSICS_OBJECT.collider) - physicsWorld->RemoveCollider(PHYSICS_OBJECT.collider); + collisionSpace->RemoveCollider(PHYSICS_OBJECT.collider); } + delete collisionSpace; + collisionSpace = nullptr; + delete physicsWorld; physicsWorld = nullptr; @@ -247,10 +311,10 @@ namespace SHADE { physicsObjectManager.AddCollider(EID); - if (physicsWorld) + if (collisionSpace) { auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider; - physicsWorld->AddCollider(collider); + collisionSpace->AddCollider(collider); } } @@ -289,17 +353,16 @@ namespace SHADE if (IS_COLLIDER) { - if (physicsWorld) + if (collisionSpace) { auto* collider = physicsObjectManager.GetPhysicsObject(EID)->collider; - physicsWorld->RemoveCollider(collider); + collisionSpace->RemoveCollider(collider); } physicsObjectManager.RemoveCollider(EID); } - return onComponentRemovedEvent.get()->handle; } -} // namespace SHADE \ No newline at end of file +} // namespace SHADE diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h index fca12498..ab28a299 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystem.h @@ -33,6 +33,13 @@ namespace SHADE */ class SH_API SHPhysicsSystem final : public SHSystem { + private: + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHPhysicsDebugDrawSystem; + public: /*---------------------------------------------------------------------------------*/ /* Constructors & Destructor */ @@ -45,7 +52,6 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] const SHPhysicsWorld* GetWorld () const noexcept; [[nodiscard]] double GetFixedUpdateRate() const noexcept; [[nodiscard]] double GetFixedDT () const noexcept; @@ -56,6 +62,9 @@ namespace SHADE void SetFixedUpdateRate(double fixedUpdateRate) noexcept; void SetFixedDT(double fixedDt) noexcept; + const std::vector& GetTriggerInfo () const noexcept; + const std::vector& GetCollisionInfo () const noexcept; + /*---------------------------------------------------------------------------------*/ /* Member Functions */ /*---------------------------------------------------------------------------------*/ @@ -137,6 +146,7 @@ namespace SHADE // Sub-systems / managers SHPhysicsWorld* physicsWorld; + SHCollisionSpace* collisionSpace; SHPhysicsObjectManager physicsObjectManager; /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp index 06f1b464..f72eb271 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.cpp @@ -1,8 +1,6 @@ /************************************************************************************//*! \file SHPhysicsSystemInterface.cpp -\author Tng Kah Wei, kahwei.tng, 390009620 -\par email: kahwei.tng\@digipen.edu -\date Oct 31, 2022 +\author Diren D Bharwani, diren.dbharwani, 390002520 \brief Contains the definitions of the functions of the static SHPhysicsSystemInterface class. @@ -10,10 +8,13 @@ Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. *//*************************************************************************************/ -// Precompiled Headers + + #include "SHpch.h" + // Primary Header #include "SHPhysicsSystemInterface.h" + // Project Includes #include "ECS_Base/Managers/SHSystemManager.h" #include "Physics/System/SHPhysicsSystem.h" @@ -23,42 +24,47 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Static Usage Functions */ /*-----------------------------------------------------------------------------------*/ - const std::vector& SHPhysicsSystemInterface::GetCollisionInfo() noexcept + const std::vector& SHPhysicsSystemInterface::GetCollisionInfo() noexcept { - static std::vector emptyVec; + static std::vector emptyVec; - //auto phySystem = SHSystemManager::GetSystem(); - //if (phySystem) - //{ - // return phySystem->GetAllCollisionInfo(); - //} + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + return physicsSystem->GetCollisionInfo(); - //SHLOGV_WARNING("Failed to get collision events. Empty vector returned instead."); + SHLOGV_WARNING("Failed to get collision events. Empty vector returned instead."); return emptyVec; } - const std::vector& SHPhysicsSystemInterface::GetTriggerInfo() noexcept + const std::vector& SHPhysicsSystemInterface::GetTriggerInfo() noexcept { - static std::vector emptyVec; + static std::vector emptyVec; - //auto phySystem = SHSystemManager::GetSystem(); - //if (phySystem) - //{ - // return phySystem->GetAllTriggerInfo(); - //} + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + return physicsSystem->GetTriggerInfo(); - //SHLOGV_WARNING("Failed to get trigger events. Empty vector returned instead."); + SHLOGV_WARNING("Failed to get trigger events. Empty vector returned instead."); return emptyVec; } double SHPhysicsSystemInterface::GetFixedDT() noexcept { - auto phySystem = SHSystemManager::GetSystem(); - if (phySystem) - { - return 1.0 / phySystem->GetFixedUpdateRate(); - } + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + return physicsSystem->GetFixedDT(); SHLOGV_WARNING("Failed to get fixed delta time. 0.0 returned instead."); return 0.0; } + + int SHPhysicsSystemInterface::GetFixedUpdateRate() noexcept + { + auto* physicsSystem = SHSystemManager::GetSystem(); + if (physicsSystem) + return physicsSystem->GetFixedUpdateRate(); + + SHLOGV_WARNING("Failed to get fixed update rate. 0.0 returned instead."); + return 0.0; + } + } diff --git a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h index ed190cc9..e6103e87 100644 --- a/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h +++ b/SHADE_Engine/src/Physics/System/SHPhysicsSystemInterface.h @@ -1,22 +1,20 @@ /************************************************************************************//*! \file SHPhysicsSystemInterface.h -\author Tng Kah Wei, kahwei.tng, 390009620 -\par email: kahwei.tng\@digipen.edu -\date Oct 31, 2022 +\author Diren D Bharwani, diren.dbharwani, 390002520 \brief Contains the definition of the SHGraphicsSystemInterface static class. Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. *//*************************************************************************************/ + #pragma once -// STL Includes #include // Project Headers #include "ECS_Base/Entity/SHEntity.h" -#include "Physics/Collision/SHCollisionInfo.h" +#include "Physics/Collision/Contacts/SHCollisionEvents.h" namespace SHADE @@ -49,8 +47,8 @@ namespace SHADE /* Static Usage Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] static const std::vector& GetCollisionInfo () noexcept; - [[nodiscard]] static const std::vector& GetTriggerInfo () noexcept; + [[nodiscard]] static const std::vector& GetCollisionInfo () noexcept; + [[nodiscard]] static const std::vector& GetTriggerInfo () noexcept; [[nodiscard]] static double GetFixedDT () noexcept; [[nodiscard]] static int GetFixedUpdateRate () noexcept; }; diff --git a/SHADE_Managed/src/Scripts/ScriptStore.cxx b/SHADE_Managed/src/Scripts/ScriptStore.cxx index a5a0ebc7..1393fe33 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.cxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.cxx @@ -30,7 +30,6 @@ of DigiPen Institute of Technology is prohibited. #include "Engine/Application.hxx" #include "Physics/System/SHPhysicsSystemInterface.h" #include "Physics/SHPhysicsEvents.h" -#include "Physics/Collision/SHCollisionInfo.h" namespace SHADE { @@ -605,8 +604,8 @@ namespace SHADE { auto entities = { - std::make_pair(collisionInfo.GetEntityA(), collisionInfo.GetEntityB()), - std::make_pair(collisionInfo.GetEntityB(), collisionInfo.GetEntityA()) + std::make_pair(collisionInfo.info.GetEntityA(), collisionInfo.info.GetEntityB()), + std::make_pair(collisionInfo.info.GetEntityB(), collisionInfo.info.GetEntityA()) }; for (auto entity : entities) { @@ -625,15 +624,15 @@ namespace SHADE for (int i = 0; i < entityScripts->Count; ++i) { Script^ script = entityScripts[i]; - switch (collisionInfo.GetCollisionState()) + switch (collisionInfo.state) { - case SHCollisionInfo::State::ENTER: + case SHCollisionState::ENTER: script->OnCollisionEnter(info); break; - case SHCollisionInfo::State::STAY: + case SHCollisionState::STAY: script->OnCollisionStay(info); break; - case SHCollisionInfo::State::EXIT: + case SHCollisionState::EXIT: script->OnCollisionExit(info); break; } @@ -647,8 +646,8 @@ namespace SHADE { auto entities = { - std::make_pair(triggerInfo.GetEntityA(), triggerInfo.GetEntityB()), - std::make_pair(triggerInfo.GetEntityB(), triggerInfo.GetEntityA()) + std::make_pair(triggerInfo.info.GetEntityA(), triggerInfo.info.GetEntityB()), + std::make_pair(triggerInfo.info.GetEntityB(), triggerInfo.info.GetEntityA()) }; for (auto entity : entities) { @@ -667,15 +666,15 @@ namespace SHADE for (int i = 0; i < entityScripts->Count; ++i) { Script^ script = entityScripts[i]; - switch (triggerInfo.GetCollisionState()) + switch (triggerInfo.state) { - case SHCollisionInfo::State::ENTER: + case SHCollisionState::ENTER: script->OnTriggerEnter(info); break; - case SHCollisionInfo::State::STAY: + case SHCollisionState::STAY: script->OnTriggerStay(info); break; - case SHCollisionInfo::State::EXIT: + case SHCollisionState::EXIT: script->OnTriggerExit(info); break; }