diff --git a/SHADE_Application/src/Scenes/SBTestScene.cpp b/SHADE_Application/src/Scenes/SBTestScene.cpp index 8cbeb43a..4cdac9dc 100644 --- a/SHADE_Application/src/Scenes/SBTestScene.cpp +++ b/SHADE_Application/src/Scenes/SBTestScene.cpp @@ -96,11 +96,7 @@ namespace Sandbox transform.SetWorldRotation(SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f), SHMath::GenerateRandomNumber(0.0f, 360.0f)); transform.SetWorldScale(TEST_OBJ_SCALE); - //if (const bool IS_EVEN = (y * NUM_ROWS + x) % 2; IS_EVEN) - collider.AddBoundingBox(SHVec3::One * 0.5f, SHVec3::Zero); - //else - // collider.AddBoundingSphere(0.5f, SHVec3::Zero); - + collider.AddBoundingBox(SHVec3::One, SHVec3::Zero); stressTestObjects.emplace_back(entity); } diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index 7fa39d74..4645bf52 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -207,6 +207,10 @@ namespace SHADE { if (!component) return; + + // Get transform component for extrapolating relative sizes + auto* transformComponent = SHComponentManager::GetComponent(component->GetEID()); + const auto componentType = rttr::type::get(*component); SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }); ImGui::SameLine(); @@ -221,28 +225,41 @@ namespace SHADE for (int i{}; i < size; ++i) { ImGui::PushID(i); - SHCollider& collider = component->GetCollider(i); + SHCollider* collider = &component->GetCollider(i); auto cursorPos = ImGui::GetCursorPos(); - if (collider.GetType() == SHCollider::Type::BOX) + if (collider->GetType() == SHCollider::Type::BOX) { SHEditorWidgets::BeginPanel( std::format("{} Box Collider #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - auto box = reinterpret_cast(collider.GetShape()); - SHEditorWidgets::DragVec3("Half Extents", { "X", "Y", "Z" }, [box] {return box->GetHalfExtents(); }, [box](SHVec3 const& vec) {box->SetHalfExtents(vec);}); + auto box = reinterpret_cast(collider->GetShape()); + SHEditorWidgets::DragVec3 + ( + "Half Extents", { "X", "Y", "Z" }, + [box, transformComponent] { return (transformComponent->GetWorldScale() * 2.0f) * box->GetHalfExtents(); }, + [collider](SHVec3 const& vec) { collider->SetBoundingBox(vec); }); } - else if (collider.GetType() == SHCollider::Type::SPHERE) + else if (collider->GetType() == SHCollider::Type::SPHERE) { SHEditorWidgets::BeginPanel(std::format("{} Sphere Collider #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }); - auto sphere = reinterpret_cast(collider.GetShape()); - SHEditorWidgets::DragFloat("Radius", [sphere] {return sphere->GetRadius(); }, [sphere](float const& value) {sphere->SetRadius(value);}); + auto sphere = reinterpret_cast(collider->GetShape()); + SHEditorWidgets::DragFloat + ( + "Radius", + [sphere, transformComponent] + { + const SHVec3& TF_WORLD_SCALE = transformComponent->GetWorldScale(); + const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z }); + return sphere->GetRadius() / MAX_SCALE; + }, + [collider](float const& value) { collider->SetBoundingSphere(value);}); } - else if (collider.GetType() == SHCollider::Type::CAPSULE) + else if (collider->GetType() == SHCollider::Type::CAPSULE) { } { SHEditorWidgets::BeginPanel("Offset", { ImGui::GetContentRegionAvail().x, 30.0f }); - SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider.GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider.SetPositionOffset(vec); }); + SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); }); SHEditorWidgets::EndPanel(); } if(ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data())) diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.cpp b/SHADE_Engine/src/Math/Geometry/SHShape.cpp index 3fc5775d..2f869029 100644 --- a/SHADE_Engine/src/Math/Geometry/SHShape.cpp +++ b/SHADE_Engine/src/Math/Geometry/SHShape.cpp @@ -27,10 +27,9 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - SHShape::Type SHShape::GetType() const + SHShape::Type SHShape::GetType() const noexcept { return type; } - } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Math/Geometry/SHShape.h b/SHADE_Engine/src/Math/Geometry/SHShape.h index 18f54fe6..62198897 100644 --- a/SHADE_Engine/src/Math/Geometry/SHShape.h +++ b/SHADE_Engine/src/Math/Geometry/SHShape.h @@ -63,7 +63,7 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] Type GetType() const; + [[nodiscard]] Type GetType () const noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ @@ -77,6 +77,6 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - Type type; + Type type; }; } // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp b/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp index 75a00491..fb999847 100644 --- a/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp +++ b/SHADE_Engine/src/Physics/Components/SHColliderComponent.cpp @@ -58,7 +58,7 @@ namespace SHADE if (index < 0 || static_cast(index) >= colliders.size()) throw std::invalid_argument("Out-of-range access!"); - return colliders[index].first; + return colliders[index]; } /*-----------------------------------------------------------------------------------*/ @@ -85,13 +85,11 @@ namespace SHADE static constexpr auto TYPE = SHCollider::Type::BOX; - auto boxPair = std::make_pair(SHCollider{ TYPE }, true); - auto& collider = colliders.emplace_back(boxPair).first; - - const auto* tf = SHComponentManager::GetComponent(GetEID()); + auto& collider = colliders.emplace_back(SHCollider{ GetEID(), TYPE }); + collider.entityID = GetEID(); collider.SetPositionOffset(posOffset); - collider.SetAsBoundingBox(tf->GetWorldScale() * halfExtents); + collider.SetBoundingBox(halfExtents); // Notify Physics System system->AddCollisionShape(GetEID(), &collider); @@ -109,16 +107,11 @@ namespace SHADE static constexpr auto TYPE = SHCollider::Type::SPHERE; - auto spherePair = std::make_pair(SHCollider{ TYPE }, true); - auto& collider = colliders.emplace_back(spherePair).first; - - const auto* tf = SHComponentManager::GetComponent(GetEID()); + auto& collider = colliders.emplace_back(SHCollider{ GetEID(), TYPE }); + collider.entityID = GetEID(); collider.SetPositionOffset(posOffset); - - const SHVec3 TF_WORLD_SCALE = tf->GetWorldScale(); - const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z }); - collider.SetAsBoundingSphere(MAX_SCALE * 0.5f * radius); + collider.SetBoundingSphere(radius); // Notify Physics System system->AddCollisionShape(GetEID(), &collider); diff --git a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h b/SHADE_Engine/src/Physics/Components/SHColliderComponent.h index 4ecd0e93..af726b51 100644 --- a/SHADE_Engine/src/Physics/Components/SHColliderComponent.h +++ b/SHADE_Engine/src/Physics/Components/SHColliderComponent.h @@ -43,8 +43,7 @@ namespace SHADE /* Type Definitions */ /*---------------------------------------------------------------------------------*/ - using ColliderDirtyPair = std::pair; - using Colliders = std::vector; + using Colliders = std::vector; public: diff --git a/SHADE_Engine/src/Physics/SHCollider.cpp b/SHADE_Engine/src/Physics/SHCollider.cpp index f5899cfc..9488042d 100644 --- a/SHADE_Engine/src/Physics/SHCollider.cpp +++ b/SHADE_Engine/src/Physics/SHCollider.cpp @@ -15,6 +15,8 @@ // Project Headers #include "Math/Geometry/SHBoundingBox.h" #include "Math/Geometry/SHBoundingSphere.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Math/SHMathHelpers.h" namespace SHADE { @@ -22,22 +24,24 @@ namespace SHADE /* Constructors & Destructor Definitions */ /*-----------------------------------------------------------------------------------*/ - SHCollider::SHCollider(Type colliderType) + SHCollider::SHCollider(EntityID eid, Type colliderType, const SHPhysicsMaterial& physicsMaterial) : type { colliderType } + , entityID { eid } , isTrigger { false } , dirty { true } , shape { nullptr } + , material { physicsMaterial } { switch (type) { case Type::BOX: { - SetAsBoundingBox(SHVec3::One); + shape = new SHBoundingBox{ SHVec3::Zero, SHVec3::One }; break; } case Type::SPHERE: { - SetAsBoundingSphere(1.0f); + shape = new SHBoundingSphere{ SHVec3::Zero, 0.5f }; break; } default: break; @@ -46,19 +50,27 @@ namespace SHADE SHCollider::SHCollider(const SHCollider& rhs) noexcept : type { rhs.type} + , entityID { rhs.entityID } , isTrigger { rhs.isTrigger } , dirty { true } - , shape { rhs.shape } + , shape { nullptr } + , material { rhs.material } , positionOffset { rhs.positionOffset } - {} + { + CopyShape(rhs.shape); + } SHCollider::SHCollider(SHCollider&& rhs) noexcept : type { rhs.type} + , entityID { rhs.entityID } , isTrigger { rhs.isTrigger } , dirty { true } - , shape { rhs.shape } + , shape { nullptr } + , material { rhs.material } , positionOffset { rhs.positionOffset } - {} + { + CopyShape(rhs.shape); + } SHCollider::~SHCollider() noexcept { @@ -75,22 +87,30 @@ namespace SHADE return *this; type = rhs.type; + entityID = rhs.entityID; isTrigger = rhs.isTrigger; dirty = true; - shape = rhs.shape; + material = rhs.material; positionOffset = rhs.positionOffset; + delete shape; + CopyShape(rhs.shape); + return *this; } SHCollider& SHCollider::operator=(SHCollider&& rhs) noexcept { type = rhs.type; + entityID = rhs.entityID; isTrigger = rhs.isTrigger; dirty = true; - shape = rhs.shape; + material = rhs.material; positionOffset = rhs.positionOffset; + delete shape; + CopyShape(rhs.shape); + return *this; } @@ -115,19 +135,22 @@ namespace SHADE float SHCollider::GetFriction() const noexcept { - // TODO(Diren): Fix after implementing materials - return 0.0f; + return material.GetFriction(); } float SHCollider::GetBounciness() const noexcept { - // TODO(Diren): Fix after implementing materials - return 0.0f; + return material.GetBounciness(); } + float SHCollider::GetDensity() const noexcept { - // TODO(Diren): Fix after implementing materials - return 0.0f; + return material.GetDensity(); + } + + const SHPhysicsMaterial& SHCollider::GetMaterial() const noexcept + { + return material; } const SHVec3& SHCollider::GetPositionOffset() const noexcept @@ -145,22 +168,60 @@ namespace SHADE /* Setter Function Definitions */ /*-----------------------------------------------------------------------------------*/ - void SHCollider::SetAsBoundingBox(const SHVec3& halfExtents) + void SHCollider::SetBoundingBox(const SHVec3& halfExtents) { dirty = true; - type = Type::BOX; - delete shape; - shape = new SHBoundingBox{ positionOffset, halfExtents }; + // Set the half extents relative to transform + SHVec3 worldHalfExtents = halfExtents; + + const auto* transformComponent = SHComponentManager::GetComponent_s(entityID); + if (transformComponent != nullptr) + worldHalfExtents *= (transformComponent->GetWorldScale() * 0.5f); + + if (type == Type::BOX) + { + auto* box = reinterpret_cast(shape); + box->SetHalfExtents(worldHalfExtents); + } + else + { + type = Type::BOX; + + delete shape; + shape = new SHBoundingBox{ positionOffset, worldHalfExtents }; + } } - void SHCollider::SetAsBoundingSphere(float radius) + void SHCollider::SetBoundingSphere(float radius) { dirty = true; - type = Type::SPHERE; - delete shape; - shape = new SHBoundingSphere{ positionOffset, radius }; + // Set the radius relative to transform + float worldRadius = radius; + + const auto* transformComponent = SHComponentManager::GetComponent_s(entityID); + if (transformComponent != nullptr) + { + const SHVec3 TF_WORLD_SCALE = transformComponent->GetWorldScale(); + const float MAX_SCALE = SHMath::Max({ TF_WORLD_SCALE.x, TF_WORLD_SCALE.y, TF_WORLD_SCALE.z }); + + worldRadius *= MAX_SCALE; + } + + if (type == Type::SPHERE) + { + auto* sphere = reinterpret_cast(shape); + sphere->SetRadius(worldRadius); + } + else + { + type = Type::SPHERE; + + delete shape; + shape = new SHBoundingSphere{ positionOffset, worldRadius }; + } + } void SHCollider::SetIsTrigger(bool trigger) noexcept @@ -172,23 +233,74 @@ namespace SHADE void SHCollider::SetFriction(float friction) noexcept { dirty = true; + material.SetFriction(friction); } void SHCollider::SetBounciness(float bounciness) noexcept { dirty = true; + material.SetBounciness(bounciness); } void SHCollider::SetDensity(float density) noexcept { dirty = true; + material.SetDensity(density); + } + + void SHCollider::SetMaterial(const SHPhysicsMaterial& newMaterial) noexcept + { + dirty = true; + material = newMaterial; } void SHCollider::SetPositionOffset(const SHVec3& posOffset) noexcept { dirty = true; positionOffset = posOffset; + + switch (type) + { + case Type::BOX: + { + reinterpret_cast(shape)->SetCenter(positionOffset); + break; + } + case Type::SPHERE: + { + reinterpret_cast(shape)->SetCenter(positionOffset); + break; + } + default: break; + } } + + /*-----------------------------------------------------------------------------------*/ + /* Private Function Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHCollider::CopyShape(const SHShape* rhs) + { + switch (type) + { + case Type::BOX: + { + const auto* RHS_BOX = reinterpret_cast(rhs); + + shape = new SHBoundingBox{ positionOffset, RHS_BOX->GetHalfExtents() }; + break; + } + case Type::SPHERE: + { + const auto* RHS_SPHERE = reinterpret_cast(rhs); + + shape = new SHBoundingSphere{ positionOffset, RHS_SPHERE->GetRadius() }; + break; + } + default: break; + } + } + } // namespace SHADE RTTR_REGISTRATION @@ -205,5 +317,4 @@ RTTR_REGISTRATION registration::class_("Collider") .property("Position Offset", &SHCollider::GetPositionOffset, &SHCollider::SetPositionOffset); - // TODO(Diren): Add Physics Materials } \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHCollider.h b/SHADE_Engine/src/Physics/SHCollider.h index 0e024f09..f760ffd0 100644 --- a/SHADE_Engine/src/Physics/SHCollider.h +++ b/SHADE_Engine/src/Physics/SHCollider.h @@ -13,8 +13,10 @@ #include // Project Headers +#include "ECS_Base/Entity/SHEntity.h" #include "Math/Geometry/SHShape.h" #include "Math/SHQuaternion.h" +#include "SHPhysicsMaterial.h" namespace SHADE { @@ -24,6 +26,15 @@ namespace SHADE class SH_API SHCollider { + private: + + /*---------------------------------------------------------------------------------*/ + /* Friends */ + /*---------------------------------------------------------------------------------*/ + + friend class SHColliderComponent; + friend class SHPhysicsObject; + public: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -40,7 +51,7 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHCollider (Type colliderType = Type::BOX); + SHCollider (EntityID eid, Type colliderType = Type::BOX, const SHPhysicsMaterial& physicsMaterial = SHPhysicsMaterial::DEFAULT); SHCollider (const SHCollider& rhs) noexcept; SHCollider (SHCollider&& rhs) noexcept; @@ -57,31 +68,33 @@ namespace SHADE /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] bool HasChanged () const noexcept; + [[nodiscard]] bool HasChanged () const noexcept; - [[nodiscard]] bool IsTrigger () const noexcept; + [[nodiscard]] bool IsTrigger () const noexcept; - [[nodiscard]] Type GetType () const noexcept; + [[nodiscard]] Type GetType () const noexcept; - [[nodiscard]] float GetFriction () const noexcept; - [[nodiscard]] float GetBounciness () const noexcept; - [[nodiscard]] float GetDensity () const noexcept; + [[nodiscard]] float GetFriction () const noexcept; + [[nodiscard]] float GetBounciness () const noexcept; + [[nodiscard]] float GetDensity () const noexcept; + [[nodiscard]] const SHPhysicsMaterial& GetMaterial () const noexcept; - [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; + [[nodiscard]] const SHVec3& GetPositionOffset () const noexcept; - [[nodiscard]] SHShape* GetShape () noexcept; + [[nodiscard]] SHShape* GetShape () noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetAsBoundingBox (const SHVec3& halfExtents); - void SetAsBoundingSphere (float radius); + void SetBoundingBox (const SHVec3& halfExtents); + void SetBoundingSphere (float radius); - void SetIsTrigger (bool isTrigger) noexcept; - void SetFriction (float friction) noexcept; - void SetBounciness (float bounciness) noexcept; - void SetDensity (float density) noexcept; + void SetIsTrigger (bool isTrigger) noexcept; + void SetFriction (float friction) noexcept; + void SetBounciness (float bounciness) noexcept; + void SetDensity (float density) noexcept; + void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept; void SetPositionOffset (const SHVec3& positionOffset) noexcept; @@ -90,11 +103,19 @@ namespace SHADE /* Data Members */ /*---------------------------------------------------------------------------------*/ - Type type; - bool isTrigger; - bool dirty; - SHShape* shape; - SHVec3 positionOffset; + Type type; + EntityID entityID; // The entity this collider belongs to + bool isTrigger; + bool dirty; + SHShape* shape; + SHPhysicsMaterial material; + SHVec3 positionOffset; + + /*---------------------------------------------------------------------------------*/ + /* Function Members */ + /*---------------------------------------------------------------------------------*/ + + void CopyShape(const SHShape* rhs); RTTR_ENABLE() }; diff --git a/SHADE_Engine/src/Physics/SHPhysicsMaterial.cpp b/SHADE_Engine/src/Physics/SHPhysicsMaterial.cpp new file mode 100644 index 00000000..677e448f --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsMaterial.cpp @@ -0,0 +1,104 @@ +/**************************************************************************************** + * \file SHPhysicsMaterial.cpp + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Implementation for a Physics Material. + * + * \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 "SHPhysicsMaterial.h" +// Project Headers +#include "Math/SHMathHelpers.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Static Data Member Definitions */ + /*-----------------------------------------------------------------------------------*/ + + const SHPhysicsMaterial SHPhysicsMaterial::DEFAULT { 0.4f, 0.0f, 1.0f }; + + /*-----------------------------------------------------------------------------------*/ + /* Constructors & Destructor Definitions */ + /*-----------------------------------------------------------------------------------*/ + + SHPhysicsMaterial::SHPhysicsMaterial(float _friction, float _bounciness, float _density) noexcept + : friction { std::clamp(_friction, 0.0f, 1.0f) } + , bounciness{ std::clamp(_bounciness, 0.0f, 1.0f) } + , density { std::fabs(_density) } + {} + + /*-----------------------------------------------------------------------------------*/ + /* Operator Overload Definitions */ + /*-----------------------------------------------------------------------------------*/ + + bool SHPhysicsMaterial::operator==(const SHPhysicsMaterial& rhs) const noexcept + { + return SHMath::CompareFloat(friction, rhs.friction) + && SHMath::CompareFloat(bounciness, rhs.bounciness) + && SHMath::CompareFloat(density, rhs.density); + } + + bool SHPhysicsMaterial::operator!=(const SHPhysicsMaterial& rhs) const noexcept + { + return !SHMath::CompareFloat(friction, rhs.friction) + || !SHMath::CompareFloat(bounciness, rhs.bounciness) + || !SHMath::CompareFloat(density, rhs.density); + } + + /*-----------------------------------------------------------------------------------*/ + /* Getter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + float SHPhysicsMaterial::GetFriction() const noexcept + { + return friction; + } + + float SHPhysicsMaterial::GetBounciness() const noexcept + { + return bounciness; + } + + float SHPhysicsMaterial::GetDensity() const noexcept + { + return density; + } + + /*-----------------------------------------------------------------------------------*/ + /* Setter Function Definitions */ + /*-----------------------------------------------------------------------------------*/ + + void SHPhysicsMaterial::SetFriction(float newFriction) noexcept + { + if (newFriction < 0.0f || newFriction > 1.0f) + { + SHLOG_WARNING("Clamping friction of Physics Material between [0,1].") + } + friction = std::clamp(newFriction, 0.0f, 1.0f); + } + + void SHPhysicsMaterial::SetBounciness(float newBounciness) noexcept + { + if (newBounciness < 0.0f || newBounciness > 1.0f) + { + SHLOG_WARNING("Clamping bounciness of Physics Material between [0,1].") + } + bounciness = std::clamp(newBounciness, 0.0f, 1.0f); + } + + void SHPhysicsMaterial::SetDensity(float newDensity) noexcept + { + if (newDensity < 0.0f) + { + SHLOG_WARNING("Setting negative density of Physics Material to positive.") + } + density = std::fabs(newDensity); + } + +} // namespace SHADE \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsMaterial.h b/SHADE_Engine/src/Physics/SHPhysicsMaterial.h new file mode 100644 index 00000000..b3db1655 --- /dev/null +++ b/SHADE_Engine/src/Physics/SHPhysicsMaterial.h @@ -0,0 +1,113 @@ +/**************************************************************************************** + * \file SHPhysicsMaterial.h + * \author Diren D Bharwani, diren.dbharwani, 390002520 + * \brief Interface for a Physics Material. + * + * \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 "SH_API.h" + +namespace SHADE +{ + /*-----------------------------------------------------------------------------------*/ + /* Type Definitions */ + /*-----------------------------------------------------------------------------------*/ + + class SH_API SHPhysicsMaterial + { + public: + /*---------------------------------------------------------------------------------*/ + /* Static Data Members */ + /*---------------------------------------------------------------------------------*/ + + static const SHPhysicsMaterial DEFAULT; + + /*---------------------------------------------------------------------------------*/ + /* Constructors & Destructor */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsMaterial (const SHPhysicsMaterial&) noexcept = default; + SHPhysicsMaterial (SHPhysicsMaterial&&) noexcept = default; + ~SHPhysicsMaterial() = default; + + /** + * @brief Default constructor for a physics material. + * @param friction The friction of the material. Clamped between [0,1]. Defaults to 0.4. + * @param bounciness The bounciness of the material. Clamped between [0,1]. + * @param density The mass density of the material. Always made positive. + */ + SHPhysicsMaterial (float friction = 0.4f, float bounciness = 0.0f, float density = 1.0f) noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Operator Overloads */ + /*---------------------------------------------------------------------------------*/ + + SHPhysicsMaterial& operator= (const SHPhysicsMaterial&) noexcept = default; + SHPhysicsMaterial& operator= (SHPhysicsMaterial&&) noexcept = default; + + bool operator==(const SHPhysicsMaterial& rhs) const noexcept; + bool operator!=(const SHPhysicsMaterial& rhs) const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Getter Functions */ + /*---------------------------------------------------------------------------------*/ + + [[nodiscard]] float GetFriction () const noexcept; + [[nodiscard]] float GetBounciness () const noexcept; + [[nodiscard]] float GetDensity () const noexcept; + + /*---------------------------------------------------------------------------------*/ + /* Setter Functions */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief Sets the friction coefficient of the physics material. + * @param newFriction The friction value to set. Clamped between [0,1]. + */ + void SetFriction (float newFriction) noexcept; + + /** + * @brief Sets the bounciness factor of the physics material. + * @param newBounciness The bounciness value to set. Clamped between [0,1]. + */ + void SetBounciness (float newBounciness) noexcept; + + /** + * @brief Sets the mass density of the physics material. + * @param newDensity The density value to set. Always made positive. + */ + void SetDensity (float newDensity) noexcept; + + private: + + /*---------------------------------------------------------------------------------*/ + /* Data Members */ + /*---------------------------------------------------------------------------------*/ + + /** + * @brief The friction coefficient of the physics object., clamped between [0,1].
+ * 0 means the object will never experience friction. + * 1 means the friction force against the object is equal to the applied force. + */ + float friction; + + /** + * @brief The bounciness factor of the physics object., clamped between [0,1].
+ * 0 means the object will never bounce. + * 1 means the object never loses energy on a bounce. + */ + float bounciness; + + /** + * @brief The density of the collider that determines the mass of the collision shape + * if it is automatically computed. Must be a positive number. + */ + float density; + }; +} \ No newline at end of file diff --git a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp index 986ce503..4d4d8cd7 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsObject.cpp +++ b/SHADE_Engine/src/Physics/SHPhysicsObject.cpp @@ -261,9 +261,9 @@ namespace SHADE void SHPhysicsObject::SyncColliders(SHColliderComponent* c) const noexcept { int index = 0; - for (auto& [collider, dirty] : c->colliders) + for (auto& collider : c->colliders) { - if (!dirty) + if (!collider.dirty) continue; // Update offsets @@ -293,7 +293,7 @@ namespace SHADE default: break; } - dirty = false; + collider.dirty = false; ++index; } } diff --git a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp index 1c6e79d7..44142aaf 100644 --- a/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp +++ b/SHADE_Engine/src/Physics/SHPhysicsSystem.cpp @@ -246,21 +246,6 @@ namespace SHADE if (physicsObject.rp3dBody == nullptr) continue; - auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); - - // Clear all forces and velocities if editor is not in play - if (SHSystemManager::GetSystem()->editorState == SHEditor::State::STOP) - { - if (rigidBodyComponent) - { - auto* rp3dRigidBody = reinterpret_cast(physicsObject.rp3dBody); - rp3dRigidBody->resetForce(); - rp3dRigidBody->resetTorque(); - rp3dRigidBody->setLinearVelocity(SHVec3::Zero); - rp3dRigidBody->setAngularVelocity(SHVec3::Zero); - } - } - const auto* transformComponent = SHComponentManager::GetComponent_s(entityID); if (transformComponent && transformComponent->HasChanged()) { @@ -270,10 +255,21 @@ namespace SHADE physicsObject.SetPosition(WORLD_POS); physicsObject.SetOrientation(WORLD_ROT); + auto* rigidBodyComponent = SHComponentManager::GetComponent_s(entityID); if (rigidBodyComponent) { rigidBodyComponent->position = WORLD_POS; rigidBodyComponent->orientation = WORLD_ROT; + + // Clear all forces and velocities if editor is stopped + if (SHSystemManager::GetSystem()->editorState == SHEditor::State::STOP) + { + auto* rp3dRigidBody = reinterpret_cast(physicsObject.rp3dBody); + rp3dRigidBody->resetForce(); + rp3dRigidBody->resetTorque(); + rp3dRigidBody->setLinearVelocity(SHVec3::Zero); + rp3dRigidBody->setAngularVelocity(SHVec3::Zero); + } } auto* colliderComponent = SHComponentManager::GetComponent_s(entityID); @@ -517,7 +513,7 @@ namespace SHADE // Add collision shapes back into the body if (colliderComponent != nullptr) { - for (auto& collider : colliderComponent->colliders | std::views::keys) + for (auto& collider : colliderComponent->colliders) physicsObject->AddCollider(&collider); } } @@ -538,7 +534,7 @@ namespace SHADE } // Add Collision Shapes - for (auto& collider : colliderComponent->colliders | std::views::keys) + for (auto& collider : colliderComponent->colliders) physicsObject->AddCollider(&collider); } } @@ -576,7 +572,7 @@ namespace SHADE rp3d::Transform{ colliderComponent->position, colliderComponent->orientation } ); - for (auto& collider : colliderComponent->colliders | std::views::keys) + for (auto& collider : colliderComponent->colliders) physicsObject->AddCollider(&collider); } diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.cpp b/SHADE_Engine/src/Scene/SHSceneGraph.cpp index 574747ec..df46b3fb 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.cpp +++ b/SHADE_Engine/src/Scene/SHSceneGraph.cpp @@ -582,9 +582,9 @@ namespace SHADE ReleaseNode(node); } - void SHSceneGraph::Traverse (const UnaryFunction& predicate) const + void SHSceneGraph::Traverse (const UnaryFunction& function) const { - TraverseAndInvokeFunction(root, predicate); + TraverseAndInvokeFunction(root, function); } /*-----------------------------------------------------------------------------------*/ @@ -621,7 +621,7 @@ namespace SHADE delete node; } - void SHSceneGraph::TraverseAndInvokeFunction (const SHSceneNode* node, const UnaryFunction& function) + void SHSceneGraph::TraverseAndInvokeFunction(const SHSceneNode* node, const UnaryFunction& function) { for (auto* child : node->children) { diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.h b/SHADE_Engine/src/Scene/SHSceneGraph.h index b52fd1ff..45ab48e5 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.h +++ b/SHADE_Engine/src/Scene/SHSceneGraph.h @@ -142,7 +142,7 @@ namespace SHADE bool RemoveNode (SHSceneNode* nodeToRemove) noexcept; void Reset () noexcept; - void Traverse (const UnaryFunction& predicate) const; + void Traverse (const UnaryFunction& function) const; private: /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index f0f8912b..21ce7b82 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -417,13 +417,13 @@ namespace SHADE ( DEFAULT_CSHARP_LIB_NAME, DEFAULT_CSHARP_NAMESPACE + ".Collider", - "OnColliderBoundChanged" + "OnCollisionShapeChanged" ); csColliderOnRemoved = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, DEFAULT_CSHARP_NAMESPACE + ".Collider", - "OnColliderRemoved" + "OnCollisionShapeRemoved" ); csEditorRenderScripts = dotNet.GetFunctionPtr ( diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx index 6d2c2f01..f2119b43 100644 --- a/SHADE_Managed/src/Components/Collider.cxx +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -22,7 +22,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* ColliderBound - Constructors */ /*---------------------------------------------------------------------------------*/ - ColliderBound::ColliderBound(int arrayIdx, Entity attachedEntity) + CollisionShape::CollisionShape(int arrayIdx, Entity attachedEntity) : arrayIndex { arrayIdx } , entity { attachedEntity } {} @@ -30,7 +30,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* ColliderBound - Setter Functions */ /*---------------------------------------------------------------------------------*/ - void ColliderBound::updateArrayIndex(int index) + void CollisionShape::updateArrayIndex(int index) { arrayIndex = index; } @@ -38,42 +38,42 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* BoxColliderBound - Constructors */ /*---------------------------------------------------------------------------------*/ - BoxColliderBound::BoxColliderBound(int arrayIdx, Entity attachedEntity) - : ColliderBound { arrayIndex, attachedEntity } + BoxCollider::BoxCollider(int arrayIdx, Entity attachedEntity) + : CollisionShape { arrayIndex, attachedEntity } {} /*---------------------------------------------------------------------------------*/ /* BoxColliderBound - Properties */ /*---------------------------------------------------------------------------------*/ - Vector3 BoxColliderBound::Center::get() + Vector3 BoxCollider::Center::get() { return Convert::ToCLI(getNativeBoundObject().GetCenter()); } - void BoxColliderBound::Center::set(Vector3 value) + void BoxCollider::Center::set(Vector3 value) { getNativeBoundObject().SetCenter(Convert::ToNative(value)); } - Vector3 BoxColliderBound::HalfExtents::get() + Vector3 BoxCollider::HalfExtents::get() { return Convert::ToCLI(getNativeBoundObject().GetHalfExtents()); } - void BoxColliderBound::HalfExtents::set(Vector3 value) + void BoxCollider::HalfExtents::set(Vector3 value) { getNativeBoundObject().SetHalfExtents(Convert::ToNative(value)); } - Vector3 BoxColliderBound::Min::get() + Vector3 BoxCollider::Min::get() { return Convert::ToCLI(getNativeBoundObject().GetMin()); } - void BoxColliderBound::Min::set(Vector3 value) + void BoxCollider::Min::set(Vector3 value) { getNativeBoundObject().SetMin(Convert::ToNative(value)); } - Vector3 BoxColliderBound::Max::get() + Vector3 BoxCollider::Max::get() { return Convert::ToCLI(getNativeBoundObject().GetMax()); } - void BoxColliderBound::Max::set(Vector3 value) + void BoxCollider::Max::set(Vector3 value) { getNativeBoundObject().SetMax(Convert::ToNative(value)); } @@ -81,11 +81,11 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* BoxColliderBound - Usage Functions */ /*---------------------------------------------------------------------------------*/ - bool BoxColliderBound::TestPoint(Vector3 point) + bool BoxCollider::TestPoint(Vector3 point) { return getNativeBoundObject().TestPoint(Convert::ToNative(point)); } - bool BoxColliderBound::Raycast(Ray ray, float maxDistance) + bool BoxCollider::Raycast(Ray ray, float maxDistance) { return getNativeBoundObject().Raycast(Convert::ToNative(ray), maxDistance); } @@ -93,19 +93,19 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* BoxColliderBound - Properties */ /*---------------------------------------------------------------------------------*/ - Vector3 SphereColliderBound::Center::get() + Vector3 SphereCollider::Center::get() { return Convert::ToCLI(getNativeBoundObject().GetCenter()); } - void SphereColliderBound::Center::set(Vector3 value) + void SphereCollider::Center::set(Vector3 value) { getNativeBoundObject().SetCenter(Convert::ToNative(value)); } - float SphereColliderBound::Radius::get() + float SphereCollider::Radius::get() { return getNativeBoundObject().GetRadius(); } - void SphereColliderBound::Radius::set(float value) + void SphereCollider::Radius::set(float value) { getNativeBoundObject().SetRadius(value); } @@ -113,11 +113,11 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* SphereColliderBound - Usage Functions */ /*---------------------------------------------------------------------------------*/ - bool SphereColliderBound::TestPoint(Vector3 point) + bool SphereCollider::TestPoint(Vector3 point) { return getNativeBoundObject().TestPoint(Convert::ToNative(point)); } - bool SphereColliderBound::Raycast(Ray ray, float maxDistance) + bool SphereCollider::Raycast(Ray ray, float maxDistance) { return getNativeBoundObject().Raycast(Convert::ToNative(ray), maxDistance); } @@ -125,8 +125,8 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* SphereColliderBound - Constructors */ /*---------------------------------------------------------------------------------*/ - SphereColliderBound::SphereColliderBound(int arrayIndex, Entity attachedEntity) - : ColliderBound{ arrayIndex, attachedEntity } + SphereCollider::SphereCollider(int arrayIndex, Entity attachedEntity) + : CollisionShape{ arrayIndex, attachedEntity } {} /*---------------------------------------------------------------------------------*/ @@ -137,7 +137,7 @@ namespace SHADE { // Create lists if they don't exist if (colliders == nullptr) - colliders = gcnew CollidersMap; + colliders = gcnew ColliderMap; if (!colliders->ContainsKey(entity)) colliders->Add(entity, gcnew WeakReferenceList()); @@ -148,7 +148,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Collider - Properties */ /*---------------------------------------------------------------------------------*/ - int Collider::ColliderBoundsCount::get() + int Collider::CollisionShapeCount::get() { return static_cast(GetNativeComponent()->GetColliders().size()); } @@ -156,7 +156,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Collider - ColliderBound Functions */ /*---------------------------------------------------------------------------------*/ - ColliderBound^ Collider::GetColliderBound(int index) + CollisionShape^ Collider::GetCollisionShape(int index) { // Populate the list if it hasn't been if (subColliderList == nullptr) @@ -172,15 +172,15 @@ namespace SHADE return subColliderList[index]; } generic - T Collider::GetColliderBound(int index) + T Collider::GetCollisionShape(int index) { - return safe_cast(GetColliderBound(index)); + return safe_cast(GetCollisionShape(index)); } /*---------------------------------------------------------------------------------*/ /* Event Handling Functions */ /*---------------------------------------------------------------------------------*/ - void Collider::OnColliderRemoved(EntityID entity) + void Collider::OnCollisionShapeRemoved(EntityID entity) { SAFE_NATIVE_CALL_BEGIN // Check if there are any colliders to update @@ -192,7 +192,7 @@ namespace SHADE SAFE_NATIVE_CALL_END("Collider.OnColliderRemoved") } - void Collider::OnColliderBoundChanged(EntityID entity) + void Collider::OnCollisionShapeChanged(EntityID entity) { SAFE_NATIVE_CALL_BEGIN // Check if there are any colliders to update @@ -226,20 +226,20 @@ namespace SHADE if (subColliderList) subColliderList->Clear(); else - subColliderList = gcnew System::Collections::Generic::List(); + subColliderList = gcnew System::Collections::Generic::List(); // Populate the list int i = 0; for (const auto& collider : GetNativeComponent()->GetColliders()) { - ColliderBound^ bound = nullptr; - switch (collider.first.GetType()) + CollisionShape^ bound = nullptr; + switch (collider.GetType()) { case SHCollider::Type::BOX: - bound = gcnew BoxColliderBound(i, Owner.GetEntity()); + bound = gcnew BoxCollider(i, Owner.GetEntity()); break; case SHCollider::Type::SPHERE: - bound = gcnew SphereColliderBound(i, Owner.GetEntity()); + bound = gcnew SphereCollider(i, Owner.GetEntity()); break; case SHCollider::Type::CAPSULE: // TODO diff --git a/SHADE_Managed/src/Components/Collider.h++ b/SHADE_Managed/src/Components/Collider.h++ index 66f77e18..1f8b43eb 100644 --- a/SHADE_Managed/src/Components/Collider.h++ +++ b/SHADE_Managed/src/Components/Collider.h++ @@ -18,8 +18,8 @@ of DigiPen Institute of Technology is prohibited. #include "Component.hxx" namespace SHADE { - template - ColliderBoundType& SHADE::ColliderBound::getNativeBoundObject() + template + CollisionShapeType& SHADE::CollisionShape::getNativeBoundObject() { SHColliderComponent* collider = SHComponentManager::GetComponent_s(entity); if (!collider) @@ -31,7 +31,7 @@ namespace SHADE if (bounds.GetType() != SHCollider::Type::BOX) throw gcnew System::InvalidOperationException("Attempted to retrieve invalid ColliderBound."); - return reinterpret_cast(bounds); + return reinterpret_cast(bounds); } catch (std::invalid_argument&) { diff --git a/SHADE_Managed/src/Components/Collider.hxx b/SHADE_Managed/src/Components/Collider.hxx index f827ab71..9555976f 100644 --- a/SHADE_Managed/src/Components/Collider.hxx +++ b/SHADE_Managed/src/Components/Collider.hxx @@ -27,7 +27,7 @@ namespace SHADE /// /// Base interface for all Collider Shapes. /// - public ref class ColliderBound + public ref class CollisionShape { public: /*-----------------------------------------------------------------------------*/ @@ -51,7 +51,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Constructors */ /*-----------------------------------------------------------------------------*/ - ColliderBound(int arrayIdx, Entity attachedEntity); + CollisionShape(int arrayIdx, Entity attachedEntity); /*-----------------------------------------------------------------------------*/ /* Data Members */ @@ -62,8 +62,8 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Helper Functions */ /*-----------------------------------------------------------------------------*/ - template - ColliderBoundType& getNativeBoundObject(); + template + CollisionShapeType& getNativeBoundObject(); internal: /*-----------------------------------------------------------------------------*/ @@ -75,7 +75,7 @@ namespace SHADE /// /// Box-shaped Collider Bound. /// - public ref class BoxColliderBound : public ColliderBound + public ref class BoxCollider : public CollisionShape { public: /*-----------------------------------------------------------------------------*/ @@ -128,13 +128,13 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Constructors */ /*-----------------------------------------------------------------------------*/ - BoxColliderBound(int arrayIndex, Entity attachedEntity); + BoxCollider(int arrayIndex, Entity attachedEntity); }; /// /// Sphere-shaped Collider Bound. /// - public ref class SphereColliderBound : public ColliderBound + public ref class SphereCollider : public CollisionShape { public: /*-----------------------------------------------------------------------------*/ @@ -169,7 +169,7 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Constructors */ /*-----------------------------------------------------------------------------*/ - SphereColliderBound(int arrayIndex, Entity attachedEntity); + SphereCollider(int arrayIndex, Entity attachedEntity); }; /// @@ -196,7 +196,7 @@ namespace SHADE /// /// Total number of ColliderBounds in the Collider component. /// - property int ColliderBoundsCount + property int CollisionShapeCount { int get(); } @@ -209,7 +209,7 @@ namespace SHADE /// /// Index to retrieve a ColliderBound from. /// ColliderBound for the specified index. - ColliderBound^ GetColliderBound(int index); + CollisionShape^ GetCollisionShape(int index); /// /// Retrieves a ColliderBound at the specified index in the ColliderBound list /// and casts it to the appropriate type. @@ -217,42 +217,42 @@ namespace SHADE /// Type of the ColliderBound to cast to. /// Index to retrieve a ColliderBound from. /// ColliderBound for the specified index. - generic where T:ColliderBound - T GetColliderBound(int index); + generic where T:CollisionShape + T GetCollisionShape(int index); internal: /*-----------------------------------------------------------------------------*/ /* Event Handling Functions */ /*-----------------------------------------------------------------------------*/ /// - /// To be called from native code when a collider has been removed. + /// To be called from native code when a collision shape has been removed. /// - /// The entity which has it's collider removed. - static void OnColliderRemoved(EntityID entity); + /// The entity which has it's collision shape removed. + static void OnCollisionShapeRemoved(EntityID entity); /// - /// To be called from native code when a Collider bound has been removed. + /// To be called from native code when a Collision Shape has been changed. /// /// - /// The entity which has it's collider bounds changed. + /// The entity which has it's collision shape changed. /// - static void OnColliderBoundChanged(EntityID entity); + static void OnCollisionShapeChanged(EntityID entity); private: /*-----------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------*/ using WeakReferenceList = System::Collections::Generic::List; - using CollidersMap = System::Collections::Generic::Dictionary; + using ColliderMap = System::Collections::Generic::Dictionary; /*-----------------------------------------------------------------------------*/ /* Static Data Members */ /*-----------------------------------------------------------------------------*/ - static CollidersMap^ colliders; + static ColliderMap^ colliders; /*-----------------------------------------------------------------------------*/ /* Data Members */ /*-----------------------------------------------------------------------------*/ - System::Collections::Generic::List^ subColliderList; + System::Collections::Generic::List^ subColliderList; /*-----------------------------------------------------------------------------*/ /* Helper Functions */