Added UI functionality to the Graphics System #232
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Report a bug that should be fixed
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest a feature for the project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
|
@ -223,9 +223,4 @@
|
|||
Bounciness: 0
|
||||
Density: 1
|
||||
Position Offset: {x: 0, y: 0.5, z: 0}
|
||||
Scripts:
|
||||
- Type: Item
|
||||
currCategory: 0
|
||||
- Type: PickAndThrow
|
||||
throwForce: [100, 200, 100]
|
||||
item: 51000
|
||||
Scripts: ~
|
|
@ -560,6 +560,34 @@ namespace SHADE
|
|||
assetCollection.emplace(newAsset.id, newAsset);
|
||||
SHAssetMetaHandler::WriteMetaData(newAsset);
|
||||
|
||||
return newAsset.id;
|
||||
}
|
||||
else if (ext == SCENE_EXTENSION)
|
||||
{
|
||||
SHAsset newAsset{
|
||||
path.stem().string(),
|
||||
GenerateAssetID(AssetType::SCENE),
|
||||
AssetType::SCENE,
|
||||
path,
|
||||
false
|
||||
};
|
||||
assetCollection.emplace(newAsset.id, newAsset);
|
||||
SHAssetMetaHandler::WriteMetaData(newAsset);
|
||||
|
||||
return newAsset.id;
|
||||
}
|
||||
else if (ext == FONT_EXTENSION)
|
||||
{
|
||||
SHAsset newAsset{
|
||||
path.stem().string(),
|
||||
GenerateAssetID(AssetType::FONT),
|
||||
AssetType::FONT,
|
||||
path,
|
||||
false
|
||||
};
|
||||
assetCollection.emplace(newAsset.id, newAsset);
|
||||
SHAssetMetaHandler::WriteMetaData(newAsset);
|
||||
|
||||
return newAsset.id;
|
||||
}
|
||||
}
|
||||
|
@ -571,8 +599,11 @@ namespace SHADE
|
|||
|
||||
for (auto& file : toGenNew)
|
||||
{
|
||||
auto newID{ GenerateNewMeta(file->path).value() };
|
||||
file->assetMeta = &assetCollection[newID];
|
||||
auto newID{ GenerateNewMeta(file->path) };
|
||||
if (newID.has_value())
|
||||
{
|
||||
file->assetMeta = &assetCollection[newID.value()];
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& asset : std::ranges::views::values(assetCollection))
|
||||
|
|
|
@ -223,7 +223,7 @@ namespace SHADE
|
|||
{
|
||||
if (!component)
|
||||
return;
|
||||
|
||||
ImGui::PushID(component);
|
||||
const auto componentType = rttr::type::get(*component);
|
||||
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
|
||||
ImGui::SameLine();
|
||||
|
@ -246,7 +246,7 @@ namespace SHADE
|
|||
if (collider->GetType() == SHCollisionShape::Type::BOX)
|
||||
{
|
||||
SHEditorWidgets::BeginPanel(std::format("{} Box #{}", ICON_FA_CUBE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
|
||||
const auto* BOX = reinterpret_cast<const SHBoundingBox*>(collider->GetShape());
|
||||
const auto* BOX = reinterpret_cast<const SHBox*>(collider->GetShape());
|
||||
SHEditorWidgets::DragVec3
|
||||
(
|
||||
"Half Extents", { "X", "Y", "Z" },
|
||||
|
@ -256,7 +256,7 @@ namespace SHADE
|
|||
else if (collider->GetType() == SHCollisionShape::Type::SPHERE)
|
||||
{
|
||||
SHEditorWidgets::BeginPanel(std::format("{} Sphere #{}", ICON_MD_CIRCLE, i).data(), { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y });
|
||||
const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(collider->GetShape());
|
||||
const auto* SPHERE = reinterpret_cast<const SHSphere*>(collider->GetShape());
|
||||
SHEditorWidgets::DragFloat
|
||||
(
|
||||
"Radius",
|
||||
|
@ -322,6 +322,7 @@ namespace SHADE
|
|||
}
|
||||
}
|
||||
else DrawContextMenu(component);
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
|
@ -34,8 +34,11 @@ namespace SHADE
|
|||
void SHRenderable::OnDestroy()
|
||||
{
|
||||
// Remove from SuperBatch
|
||||
if (sharedMaterial)
|
||||
{
|
||||
Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
|
||||
superBatch->Remove(this);
|
||||
}
|
||||
|
||||
// Free resources
|
||||
if (material)
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <SHpch.h>
|
||||
|
||||
// Primary Header
|
||||
#include "SHBoundingBox.h"
|
||||
#include "SHBox.h"
|
||||
// Project Headers
|
||||
#include "Math/SHMathHelpers.h"
|
||||
#include "Math/SHRay.h"
|
||||
|
@ -24,13 +24,13 @@ namespace SHADE
|
|||
/* Constructors & Destructor Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHBoundingBox::SHBoundingBox() noexcept
|
||||
SHBox::SHBox() noexcept
|
||||
: RelativeExtents { SHVec3::One }
|
||||
{
|
||||
type = Type::BOX;
|
||||
}
|
||||
|
||||
SHBoundingBox::SHBoundingBox(const SHVec3& c, const SHVec3& hE) noexcept
|
||||
SHBox::SHBox(const SHVec3& c, const SHVec3& hE) noexcept
|
||||
: RelativeExtents { SHVec3::One }
|
||||
{
|
||||
type = Type::BOX;
|
||||
|
@ -40,7 +40,7 @@ namespace SHADE
|
|||
}
|
||||
|
||||
|
||||
SHBoundingBox::SHBoundingBox(const SHBoundingBox& rhs) noexcept
|
||||
SHBox::SHBox(const SHBox& rhs) noexcept
|
||||
{
|
||||
if (this == &rhs)
|
||||
return;
|
||||
|
@ -52,7 +52,7 @@ namespace SHADE
|
|||
RelativeExtents = rhs.RelativeExtents;
|
||||
}
|
||||
|
||||
SHBoundingBox::SHBoundingBox(SHBoundingBox&& rhs) noexcept
|
||||
SHBox::SHBox(SHBox&& rhs) noexcept
|
||||
{
|
||||
type = Type::BOX;
|
||||
|
||||
|
@ -65,7 +65,7 @@ namespace SHADE
|
|||
/* Operator Overload Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHBoundingBox& SHBoundingBox::operator=(const SHBoundingBox& rhs) noexcept
|
||||
SHBox& SHBox::operator=(const SHBox& rhs) noexcept
|
||||
{
|
||||
if (rhs.type != Type::BOX)
|
||||
{
|
||||
|
@ -81,7 +81,7 @@ namespace SHADE
|
|||
return *this;
|
||||
}
|
||||
|
||||
SHBoundingBox& SHBoundingBox::operator=(SHBoundingBox&& rhs) noexcept
|
||||
SHBox& SHBox::operator=(SHBox&& rhs) noexcept
|
||||
{
|
||||
if (rhs.type != Type::BOX)
|
||||
{
|
||||
|
@ -101,27 +101,27 @@ namespace SHADE
|
|||
/* Getter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHVec3 SHBoundingBox::GetCenter() const noexcept
|
||||
SHVec3 SHBox::GetCenter() const noexcept
|
||||
{
|
||||
return Center;
|
||||
}
|
||||
|
||||
SHVec3 SHBoundingBox::GetWorldExtents() const noexcept
|
||||
SHVec3 SHBox::GetWorldExtents() const noexcept
|
||||
{
|
||||
return Extents;
|
||||
}
|
||||
|
||||
const SHVec3& SHBoundingBox::GetRelativeExtents() const noexcept
|
||||
const SHVec3& SHBox::GetRelativeExtents() const noexcept
|
||||
{
|
||||
return RelativeExtents;
|
||||
}
|
||||
|
||||
SHVec3 SHBoundingBox::GetMin() const noexcept
|
||||
SHVec3 SHBox::GetMin() const noexcept
|
||||
{
|
||||
return SHVec3{ Center.x - Extents.x, Center.y - Extents.y, Center.z - Extents.z };
|
||||
}
|
||||
|
||||
SHVec3 SHBoundingBox::GetMax() const noexcept
|
||||
SHVec3 SHBox::GetMax() const noexcept
|
||||
{
|
||||
return SHVec3{ Center.x + Extents.x, Center.y + Extents.y, Center.z + Extents.z };
|
||||
}
|
||||
|
@ -130,22 +130,22 @@ namespace SHADE
|
|||
/* Setter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHBoundingBox::SetCenter(const SHVec3& newCenter) noexcept
|
||||
void SHBox::SetCenter(const SHVec3& newCenter) noexcept
|
||||
{
|
||||
Center = newCenter;
|
||||
}
|
||||
|
||||
void SHBoundingBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept
|
||||
void SHBox::SetWorldExtents(const SHVec3& newWorldExtents) noexcept
|
||||
{
|
||||
Extents = newWorldExtents;
|
||||
}
|
||||
|
||||
void SHBoundingBox::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept
|
||||
void SHBox::SetRelativeExtents(const SHVec3& newRelativeExtents) noexcept
|
||||
{
|
||||
RelativeExtents = newRelativeExtents;
|
||||
}
|
||||
|
||||
void SHBoundingBox::SetMin(const SHVec3& min) noexcept
|
||||
void SHBox::SetMin(const SHVec3& min) noexcept
|
||||
{
|
||||
const SHVec3 MAX = GetMax();
|
||||
|
||||
|
@ -153,7 +153,7 @@ namespace SHADE
|
|||
Extents = SHVec3::Abs((MAX - min) * 0.5f);
|
||||
}
|
||||
|
||||
void SHBoundingBox::SetMax(const SHVec3& max) noexcept
|
||||
void SHBox::SetMax(const SHVec3& max) noexcept
|
||||
{
|
||||
const SHVec3 MIN = GetMin();
|
||||
|
||||
|
@ -161,13 +161,13 @@ namespace SHADE
|
|||
Extents = SHVec3::Abs((max - MIN) * 0.5f);
|
||||
}
|
||||
|
||||
void SHBoundingBox::SetMinMax(const SHVec3& min, const SHVec3& max) noexcept
|
||||
void SHBox::SetMinMax(const SHVec3& min, const SHVec3& max) noexcept
|
||||
{
|
||||
Center = SHVec3::Lerp(min, max, 0.5f);
|
||||
Extents = SHVec3::Abs((max - min) * 0.5f);
|
||||
}
|
||||
|
||||
std::vector<SHVec3> SHBoundingBox::GetVertices() const noexcept
|
||||
std::vector<SHVec3> SHBox::GetVertices() const noexcept
|
||||
{
|
||||
std::vector<SHVec3> vertices{ 8 };
|
||||
GetCorners(vertices.data());
|
||||
|
@ -178,27 +178,27 @@ namespace SHADE
|
|||
/* Public Function Member Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
bool SHBoundingBox::TestPoint(const SHVec3& point) noexcept
|
||||
bool SHBox::TestPoint(const SHVec3& point) noexcept
|
||||
{
|
||||
return BoundingBox::Contains(point);
|
||||
}
|
||||
|
||||
bool SHBoundingBox::Raycast(const SHRay& ray, float& distance) noexcept
|
||||
bool SHBox::Raycast(const SHRay& ray, float& distance) noexcept
|
||||
{
|
||||
return BoundingBox::Intersects(ray.position, ray.direction, distance);
|
||||
}
|
||||
|
||||
bool SHBoundingBox::Contains(const SHBoundingBox& rhs) const noexcept
|
||||
bool SHBox::Contains(const SHBox& rhs) const noexcept
|
||||
{
|
||||
return BoundingBox::Contains(rhs);
|
||||
}
|
||||
|
||||
float SHBoundingBox::Volume() const noexcept
|
||||
float SHBox::Volume() const noexcept
|
||||
{
|
||||
return 8.0f * (Extents.x * Extents.y * Extents.z);
|
||||
}
|
||||
|
||||
float SHBoundingBox::SurfaceArea() const noexcept
|
||||
float SHBox::SurfaceArea() const noexcept
|
||||
{
|
||||
return 8.0f * ((Extents.x * Extents.y)
|
||||
+ (Extents.x * Extents.z)
|
||||
|
@ -209,21 +209,21 @@ namespace SHADE
|
|||
/* Static Function Member Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHBoundingBox SHBoundingBox::Combine(const SHBoundingBox& lhs, const SHBoundingBox& rhs) noexcept
|
||||
SHBox SHBox::Combine(const SHBox& lhs, const SHBox& rhs) noexcept
|
||||
{
|
||||
SHBoundingBox result;
|
||||
SHBox result;
|
||||
CreateMerged(result, lhs, rhs);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SHBoundingBox::Intersect(const SHBoundingBox& lhs, const SHBoundingBox& rhs) noexcept
|
||||
bool SHBox::Intersect(const SHBox& lhs, const SHBox& rhs) noexcept
|
||||
{
|
||||
return lhs.Intersects(rhs);
|
||||
}
|
||||
|
||||
SHBoundingBox SHBoundingBox::BuildFromBoxes(const SHBoundingBox* boxes, size_t numBoxes) noexcept
|
||||
SHBox SHBox::BuildFromBoxes(const SHBox* boxes, size_t numBoxes) noexcept
|
||||
{
|
||||
SHBoundingBox result;
|
||||
SHBox result;
|
||||
|
||||
for (size_t i = 1; i < numBoxes; ++i)
|
||||
CreateMerged(result, boxes[i - 1], boxes[i]);
|
||||
|
@ -231,9 +231,9 @@ namespace SHADE
|
|||
return result;
|
||||
}
|
||||
|
||||
SHBoundingBox SHBoundingBox::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept
|
||||
SHBox SHBox::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept
|
||||
{
|
||||
SHBoundingBox result;
|
||||
SHBox result;
|
||||
CreateFromPoints(result, numVertices, vertices, stride);
|
||||
return result;
|
||||
}
|
|
@ -22,7 +22,7 @@ namespace SHADE
|
|||
/* Type Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
class SH_API SHBoundingBox : public SHShape,
|
||||
class SH_API SHBox : public SHShape,
|
||||
private DirectX::BoundingBox
|
||||
{
|
||||
public:
|
||||
|
@ -36,19 +36,19 @@ namespace SHADE
|
|||
/* Constructors & Destructor */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
~SHBoundingBox () override = default;
|
||||
~SHBox () override = default;
|
||||
|
||||
SHBoundingBox () noexcept;
|
||||
SHBoundingBox (const SHVec3& center, const SHVec3& halfExtents) noexcept;
|
||||
SHBoundingBox (const SHBoundingBox& rhs) noexcept;
|
||||
SHBoundingBox (SHBoundingBox&& rhs) noexcept;
|
||||
SHBox () noexcept;
|
||||
SHBox (const SHVec3& center, const SHVec3& halfExtents) noexcept;
|
||||
SHBox (const SHBox& rhs) noexcept;
|
||||
SHBox (SHBox&& rhs) noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Operator Overloads */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
SHBoundingBox& operator= (const SHBoundingBox& rhs) noexcept;
|
||||
SHBoundingBox& operator= (SHBoundingBox&& rhs) noexcept;
|
||||
SHBox& operator= (const SHBox& rhs) noexcept;
|
||||
SHBox& operator= (SHBox&& rhs) noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Getter Functions */
|
||||
|
@ -79,7 +79,7 @@ namespace SHADE
|
|||
[[nodiscard]] bool TestPoint (const SHVec3& point) noexcept override;
|
||||
[[nodiscard]] bool Raycast (const SHRay& ray, float& distance) noexcept override;
|
||||
|
||||
[[nodiscard]] bool Contains (const SHBoundingBox& rhs) const noexcept;
|
||||
[[nodiscard]] bool Contains (const SHBox& rhs) const noexcept;
|
||||
[[nodiscard]] float Volume () const noexcept;
|
||||
[[nodiscard]] float SurfaceArea () const noexcept;
|
||||
|
||||
|
@ -87,10 +87,10 @@ namespace SHADE
|
|||
/* Static Function Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] static SHBoundingBox Combine (const SHBoundingBox& lhs, const SHBoundingBox& rhs) noexcept;
|
||||
[[nodiscard]] static bool Intersect (const SHBoundingBox& lhs, const SHBoundingBox& rhs) noexcept;
|
||||
[[nodiscard]] static SHBoundingBox BuildFromBoxes (const SHBoundingBox* boxes, size_t numBoxes) noexcept;
|
||||
[[nodiscard]] static SHBoundingBox BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept;
|
||||
[[nodiscard]] static SHBox Combine (const SHBox& lhs, const SHBox& rhs) noexcept;
|
||||
[[nodiscard]] static bool Intersect (const SHBox& lhs, const SHBox& rhs) noexcept;
|
||||
[[nodiscard]] static SHBox BuildFromBoxes (const SHBox* boxes, size_t numBoxes) noexcept;
|
||||
[[nodiscard]] static SHBox BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept;
|
||||
|
||||
private:
|
||||
/*---------------------------------------------------------------------------------*/
|
|
@ -11,7 +11,7 @@
|
|||
#include <SHpch.h>
|
||||
|
||||
// Primary Header
|
||||
#include "SHBoundingSphere.h"
|
||||
#include "SHSphere.h"
|
||||
// Project Headers
|
||||
#include "Math/SHMathHelpers.h"
|
||||
#include "Math/SHRay.h"
|
||||
|
@ -24,13 +24,13 @@ namespace SHADE
|
|||
/* Constructors & Destructor Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHBoundingSphere::SHBoundingSphere() noexcept
|
||||
SHSphere::SHSphere() noexcept
|
||||
: RelativeRadius { 1.0f }
|
||||
{
|
||||
type = Type::SPHERE;
|
||||
}
|
||||
|
||||
SHBoundingSphere::SHBoundingSphere(const SHVec3& center, float radius) noexcept
|
||||
SHSphere::SHSphere(const SHVec3& center, float radius) noexcept
|
||||
: RelativeRadius { 1.0f }
|
||||
{
|
||||
type = Type::SPHERE;
|
||||
|
@ -39,7 +39,7 @@ namespace SHADE
|
|||
Radius = radius;
|
||||
}
|
||||
|
||||
SHBoundingSphere::SHBoundingSphere(const SHBoundingSphere& rhs) noexcept
|
||||
SHSphere::SHSphere(const SHSphere& rhs) noexcept
|
||||
{
|
||||
if (this == &rhs)
|
||||
return;
|
||||
|
@ -51,7 +51,7 @@ namespace SHADE
|
|||
RelativeRadius = rhs.RelativeRadius;
|
||||
}
|
||||
|
||||
SHBoundingSphere::SHBoundingSphere(SHBoundingSphere&& rhs) noexcept
|
||||
SHSphere::SHSphere(SHSphere&& rhs) noexcept
|
||||
{
|
||||
type = Type::SPHERE;
|
||||
|
||||
|
@ -64,7 +64,7 @@ namespace SHADE
|
|||
/* Operator Overload Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHBoundingSphere& SHBoundingSphere::operator=(const SHBoundingSphere& rhs) noexcept
|
||||
SHSphere& SHSphere::operator=(const SHSphere& rhs) noexcept
|
||||
{
|
||||
if (rhs.type != Type::SPHERE)
|
||||
{
|
||||
|
@ -80,7 +80,7 @@ namespace SHADE
|
|||
return *this;
|
||||
}
|
||||
|
||||
SHBoundingSphere& SHBoundingSphere::operator=(SHBoundingSphere&& rhs) noexcept
|
||||
SHSphere& SHSphere::operator=(SHSphere&& rhs) noexcept
|
||||
{
|
||||
if (rhs.type != Type::SPHERE)
|
||||
{
|
||||
|
@ -100,17 +100,17 @@ namespace SHADE
|
|||
/* Getter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHVec3 SHBoundingSphere::GetCenter() const noexcept
|
||||
SHVec3 SHSphere::GetCenter() const noexcept
|
||||
{
|
||||
return Center;
|
||||
}
|
||||
|
||||
float SHBoundingSphere::GetWorldRadius() const noexcept
|
||||
float SHSphere::GetWorldRadius() const noexcept
|
||||
{
|
||||
return Radius;
|
||||
}
|
||||
|
||||
float SHBoundingSphere::GetRelativeRadius() const noexcept
|
||||
float SHSphere::GetRelativeRadius() const noexcept
|
||||
{
|
||||
return RelativeRadius;
|
||||
}
|
||||
|
@ -119,17 +119,17 @@ namespace SHADE
|
|||
/* Setter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHBoundingSphere::SetCenter(const SHVec3& center) noexcept
|
||||
void SHSphere::SetCenter(const SHVec3& center) noexcept
|
||||
{
|
||||
Center = center;
|
||||
}
|
||||
|
||||
void SHBoundingSphere::SetWorldRadius(float newWorldRadius) noexcept
|
||||
void SHSphere::SetWorldRadius(float newWorldRadius) noexcept
|
||||
{
|
||||
Radius = newWorldRadius;
|
||||
}
|
||||
|
||||
void SHBoundingSphere::SetRelativeRadius(float newRelativeRadius) noexcept
|
||||
void SHSphere::SetRelativeRadius(float newRelativeRadius) noexcept
|
||||
{
|
||||
RelativeRadius = newRelativeRadius;
|
||||
}
|
||||
|
@ -138,27 +138,27 @@ namespace SHADE
|
|||
/* Public Function Member Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
bool SHBoundingSphere::TestPoint(const SHVec3& point) noexcept
|
||||
bool SHSphere::TestPoint(const SHVec3& point) noexcept
|
||||
{
|
||||
return BoundingSphere::Contains(point);
|
||||
}
|
||||
|
||||
bool SHBoundingSphere::Raycast(const SHRay& ray, float& distance) noexcept
|
||||
bool SHSphere::Raycast(const SHRay& ray, float& distance) noexcept
|
||||
{
|
||||
return Intersects(ray.position, ray.direction, distance);
|
||||
}
|
||||
|
||||
bool SHBoundingSphere::Contains(const SHBoundingSphere& rhs) const noexcept
|
||||
bool SHSphere::Contains(const SHSphere& rhs) const noexcept
|
||||
{
|
||||
return BoundingSphere::Contains(rhs);
|
||||
}
|
||||
|
||||
float SHBoundingSphere::Volume() const noexcept
|
||||
float SHSphere::Volume() const noexcept
|
||||
{
|
||||
return (4.0f / 3.0f) * SHMath::PI * (Radius * Radius * Radius);
|
||||
}
|
||||
|
||||
float SHBoundingSphere::SurfaceArea() const noexcept
|
||||
float SHSphere::SurfaceArea() const noexcept
|
||||
{
|
||||
return 4.0f * SHMath::PI * (Radius * Radius);
|
||||
}
|
||||
|
@ -167,21 +167,21 @@ namespace SHADE
|
|||
/* Static Function Member Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHBoundingSphere SHBoundingSphere::Combine(const SHBoundingSphere& lhs, const SHBoundingSphere& rhs) noexcept
|
||||
SHSphere SHSphere::Combine(const SHSphere& lhs, const SHSphere& rhs) noexcept
|
||||
{
|
||||
SHBoundingSphere result;
|
||||
SHSphere result;
|
||||
CreateMerged(result, lhs, rhs);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SHBoundingSphere::Intersect(const SHBoundingSphere& lhs, const SHBoundingSphere& rhs) noexcept
|
||||
bool SHSphere::Intersect(const SHSphere& lhs, const SHSphere& rhs) noexcept
|
||||
{
|
||||
return lhs.Intersects(rhs);
|
||||
}
|
||||
|
||||
SHBoundingSphere SHBoundingSphere::BuildFromSpheres(const SHBoundingSphere* spheres, size_t numSpheres) noexcept
|
||||
SHSphere SHSphere::BuildFromSpheres(const SHSphere* spheres, size_t numSpheres) noexcept
|
||||
{
|
||||
SHBoundingSphere result;
|
||||
SHSphere result;
|
||||
|
||||
for (size_t i = 1; i < numSpheres; ++i)
|
||||
CreateMerged(result, spheres[i - 1], spheres[i]);
|
||||
|
@ -189,9 +189,9 @@ namespace SHADE
|
|||
return result;
|
||||
}
|
||||
|
||||
SHBoundingSphere SHBoundingSphere::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept
|
||||
SHSphere SHSphere::BuildFromVertices(const SHVec3* vertices, size_t numVertices, size_t stride) noexcept
|
||||
{
|
||||
SHBoundingSphere result;
|
||||
SHSphere result;
|
||||
CreateFromPoints(result, numVertices, vertices, stride);
|
||||
return result;
|
||||
}
|
|
@ -22,7 +22,7 @@ namespace SHADE
|
|||
/* Type Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
class SH_API SHBoundingSphere : public SHShape,
|
||||
class SH_API SHSphere : public SHShape,
|
||||
private DirectX::BoundingSphere
|
||||
{
|
||||
public:
|
||||
|
@ -30,19 +30,19 @@ namespace SHADE
|
|||
/* Constructors & Destructor */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
SHBoundingSphere () noexcept;
|
||||
SHBoundingSphere (const SHVec3& center, float radius) noexcept;
|
||||
SHBoundingSphere (const SHBoundingSphere& rhs) noexcept;
|
||||
SHBoundingSphere (SHBoundingSphere&& rhs) noexcept;
|
||||
SHSphere () noexcept;
|
||||
SHSphere (const SHVec3& center, float radius) noexcept;
|
||||
SHSphere (const SHSphere& rhs) noexcept;
|
||||
SHSphere (SHSphere&& rhs) noexcept;
|
||||
|
||||
~SHBoundingSphere () override = default;
|
||||
~SHSphere () override = default;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Operator Overloads */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
SHBoundingSphere& operator= (const SHBoundingSphere& rhs) noexcept;
|
||||
SHBoundingSphere& operator= (SHBoundingSphere&& rhs) noexcept;
|
||||
SHSphere& operator= (const SHSphere& rhs) noexcept;
|
||||
SHSphere& operator= (SHSphere&& rhs) noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Getter Functions */
|
||||
|
@ -67,7 +67,7 @@ namespace SHADE
|
|||
[[nodiscard]] bool TestPoint (const SHVec3& point) noexcept override;
|
||||
[[nodiscard]] bool Raycast (const SHRay& ray, float& distance) noexcept override;
|
||||
|
||||
[[nodiscard]] bool Contains (const SHBoundingSphere& rhs) const noexcept;
|
||||
[[nodiscard]] bool Contains (const SHSphere& rhs) const noexcept;
|
||||
[[nodiscard]] float Volume () const noexcept;
|
||||
[[nodiscard]] float SurfaceArea () const noexcept;
|
||||
|
||||
|
@ -76,10 +76,10 @@ namespace SHADE
|
|||
/* Static Function Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] static SHBoundingSphere Combine (const SHBoundingSphere& lhs, const SHBoundingSphere& rhs) noexcept;
|
||||
[[nodiscard]] static bool Intersect (const SHBoundingSphere& lhs, const SHBoundingSphere& rhs) noexcept;
|
||||
[[nodiscard]] static SHBoundingSphere BuildFromSpheres (const SHBoundingSphere* spheres, size_t numSpheres) noexcept;
|
||||
[[nodiscard]] static SHBoundingSphere BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept;
|
||||
[[nodiscard]] static SHSphere Combine (const SHSphere& lhs, const SHSphere& rhs) noexcept;
|
||||
[[nodiscard]] static bool Intersect (const SHSphere& lhs, const SHSphere& rhs) noexcept;
|
||||
[[nodiscard]] static SHSphere BuildFromSpheres (const SHSphere* spheres, size_t numSpheres) noexcept;
|
||||
[[nodiscard]] static SHSphere BuildFromVertices (const SHVec3* vertices, size_t numVertices, size_t stride = 0) noexcept;
|
||||
|
||||
private:
|
||||
/*---------------------------------------------------------------------------------*/
|
|
@ -95,7 +95,7 @@ namespace SHADE
|
|||
{
|
||||
case SHCollisionShape::Type::BOX:
|
||||
{
|
||||
auto* box = reinterpret_cast<SHBoundingBox*>(collisionShape.shape);
|
||||
auto* box = reinterpret_cast<SHBox*>(collisionShape.shape);
|
||||
const SHVec3& RELATIVE_EXTENTS = box->GetRelativeExtents();
|
||||
|
||||
// Recompute world extents based on new scale and fixed relative extents
|
||||
|
@ -106,7 +106,7 @@ namespace SHADE
|
|||
}
|
||||
case SHCollisionShape::Type::SPHERE:
|
||||
{
|
||||
auto* sphere = reinterpret_cast<SHBoundingSphere*>(collisionShape.shape);
|
||||
auto* sphere = reinterpret_cast<SHSphere*>(collisionShape.shape);
|
||||
const float RELATIVE_RADIUS = sphere->GetRelativeRadius();
|
||||
|
||||
// Recompute world radius based on new scale and fixed radius
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
// Project Headers
|
||||
#include "ECS_Base/Components/SHComponent.h"
|
||||
#include "Math/Geometry/SHBoundingBox.h"
|
||||
#include "Math/Geometry/SHBoundingSphere.h"
|
||||
#include "Math/Geometry/SHBox.h"
|
||||
#include "Math/Geometry/SHSphere.h"
|
||||
#include "SHCollisionShape.h"
|
||||
|
||||
//namespace SHADE
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
// Primary Header
|
||||
#include "SHCollisionShape.h"
|
||||
// Project Headers
|
||||
#include "Math/Geometry/SHBoundingBox.h"
|
||||
#include "Math/Geometry/SHBoundingSphere.h"
|
||||
#include "Math/Geometry/SHBox.h"
|
||||
#include "Math/Geometry/SHSphere.h"
|
||||
#include "Math/SHMathHelpers.h"
|
||||
#include "Reflection/SHReflectionMetadata.h"
|
||||
#include "SHColliderComponent.h"
|
||||
|
@ -37,12 +37,12 @@ namespace SHADE
|
|||
{
|
||||
case Type::BOX:
|
||||
{
|
||||
shape = new SHBoundingBox{ SHVec3::Zero, SHVec3::One };
|
||||
shape = new SHBox{ SHVec3::Zero, SHVec3::One };
|
||||
break;
|
||||
}
|
||||
case Type::SPHERE:
|
||||
{
|
||||
shape = new SHBoundingSphere{ SHVec3::Zero, 0.5f };
|
||||
shape = new SHSphere{ SHVec3::Zero, 0.5f };
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
|
@ -186,10 +186,10 @@ namespace SHADE
|
|||
type = Type::BOX;
|
||||
|
||||
delete shape;
|
||||
shape = new SHBoundingBox{ positionOffset, WORLD_EXTENTS };
|
||||
shape = new SHBox{ positionOffset, WORLD_EXTENTS };
|
||||
}
|
||||
|
||||
auto* box = reinterpret_cast<SHBoundingBox*>(shape);
|
||||
auto* box = reinterpret_cast<SHBox*>(shape);
|
||||
box->SetWorldExtents(WORLD_EXTENTS);
|
||||
box->SetRelativeExtents(halfExtents);
|
||||
}
|
||||
|
@ -209,10 +209,10 @@ namespace SHADE
|
|||
type = Type::SPHERE;
|
||||
|
||||
delete shape;
|
||||
shape = new SHBoundingSphere{ positionOffset, WORLD_RADIUS };
|
||||
shape = new SHSphere{ positionOffset, WORLD_RADIUS };
|
||||
}
|
||||
|
||||
auto* sphere = reinterpret_cast<SHBoundingSphere*>(shape);
|
||||
auto* sphere = reinterpret_cast<SHSphere*>(shape);
|
||||
sphere->SetWorldRadius(WORLD_RADIUS);
|
||||
}
|
||||
|
||||
|
@ -255,12 +255,12 @@ namespace SHADE
|
|||
{
|
||||
case Type::BOX:
|
||||
{
|
||||
reinterpret_cast<SHBoundingBox*>(shape)->SetCenter(positionOffset);
|
||||
reinterpret_cast<SHBox*>(shape)->SetCenter(positionOffset);
|
||||
break;
|
||||
}
|
||||
case Type::SPHERE:
|
||||
{
|
||||
reinterpret_cast<SHBoundingSphere*>(shape)->SetCenter(positionOffset);
|
||||
reinterpret_cast<SHSphere*>(shape)->SetCenter(positionOffset);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
|
@ -283,16 +283,16 @@ namespace SHADE
|
|||
{
|
||||
case Type::BOX:
|
||||
{
|
||||
const auto* RHS_BOX = reinterpret_cast<const SHBoundingBox*>(rhs);
|
||||
const auto* RHS_BOX = reinterpret_cast<const SHBox*>(rhs);
|
||||
|
||||
shape = new SHBoundingBox{ positionOffset, RHS_BOX->GetWorldExtents() };
|
||||
shape = new SHBox{ positionOffset, RHS_BOX->GetWorldExtents() };
|
||||
break;
|
||||
}
|
||||
case Type::SPHERE:
|
||||
{
|
||||
const auto* RHS_SPHERE = reinterpret_cast<const SHBoundingSphere*>(rhs);
|
||||
const auto* RHS_SPHERE = reinterpret_cast<const SHSphere*>(rhs);
|
||||
|
||||
shape = new SHBoundingSphere{ positionOffset, RHS_SPHERE->GetWorldRadius() };
|
||||
shape = new SHSphere{ positionOffset, RHS_SPHERE->GetWorldRadius() };
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
// Project Headers
|
||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||
#include "ECS_Base/Managers/SHComponentManager.h"
|
||||
#include "Scene/SHSceneManager.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
|
@ -26,6 +27,7 @@ namespace SHADE
|
|||
|
||||
SHPhysicsObject::SHPhysicsObject(EntityID eid, rp3d::PhysicsCommon* physicsFactory, rp3d::PhysicsWorld* physicsWorld) noexcept
|
||||
: entityID { eid }
|
||||
, collidersActive { true }
|
||||
, factory { physicsFactory }
|
||||
, world { physicsWorld }
|
||||
, rp3dBody { nullptr }
|
||||
|
@ -148,6 +150,10 @@ namespace SHADE
|
|||
|
||||
void SHPhysicsObject::SyncRigidBody(SHRigidBodyComponent& component) const noexcept
|
||||
{
|
||||
// This state is synced in the pre-update routine
|
||||
if (!rp3dBody->isActive())
|
||||
return;
|
||||
|
||||
if (component.dirtyFlags == 0)
|
||||
return;
|
||||
|
||||
|
@ -267,6 +273,10 @@ namespace SHADE
|
|||
|
||||
void SHPhysicsObject::SyncColliders(SHColliderComponent& component) const noexcept
|
||||
{
|
||||
// This state is synced in the pre-update routine
|
||||
if (!rp3dBody->isActive())
|
||||
return;
|
||||
|
||||
int index = 0;
|
||||
for (auto& collisionShape : component.collisionShapes)
|
||||
{
|
||||
|
@ -299,7 +309,7 @@ namespace SHADE
|
|||
, boxShape.GetRotationOffset()
|
||||
};
|
||||
|
||||
const auto* BOX = reinterpret_cast<const SHBoundingBox*>(boxShape.GetShape());
|
||||
const auto* BOX = reinterpret_cast<const SHBox*>(boxShape.GetShape());
|
||||
rp3d::BoxShape* newBox = factory->createBoxShape(BOX->GetWorldExtents());
|
||||
|
||||
rp3dBody->addCollider(newBox, OFFSETS);
|
||||
|
@ -307,7 +317,7 @@ namespace SHADE
|
|||
|
||||
void SHPhysicsObject::syncBoxShape(int index, SHCollisionShape& boxShape) const noexcept
|
||||
{
|
||||
const auto* BOX = reinterpret_cast<const SHBoundingBox*>(boxShape.GetShape());
|
||||
const auto* BOX = reinterpret_cast<const SHBox*>(boxShape.GetShape());
|
||||
|
||||
auto* rp3dCollider = rp3dBody->getCollider(index);
|
||||
auto* rp3dBox = reinterpret_cast<rp3d::BoxShape*>(rp3dCollider->getCollisionShape());
|
||||
|
@ -332,7 +342,7 @@ namespace SHADE
|
|||
, sphereShape.GetRotationOffset()
|
||||
};
|
||||
|
||||
const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(sphereShape.GetShape());
|
||||
const auto* SPHERE = reinterpret_cast<const SHSphere*>(sphereShape.GetShape());
|
||||
rp3d::SphereShape* newSphere = factory->createSphereShape(SPHERE->GetWorldRadius());
|
||||
|
||||
rp3dBody->addCollider(newSphere, OFFSETS);
|
||||
|
@ -340,7 +350,7 @@ namespace SHADE
|
|||
|
||||
void SHPhysicsObject::syncSphereShape(int index, SHCollisionShape& sphereShape) const noexcept
|
||||
{
|
||||
const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(sphereShape.GetShape());
|
||||
const auto* SPHERE = reinterpret_cast<const SHSphere*>(sphereShape.GetShape());
|
||||
|
||||
auto* rp3dCollider = rp3dBody->getCollider(index);
|
||||
auto* rp3dSphere = reinterpret_cast<rp3d::SphereShape*>(rp3dCollider->getCollisionShape());
|
||||
|
|
|
@ -84,6 +84,7 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
EntityID entityID;
|
||||
bool collidersActive; // Only used to sync with SHADE components
|
||||
|
||||
rp3d::PhysicsCommon* factory;
|
||||
rp3d::PhysicsWorld* world;
|
||||
|
|
|
@ -167,6 +167,7 @@ namespace SHADE
|
|||
if (!COMPONENT_GROUP.rigidBodyComponent && !COMPONENT_GROUP.colliderComponent)
|
||||
{
|
||||
destroyPhysicsObject(COMMAND.eid);
|
||||
wakeAllObjects();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -176,6 +177,10 @@ namespace SHADE
|
|||
physicsObject = createPhysicsObject(COMMAND.eid);
|
||||
|
||||
componentFunc[SHUtilities::ConvertEnum(COMMAND.command)][SHUtilities::ConvertEnum(COMMAND.component)](COMMAND, physicsObject, COMPONENT_GROUP);
|
||||
|
||||
// If any removal was done, wake all objects
|
||||
if (COMMAND.command == QueueCommand::Command::REMOVE)
|
||||
wakeAllObjects();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,5 +302,11 @@ namespace SHADE
|
|||
physicsObject->RemoveCollisionShape(command.shapeIndex);
|
||||
}
|
||||
|
||||
void SHPhysicsObjectManager::wakeAllObjects() noexcept
|
||||
{
|
||||
for (auto& physicsObject : physicsObjects | std::views::values)
|
||||
physicsObject.GetRigidBody()->setIsSleeping(false);
|
||||
}
|
||||
|
||||
|
||||
} // namespace SHADE
|
|
@ -165,6 +165,8 @@ namespace SHADE
|
|||
SHPhysicsObject* createPhysicsObject (EntityID eid) noexcept;
|
||||
void destroyPhysicsObject (EntityID eid) noexcept;
|
||||
|
||||
void wakeAllObjects () noexcept;
|
||||
|
||||
static void addRigidBody (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
|
||||
static void addCollider (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
|
||||
static void removeRigidBody (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
|
||||
|
@ -172,6 +174,8 @@ namespace SHADE
|
|||
|
||||
static void addCollisionShape (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
|
||||
static void removeCollisionShape (const QueueCommand& command, SHPhysicsObject* physicsObject, const PhysicsComponentGroup& componentGroup);
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace SHADE
|
|
@ -16,6 +16,7 @@
|
|||
// Project Headers
|
||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||
#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h"
|
||||
#include "Scene/SHSceneManager.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -122,6 +123,10 @@ namespace SHADE
|
|||
const auto& COLLIDER_SET = SHComponentManager::GetDense<SHColliderComponent>();
|
||||
for (const auto& COLLIDER : COLLIDER_SET)
|
||||
{
|
||||
// Skip inactive colliders
|
||||
if (!SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(COLLIDER.GetEID()))
|
||||
continue;
|
||||
|
||||
for (auto& collisionShape : COLLIDER.GetCollisionShapes())
|
||||
{
|
||||
switch (collisionShape.GetType())
|
||||
|
@ -176,7 +181,7 @@ namespace SHADE
|
|||
return;
|
||||
}
|
||||
|
||||
auto* BOX = reinterpret_cast<const SHBoundingBox*>(collisionShape.GetShape());
|
||||
auto* BOX = reinterpret_cast<const SHBox*>(collisionShape.GetShape());
|
||||
|
||||
// Calculate final position & orientation
|
||||
const SHVec3 FINAL_POS = colliderComponent.GetPosition() + collisionShape.GetPositionOffset();
|
||||
|
@ -216,7 +221,7 @@ namespace SHADE
|
|||
return;
|
||||
}
|
||||
|
||||
auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(collisionShape.GetShape());
|
||||
auto* SPHERE = reinterpret_cast<const SHSphere*>(collisionShape.GetShape());
|
||||
|
||||
const SHColour COLLIDER_COLOUR = collisionShape.IsTrigger() ? SHColour::PURPLE : SHColour::GREEN;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "Editor/SHEditor.h"
|
||||
#include "Physics/SHPhysicsEvents.h"
|
||||
#include "Scene/SHSceneManager.h"
|
||||
#include "Scripting/SHScriptEngine.h"
|
||||
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
/* Local Helper Functions */
|
||||
|
@ -34,16 +35,16 @@ namespace SHADE
|
|||
SHPhysicsSystem::SHPhysicsSystem()
|
||||
: worldUpdated { false }
|
||||
, interpolationFactor { 0.0 }
|
||||
, fixedDT { 60.0 }
|
||||
, fixedDT { DEFAULT_FIXED_STEP }
|
||||
{}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Getter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
double SHPhysicsSystem::GetFixedDT() const noexcept
|
||||
double SHPhysicsSystem::GetFixedUpdateRate() const noexcept
|
||||
{
|
||||
return fixedDT;
|
||||
return 1.0 / fixedDT;
|
||||
}
|
||||
|
||||
const SHPhysicsWorldState::WorldSettings& SHPhysicsSystem::GetWorldSettings() const noexcept
|
||||
|
@ -76,9 +77,9 @@ namespace SHADE
|
|||
/* Setter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHPhysicsSystem::SetFixedDT(double fixedUpdateRate) noexcept
|
||||
void SHPhysicsSystem::SetFixedUpdateRate(double fixedUpdateRate) noexcept
|
||||
{
|
||||
fixedDT = fixedUpdateRate;
|
||||
fixedDT = 1.0 / fixedUpdateRate;
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::SetWorldSettings(const SHPhysicsWorldState::WorldSettings& settings) noexcept
|
||||
|
@ -126,6 +127,45 @@ namespace SHADE
|
|||
worldState.DestroyWorld(factory);
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::ForceUpdate()
|
||||
{
|
||||
if (!worldState.world)
|
||||
{
|
||||
SHLOGV_ERROR("Unable to force update without a Physics world!")
|
||||
return;
|
||||
}
|
||||
|
||||
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
|
||||
if (scriptingSystem == nullptr)
|
||||
{
|
||||
SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!");
|
||||
}
|
||||
|
||||
// Force the physics world to update once
|
||||
if (scriptingSystem != nullptr)
|
||||
scriptingSystem->ExecuteFixedUpdates();
|
||||
|
||||
worldState.world->update(static_cast<rp3d::decimal>(fixedDT));
|
||||
|
||||
// Sync transforms. No interpolation applied here
|
||||
for (auto& [entityID, physicsObject] : objectManager.physicsObjects)
|
||||
{
|
||||
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(entityID);
|
||||
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
|
||||
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
|
||||
|
||||
postUpdateSyncTransforms
|
||||
(
|
||||
physicsObject
|
||||
, transformComponent
|
||||
, rigidBodyComponent
|
||||
, colliderComponent
|
||||
, 1.0 // We use 1.0 here to avoid any interpolation
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SHPhysicsSystem::AddCollisionShape(EntityID eid, int shapeIndex)
|
||||
{
|
||||
static const auto ADD_SHAPE = [&](EntityID entityID, int index)
|
||||
|
@ -185,44 +225,51 @@ namespace SHADE
|
|||
|
||||
void SHPhysicsSystem::AddForce(EntityID eid, const SHVec3& force) noexcept
|
||||
{
|
||||
auto* physicsObject = objectManager.GetPhysicsObject(eid);
|
||||
|
||||
const auto* PHYSICS_OBJECT = objectManager.GetPhysicsObject(eid);
|
||||
PHYSICS_OBJECT->GetRigidBody()->applyWorldForceAtCenterOfMass(force);
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::AddForceAtLocalPos(EntityID eid, const SHVec3& force, const SHVec3& localPos) noexcept
|
||||
{
|
||||
auto* physicsObject = objectManager.GetPhysicsObject(eid);
|
||||
const auto* PHYSICS_OBJECT = objectManager.GetPhysicsObject(eid);
|
||||
PHYSICS_OBJECT->GetRigidBody()->applyWorldForceAtLocalPosition(force, localPos);
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::AddForceAtWorldPos(EntityID eid, const SHVec3& force, const SHVec3& worldPos) noexcept
|
||||
{
|
||||
auto* physicsObject = objectManager.GetPhysicsObject(eid);
|
||||
const auto* PHYSICS_OBJECT = objectManager.GetPhysicsObject(eid);
|
||||
PHYSICS_OBJECT->GetRigidBody()->applyWorldForceAtWorldPosition(force, worldPos);
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::AddRelativeForce(EntityID eid, const SHVec3& relativeForce) noexcept
|
||||
{
|
||||
auto* physicsObject = objectManager.GetPhysicsObject(eid);
|
||||
const auto* PHYSICS_OBJECT = objectManager.GetPhysicsObject(eid);
|
||||
PHYSICS_OBJECT->GetRigidBody()->applyLocalForceAtCenterOfMass(relativeForce);
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::AddRelativeForceAtLocalPos(EntityID eid, const SHVec3& relativeForce, const SHVec3& localPos) noexcept
|
||||
{
|
||||
auto* physicsObject = objectManager.GetPhysicsObject(eid);
|
||||
const auto* PHYSICS_OBJECT = objectManager.GetPhysicsObject(eid);
|
||||
PHYSICS_OBJECT->GetRigidBody()->applyLocalForceAtLocalPosition(relativeForce, localPos);
|
||||
}
|
||||
|
||||
|
||||
void SHPhysicsSystem::AddRelativeForceAtWorldPos(EntityID eid, const SHVec3& relativeForce, const SHVec3& worldPos) noexcept
|
||||
{
|
||||
auto* physicsObject = objectManager.GetPhysicsObject(eid);
|
||||
const auto* PHYSICS_OBJECT = objectManager.GetPhysicsObject(eid);
|
||||
PHYSICS_OBJECT->GetRigidBody()->applyLocalForceAtWorldPosition(relativeForce, worldPos);
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::AddTorque(EntityID eid, const SHVec3& torque) noexcept
|
||||
{
|
||||
auto* physicsObject = objectManager.GetPhysicsObject(eid);
|
||||
const auto* PHYSICS_OBJECT = objectManager.GetPhysicsObject(eid);
|
||||
PHYSICS_OBJECT->GetRigidBody()->applyWorldTorque(torque);
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::AddRelativeTorque(EntityID eid, const SHVec3& relativeTorque) noexcept
|
||||
{
|
||||
auto* physicsObject = objectManager.GetPhysicsObject(eid);
|
||||
const auto* PHYSICS_OBJECT = objectManager.GetPhysicsObject(eid);
|
||||
PHYSICS_OBJECT->GetRigidBody()->applyLocalTorque(relativeTorque);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -339,5 +386,93 @@ namespace SHADE
|
|||
return onStopEvent->handle;
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::preUpdateSyncTransform
|
||||
(
|
||||
SHPhysicsObject& physicsObject
|
||||
, SHTransformComponent* transformComponent
|
||||
, SHRigidBodyComponent* rigidBodyComponent
|
||||
, SHColliderComponent* colliderComponent
|
||||
) noexcept
|
||||
{
|
||||
if (!transformComponent)
|
||||
return;
|
||||
|
||||
const SHVec3& WORLD_POS = transformComponent->GetWorldPosition();
|
||||
const SHQuaternion& WORLD_ROT = transformComponent->GetWorldOrientation();
|
||||
const SHVec3& WORLD_SCL = transformComponent->GetWorldScale();
|
||||
|
||||
const rp3d::Transform RP3D_TRANSFORM { WORLD_POS, WORLD_ROT };
|
||||
physicsObject.GetRigidBody()->setTransform(RP3D_TRANSFORM);
|
||||
|
||||
if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(physicsObject.entityID))
|
||||
{
|
||||
rigidBodyComponent->position = WORLD_POS;
|
||||
rigidBodyComponent->orientation = WORLD_ROT;
|
||||
}
|
||||
|
||||
if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(physicsObject.entityID))
|
||||
{
|
||||
colliderComponent->position = WORLD_POS;
|
||||
colliderComponent->orientation = WORLD_ROT;
|
||||
colliderComponent->scale = WORLD_SCL;
|
||||
|
||||
colliderComponent->RecomputeCollisionShapes();
|
||||
}
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::postUpdateSyncTransforms
|
||||
(
|
||||
SHPhysicsObject& physicsObject
|
||||
, SHTransformComponent* transformComponent
|
||||
, SHRigidBodyComponent* rigidBodyComponent
|
||||
, SHColliderComponent* colliderComponent
|
||||
, double interpolationFactor
|
||||
) noexcept
|
||||
{
|
||||
const rp3d::Transform& CURRENT_TF = physicsObject.GetRigidBody()->getTransform();
|
||||
auto renderPos = CURRENT_TF.getPosition();
|
||||
auto renderRot = CURRENT_TF.getOrientation();
|
||||
|
||||
// Cache transforms
|
||||
if (physicsObject.GetRigidBody()->isActive())
|
||||
physicsObject.prevTransform = CURRENT_TF;
|
||||
|
||||
// Sync with rigid bodies
|
||||
if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(physicsObject.entityID))
|
||||
{
|
||||
// Skip static bodies
|
||||
if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
|
||||
return;
|
||||
|
||||
// Check if transform should be interpolated
|
||||
if (rigidBodyComponent->IsInterpolating())
|
||||
{
|
||||
// Interpolate transforms between current and predicted next transform
|
||||
|
||||
const rp3d::Transform PREV_TF = physicsObject.prevTransform;
|
||||
const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast<rp3d::decimal>(interpolationFactor));
|
||||
|
||||
renderPos = INTERPOLATED_TF.getPosition();
|
||||
renderRot = INTERPOLATED_TF.getOrientation();
|
||||
}
|
||||
|
||||
rigidBodyComponent->position = CURRENT_TF.getPosition();
|
||||
rigidBodyComponent->orientation = CURRENT_TF.getOrientation();
|
||||
}
|
||||
|
||||
// Sync with colliders
|
||||
if (colliderComponent && SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(physicsObject.entityID))
|
||||
{
|
||||
colliderComponent->position = CURRENT_TF.getPosition();
|
||||
colliderComponent->orientation = CURRENT_TF.getOrientation();
|
||||
}
|
||||
|
||||
// Set transform for rendering
|
||||
if (transformComponent)
|
||||
{
|
||||
transformComponent->SetWorldPosition(renderPos);
|
||||
transformComponent->SetWorldOrientation(renderRot);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SHADE
|
|
@ -55,7 +55,7 @@ namespace SHADE
|
|||
/* Getter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] double GetFixedDT () const noexcept;
|
||||
[[nodiscard]] double GetFixedUpdateRate () const noexcept;
|
||||
[[nodiscard]] const SHPhysicsWorldState::WorldSettings& GetWorldSettings () const noexcept;
|
||||
|
||||
[[nodiscard]] const std::vector<SHCollisionInfo>& GetAllCollisionInfo () const noexcept;
|
||||
|
@ -67,7 +67,7 @@ namespace SHADE
|
|||
/* Setter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
void SetFixedDT (double fixedUpdateRate) noexcept;
|
||||
void SetFixedUpdateRate (double fixedUpdateRate) noexcept;
|
||||
void SetWorldSettings (const SHPhysicsWorldState::WorldSettings& settings) noexcept;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -77,6 +77,8 @@ namespace SHADE
|
|||
void Init () override;
|
||||
void Exit () override;
|
||||
|
||||
void ForceUpdate ();
|
||||
|
||||
// Specific Handling for Collision Shapes as they are not under the Component System
|
||||
|
||||
void AddCollisionShape (EntityID eid, int shapeIndex);
|
||||
|
@ -120,15 +122,9 @@ namespace SHADE
|
|||
/* Function Members */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
static void syncOnPlay(EntityID eid, SHPhysicsObject& physicsObject) noexcept;
|
||||
|
||||
static void preUpdateSyncTransform
|
||||
(
|
||||
SHPhysicsObject& physicsObject
|
||||
, SHTransformComponent& transformComponent
|
||||
, SHRigidBodyComponent* rigidBodyComponent
|
||||
, SHColliderComponent* colliderComponent
|
||||
) noexcept;
|
||||
void syncRigidBodyActive (EntityID eid, SHPhysicsObject& physicsObject) const noexcept;
|
||||
void syncColliderActive (EntityID eid, SHPhysicsObject& physicsObject) const noexcept;
|
||||
static void syncOnPlay (EntityID eid, SHPhysicsObject& physicsObject) noexcept;
|
||||
};
|
||||
|
||||
class SH_API PhysicsFixedUpdate final : public SHFixedSystemRoutine
|
||||
|
@ -161,20 +157,6 @@ namespace SHADE
|
|||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
void Execute(double dt) noexcept override;
|
||||
|
||||
private:
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Function Members */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
static void postUpdateSyncTransforms
|
||||
(
|
||||
SHPhysicsObject& physicsObject
|
||||
, SHTransformComponent& transformComponent
|
||||
, SHRigidBodyComponent* rigidBodyComponent
|
||||
, SHColliderComponent* colliderComponent
|
||||
, double interpolationFactor
|
||||
) noexcept;
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -208,5 +190,24 @@ namespace SHADE
|
|||
SHEventHandle onPlay (SHEventPtr onPlayEvent);
|
||||
SHEventHandle onStop (SHEventPtr onStopEvent);
|
||||
|
||||
|
||||
|
||||
static void preUpdateSyncTransform
|
||||
(
|
||||
SHPhysicsObject& physicsObject
|
||||
, SHTransformComponent* transformComponent
|
||||
, SHRigidBodyComponent* rigidBodyComponent
|
||||
, SHColliderComponent* colliderComponent
|
||||
) noexcept;
|
||||
|
||||
static void postUpdateSyncTransforms
|
||||
(
|
||||
SHPhysicsObject& physicsObject
|
||||
, SHTransformComponent* transformComponent
|
||||
, SHRigidBodyComponent* rigidBodyComponent
|
||||
, SHColliderComponent* colliderComponent
|
||||
, double interpolationFactor
|
||||
) noexcept;
|
||||
|
||||
};
|
||||
} // namespace SHADE
|
|
@ -55,7 +55,7 @@ namespace SHADE
|
|||
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
|
||||
if (phySystem)
|
||||
{
|
||||
return phySystem->GetFixedDT();
|
||||
return phySystem->GetFixedUpdateRate();
|
||||
}
|
||||
|
||||
SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get fixed delta time. 0.0 returned instead.");
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
// Project Headers
|
||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||
#include "Editor/SHEditor.h"
|
||||
#include "Scene/SHSceneManager.h"
|
||||
#include "Scripting/SHScriptEngine.h"
|
||||
|
||||
namespace SHADE
|
||||
|
@ -45,14 +46,10 @@ namespace SHADE
|
|||
|
||||
#ifdef SHEDITOR
|
||||
|
||||
auto* editor = SHSystemManager::GetSystem<SHEditor>();
|
||||
|
||||
// Only Sync on Play.
|
||||
// Otherwise, Components are only holding data until the world is built on play.
|
||||
|
||||
if (editor)
|
||||
{
|
||||
if (editor->editorState != SHEditor::State::STOP)
|
||||
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
|
||||
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
|
||||
{
|
||||
physicsSystem->objectManager.UpdateCommands();
|
||||
|
||||
|
@ -62,6 +59,10 @@ namespace SHADE
|
|||
if (physicsObject.rp3dBody == nullptr)
|
||||
continue;
|
||||
|
||||
// Sync active states between SHADE & RP3D
|
||||
syncRigidBodyActive(entityID, physicsObject);
|
||||
syncColliderActive(entityID, physicsObject);
|
||||
|
||||
syncOnPlay(entityID, physicsObject);
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +96,6 @@ namespace SHADE
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
@ -110,6 +110,9 @@ namespace SHADE
|
|||
if (physicsObject.rp3dBody == nullptr)
|
||||
continue;
|
||||
|
||||
syncRigidBodyActive(entityID, physicsObject);
|
||||
syncColliderActive(entityID, physicsObject);
|
||||
|
||||
syncOnPlay(entityID, physicsObject);
|
||||
}
|
||||
|
||||
|
@ -125,18 +128,26 @@ namespace SHADE
|
|||
SHLOGV_ERROR("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!");
|
||||
}
|
||||
|
||||
fixedTimeStep = 1.0 / physicsSystem->fixedDT;
|
||||
const double FIXED_DT = physicsSystem->fixedDT;
|
||||
accumulatedTime += dt;
|
||||
|
||||
int count = 0;
|
||||
while (accumulatedTime > fixedTimeStep)
|
||||
while (accumulatedTime > FIXED_DT)
|
||||
{
|
||||
if (scriptingSystem != nullptr)
|
||||
scriptingSystem->ExecuteFixedUpdates();
|
||||
|
||||
physicsSystem->worldState.world->update(static_cast<rp3d::decimal>(fixedTimeStep));
|
||||
physicsSystem->worldState.world->update(static_cast<rp3d::decimal>(FIXED_DT));
|
||||
|
||||
accumulatedTime -= fixedTimeStep;
|
||||
// Clear all forces of every body in the scene after each update
|
||||
for (auto& physicsObject : physicsSystem->objectManager.physicsObjects | std::views::values)
|
||||
{
|
||||
auto* rp3dRigidBody = physicsObject.GetRigidBody();
|
||||
rp3dRigidBody->resetForce();
|
||||
rp3dRigidBody->resetTorque();
|
||||
}
|
||||
|
||||
accumulatedTime -= FIXED_DT;
|
||||
++count;
|
||||
}
|
||||
|
||||
|
@ -165,18 +176,15 @@ namespace SHADE
|
|||
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityID);
|
||||
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(entityID);
|
||||
|
||||
if (transformComponent)
|
||||
{
|
||||
postUpdateSyncTransforms
|
||||
(
|
||||
physicsObject
|
||||
, *transformComponent
|
||||
, transformComponent
|
||||
, rigidBodyComponent
|
||||
, colliderComponent
|
||||
, physicsSystem->interpolationFactor
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Collision & Trigger messages
|
||||
if (scriptingSystem != nullptr)
|
||||
|
@ -191,6 +199,48 @@ namespace SHADE
|
|||
/* Private Function Member Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHPhysicsSystem::PhysicsPreUpdate::syncRigidBodyActive(EntityID eid, SHPhysicsObject& physicsObject) const noexcept
|
||||
{
|
||||
if (!SHComponentManager::HasComponent<SHRigidBodyComponent>(eid))
|
||||
return;
|
||||
|
||||
const bool IS_ACTIVE_IN_SCENE = SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(eid);
|
||||
const bool IS_RP3D_BODY_ACTIVE = physicsObject.GetRigidBody()->isActive();
|
||||
|
||||
if (IS_ACTIVE_IN_SCENE != IS_RP3D_BODY_ACTIVE)
|
||||
physicsObject.GetRigidBody()->setIsActive(IS_ACTIVE_IN_SCENE);
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::PhysicsPreUpdate::syncColliderActive(EntityID eid, SHPhysicsObject& physicsObject) const noexcept
|
||||
{
|
||||
const auto* COLLIDER = SHComponentManager::GetComponent_s<SHColliderComponent>(eid);
|
||||
if (!COLLIDER)
|
||||
return;
|
||||
|
||||
const bool IS_ACTIVE_IN_SCENE = SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(eid);
|
||||
const bool IS_RP3D_COLLIDER_ACTIVE = physicsObject.collidersActive;
|
||||
|
||||
if (IS_ACTIVE_IN_SCENE != IS_RP3D_COLLIDER_ACTIVE)
|
||||
{
|
||||
// HACK: If active state turned off, remove all collision shapes. If turned on, add them back.
|
||||
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
|
||||
|
||||
const int NUM_SHAPES = static_cast<int>(COLLIDER->GetCollisionShapes().size());
|
||||
if (IS_ACTIVE_IN_SCENE)
|
||||
{
|
||||
for (int i = 0; i < NUM_SHAPES; ++i)
|
||||
physicsSystem->objectManager.AddCollisionShape(eid, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = NUM_SHAPES - 1; i >= 0; --i)
|
||||
physicsSystem->objectManager.RemoveCollisionShape(eid, i);
|
||||
}
|
||||
|
||||
physicsObject.collidersActive = IS_ACTIVE_IN_SCENE;
|
||||
}
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::PhysicsPreUpdate::syncOnPlay(EntityID eid, SHPhysicsObject& physicsObject) noexcept
|
||||
{
|
||||
auto* transformComponent = SHComponentManager::GetComponent_s<SHTransformComponent>(eid);
|
||||
|
@ -203,7 +253,7 @@ namespace SHADE
|
|||
preUpdateSyncTransform
|
||||
(
|
||||
physicsObject
|
||||
, *transformComponent
|
||||
, transformComponent
|
||||
, rigidBodyComponent
|
||||
, colliderComponent
|
||||
);
|
||||
|
@ -217,99 +267,4 @@ namespace SHADE
|
|||
if (colliderComponent)
|
||||
physicsObject.SyncColliders(*colliderComponent);
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::PhysicsPreUpdate::preUpdateSyncTransform
|
||||
(
|
||||
SHPhysicsObject& physicsObject
|
||||
, SHTransformComponent& transformComponent
|
||||
, SHRigidBodyComponent* rigidBodyComponent
|
||||
, SHColliderComponent* colliderComponent
|
||||
) noexcept
|
||||
{
|
||||
const SHVec3& WORLD_POS = transformComponent.GetWorldPosition();
|
||||
const SHQuaternion& WORLD_ROT = transformComponent.GetWorldOrientation();
|
||||
const SHVec3& WORLD_SCL = transformComponent.GetWorldScale();
|
||||
|
||||
const rp3d::Transform RP3D_TRANSFORM { WORLD_POS, WORLD_ROT };
|
||||
physicsObject.GetRigidBody()->setTransform(RP3D_TRANSFORM);
|
||||
|
||||
if (rigidBodyComponent)
|
||||
{
|
||||
rigidBodyComponent->position = WORLD_POS;
|
||||
rigidBodyComponent->orientation = WORLD_ROT;
|
||||
}
|
||||
|
||||
if (colliderComponent)
|
||||
{
|
||||
colliderComponent->position = WORLD_POS;
|
||||
colliderComponent->orientation = WORLD_ROT;
|
||||
colliderComponent->scale = WORLD_SCL;
|
||||
|
||||
colliderComponent->RecomputeCollisionShapes();
|
||||
}
|
||||
}
|
||||
|
||||
void SHPhysicsSystem::PhysicsPostUpdate::postUpdateSyncTransforms
|
||||
(
|
||||
SHPhysicsObject& physicsObject
|
||||
, SHTransformComponent& transformComponent
|
||||
, SHRigidBodyComponent* rigidBodyComponent
|
||||
, SHColliderComponent* colliderComponent
|
||||
, double interpolationFactor
|
||||
) noexcept
|
||||
{
|
||||
rp3d::Vector3 rp3dPos;
|
||||
rp3d::Quaternion rp3dRot;
|
||||
|
||||
const rp3d::Transform CURRENT_TF = physicsObject.rp3dBody->getTransform();
|
||||
|
||||
// Check if transform should be interpolated
|
||||
|
||||
if (rigidBodyComponent)
|
||||
{
|
||||
// Skip static bodies
|
||||
if (rigidBodyComponent->GetType() == SHRigidBodyComponent::Type::STATIC)
|
||||
return;
|
||||
|
||||
if (rigidBodyComponent->IsInterpolating())
|
||||
{
|
||||
// Interpolate transforms between current and predicted next transform
|
||||
|
||||
const rp3d::Transform PREV_TF = physicsObject.prevTransform;
|
||||
const rp3d::Transform INTERPOLATED_TF = rp3d::Transform::interpolateTransforms(PREV_TF, CURRENT_TF, static_cast<rp3d::decimal>(interpolationFactor));
|
||||
|
||||
rp3dPos = INTERPOLATED_TF.getPosition();
|
||||
rp3dRot = INTERPOLATED_TF.getOrientation();
|
||||
}
|
||||
else
|
||||
{
|
||||
rp3dPos = CURRENT_TF.getPosition();
|
||||
rp3dRot = CURRENT_TF.getOrientation();
|
||||
}
|
||||
|
||||
rigidBodyComponent->position = CURRENT_TF.getPosition();
|
||||
rigidBodyComponent->orientation = CURRENT_TF.getOrientation();
|
||||
|
||||
if (colliderComponent)
|
||||
{
|
||||
// Sync with colliders
|
||||
|
||||
colliderComponent->position = CURRENT_TF.getPosition();
|
||||
colliderComponent->orientation = CURRENT_TF.getOrientation();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rp3dPos = CURRENT_TF.getPosition();
|
||||
rp3dRot = CURRENT_TF.getOrientation();
|
||||
}
|
||||
|
||||
// Convert RP3D Transform to SHADE
|
||||
transformComponent.SetWorldPosition(rp3dPos);
|
||||
transformComponent.SetWorldOrientation(rp3dRot);
|
||||
|
||||
// Cache transforms
|
||||
physicsObject.prevTransform = CURRENT_TF;
|
||||
}
|
||||
|
||||
} // namespace SHADE
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
#include "Graphics/MiddleEnd/Interface/SHRenderable.h"
|
||||
#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h"
|
||||
#include "Math/Geometry/SHBoundingBox.h"
|
||||
#include "Math/Geometry/SHBoundingSphere.h"
|
||||
#include "Math/Geometry/SHBox.h"
|
||||
#include "Math/Geometry/SHSphere.h"
|
||||
#include "Physics/Interface/SHCollisionShape.h"
|
||||
#include "Resource/SHResourceManager.h"
|
||||
#include "Math/Vector/SHVec2.h"
|
||||
|
@ -130,13 +130,13 @@ namespace YAML
|
|||
{
|
||||
case SHCollisionShape::Type::BOX:
|
||||
{
|
||||
const auto* BOX = reinterpret_cast<const SHBoundingBox*>(rhs.GetShape());
|
||||
const auto* BOX = reinterpret_cast<const SHBox*>(rhs.GetShape());
|
||||
node[HalfExtents] = BOX->GetRelativeExtents();
|
||||
}
|
||||
break;
|
||||
case SHCollisionShape::Type::SPHERE:
|
||||
{
|
||||
const auto* SPHERE = reinterpret_cast<const SHBoundingSphere*>(rhs.GetShape());
|
||||
const auto* SPHERE = reinterpret_cast<const SHSphere*>(rhs.GetShape());
|
||||
node[Radius] = SPHERE->GetRelativeRadius();
|
||||
}
|
||||
break;
|
||||
|
@ -288,7 +288,15 @@ namespace YAML
|
|||
{
|
||||
YAML::Node node;
|
||||
node[MESH_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHMesh>(rhs.GetMesh()).value_or(0);
|
||||
auto mat = rhs.GetMaterial();
|
||||
if (mat)
|
||||
{
|
||||
node[MAT_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHMaterial>(rhs.GetMaterial()->GetBaseMaterial()).value_or(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
node[MAT_YAML_TAG.data()] = 0;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
static bool decode(YAML::Node const& node, SHRenderable& rhs)
|
||||
|
|
|
@ -47,35 +47,35 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
Vector3 BoxCollider::Center::get()
|
||||
{
|
||||
return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetCenter());
|
||||
return Convert::ToCLI(getNativeBoundObject<SHBox>().GetCenter());
|
||||
}
|
||||
void BoxCollider::Center::set(Vector3 value)
|
||||
{
|
||||
getNativeBoundObject<SHBoundingBox>().SetCenter(Convert::ToNative(value));
|
||||
getNativeBoundObject<SHBox>().SetCenter(Convert::ToNative(value));
|
||||
}
|
||||
Vector3 BoxCollider::HalfExtents::get()
|
||||
{
|
||||
return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetWorldExtents());
|
||||
return Convert::ToCLI(getNativeBoundObject<SHBox>().GetWorldExtents());
|
||||
}
|
||||
void BoxCollider::HalfExtents::set(Vector3 value)
|
||||
{
|
||||
getNativeBoundObject<SHBoundingBox>().SetWorldExtents(Convert::ToNative(value));
|
||||
getNativeBoundObject<SHBox>().SetWorldExtents(Convert::ToNative(value));
|
||||
}
|
||||
Vector3 BoxCollider::Min::get()
|
||||
{
|
||||
return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetMin());
|
||||
return Convert::ToCLI(getNativeBoundObject<SHBox>().GetMin());
|
||||
}
|
||||
void BoxCollider::Min::set(Vector3 value)
|
||||
{
|
||||
getNativeBoundObject<SHBoundingBox>().SetMin(Convert::ToNative(value));
|
||||
getNativeBoundObject<SHBox>().SetMin(Convert::ToNative(value));
|
||||
}
|
||||
Vector3 BoxCollider::Max::get()
|
||||
{
|
||||
return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetMax());
|
||||
return Convert::ToCLI(getNativeBoundObject<SHBox>().GetMax());
|
||||
}
|
||||
void BoxCollider::Max::set(Vector3 value)
|
||||
{
|
||||
getNativeBoundObject<SHBoundingBox>().SetMax(Convert::ToNative(value));
|
||||
getNativeBoundObject<SHBox>().SetMax(Convert::ToNative(value));
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -83,11 +83,11 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
bool BoxCollider::TestPoint(Vector3 point)
|
||||
{
|
||||
return getNativeBoundObject<SHBoundingBox>().TestPoint(Convert::ToNative(point));
|
||||
return getNativeBoundObject<SHBox>().TestPoint(Convert::ToNative(point));
|
||||
}
|
||||
bool BoxCollider::Raycast(Ray ray, float maxDistance)
|
||||
{
|
||||
return getNativeBoundObject<SHBoundingBox>().Raycast(Convert::ToNative(ray), maxDistance);
|
||||
return getNativeBoundObject<SHBox>().Raycast(Convert::ToNative(ray), maxDistance);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -95,19 +95,19 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
Vector3 SphereCollider::Center::get()
|
||||
{
|
||||
return Convert::ToCLI(getNativeBoundObject<SHBoundingSphere>().GetCenter());
|
||||
return Convert::ToCLI(getNativeBoundObject<SHSphere>().GetCenter());
|
||||
}
|
||||
void SphereCollider::Center::set(Vector3 value)
|
||||
{
|
||||
getNativeBoundObject<SHBoundingSphere>().SetCenter(Convert::ToNative(value));
|
||||
getNativeBoundObject<SHSphere>().SetCenter(Convert::ToNative(value));
|
||||
}
|
||||
float SphereCollider::Radius::get()
|
||||
{
|
||||
return getNativeBoundObject<SHBoundingSphere>().GetWorldRadius();
|
||||
return getNativeBoundObject<SHSphere>().GetWorldRadius();
|
||||
}
|
||||
void SphereCollider::Radius::set(float value)
|
||||
{
|
||||
getNativeBoundObject<SHBoundingSphere>().SetWorldRadius(value);
|
||||
getNativeBoundObject<SHSphere>().SetWorldRadius(value);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -115,11 +115,11 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
bool SphereCollider::TestPoint(Vector3 point)
|
||||
{
|
||||
return getNativeBoundObject<SHBoundingBox>().TestPoint(Convert::ToNative(point));
|
||||
return getNativeBoundObject<SHBox>().TestPoint(Convert::ToNative(point));
|
||||
}
|
||||
bool SphereCollider::Raycast(Ray ray, float maxDistance)
|
||||
{
|
||||
return getNativeBoundObject<SHBoundingBox>().Raycast(Convert::ToNative(ray), maxDistance);
|
||||
return getNativeBoundObject<SHBox>().Raycast(Convert::ToNative(ray), maxDistance);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
|
|
@ -190,6 +190,10 @@ namespace SHADE
|
|||
GetNativeComponent()->AddRelativeForceAtWorldPos(Convert::ToNative(relativeForce), Convert::ToNative(worldPos));
|
||||
}
|
||||
|
||||
Vector3 RigidBody::GetForce()
|
||||
{
|
||||
return Convert::ToCLI(GetNativeComponent()->GetForce());
|
||||
}
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Torque Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -202,4 +206,10 @@ namespace SHADE
|
|||
{
|
||||
GetNativeComponent()->AddRelativeTorque(Convert::ToNative(relativeTorque));
|
||||
}
|
||||
|
||||
Vector3 RigidBody::GetTorque()
|
||||
{
|
||||
return Convert::ToCLI(GetNativeComponent()->GetTorque());
|
||||
}
|
||||
|
||||
}
|
|
@ -145,11 +145,15 @@ namespace SHADE
|
|||
void AddRelativeForceAtLocalPos(Vector3 relativeForce, Vector3 localPos);
|
||||
void AddRelativeForceAtWorldPos(Vector3 relativeForce, Vector3 worldPos);
|
||||
|
||||
Vector3 GetForce();
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Torque Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
void AddTorque(Vector3 force);
|
||||
void AddRelativeTorque(Vector3 relativeForce);
|
||||
|
||||
Vector3 GetTorque();
|
||||
};
|
||||
|
||||
}
|
|
@ -27,6 +27,7 @@ of DigiPen Institute of Technology is prohibited.
|
|||
#include "Scene/SHSceneManager.h"
|
||||
#include "Scene/SHSceneGraph.h"
|
||||
#include "Tools/SHLog.h"
|
||||
#include "Graphics\MiddleEnd\Interface\SHRenderable.h"
|
||||
// Project Headers
|
||||
#include "Utility/Convert.hxx"
|
||||
#include "Utility/Debug.hxx"
|
||||
|
@ -36,6 +37,7 @@ of DigiPen Institute of Technology is prohibited.
|
|||
#include "Components/Camera.hxx"
|
||||
#include "Components/CameraArm.hxx"
|
||||
#include "Components/Light.hxx"
|
||||
#include "Components\Renderable.hxx"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -166,6 +168,70 @@ namespace SHADE
|
|||
return T();
|
||||
}
|
||||
|
||||
generic<typename T>
|
||||
System::Collections::Generic::IEnumerable<T>^ ECS::GetComponentsInChildren(EntityID entity)
|
||||
{
|
||||
System::Type^ componentType = T::typeid;
|
||||
|
||||
// Check if entity is correct
|
||||
if (!SHEntityManager::IsValidEID(entity))
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "[ECS] Attempted to retrieve Component \""
|
||||
<< Convert::ToNative(componentType->Name)
|
||||
<< "\" from invalid Entity.";
|
||||
Debug::LogError(oss.str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Search all elements via a iterative breadth first search
|
||||
System::Collections::Generic::List<T>^ results;
|
||||
System::Collections::Generic::Queue<Entity>^ searchSpace = gcnew System::Collections::Generic::Queue<Entity>();
|
||||
// Start off with direct children
|
||||
SHSceneNode* entityNode = SHSceneManager::GetCurrentSceneGraph().GetNode(entity);
|
||||
if (entityNode == nullptr)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "[ScriptStore] Failed to retrieve SceneGraphNode of entity #" << entity << ". This should not happen!";
|
||||
SHLog::Warning(oss.str());
|
||||
}
|
||||
for (const auto& child : entityNode->GetChildren())
|
||||
{
|
||||
searchSpace->Enqueue(child->GetEntityID());
|
||||
}
|
||||
// Continue with all subsequent children
|
||||
while (searchSpace->Count > 0)
|
||||
{
|
||||
// Check if this entity has the component we need
|
||||
Entity curr = searchSpace->Dequeue();
|
||||
T component = GetComponent<T>(curr);
|
||||
if (component != nullptr)
|
||||
{
|
||||
// We only construct if we need to
|
||||
if (results == nullptr)
|
||||
results = gcnew System::Collections::Generic::List<T>();
|
||||
results->Add(component);
|
||||
}
|
||||
|
||||
// Add children to the queue
|
||||
SHSceneNode* sceneGraphNode = SHSceneManager::GetCurrentSceneGraph().GetNode(curr);
|
||||
if (sceneGraphNode == nullptr)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "[ECS_CLI] Failed to retrieve SceneGraphNode of entity #" << entity << ". This should not happen!";
|
||||
SHLog::Warning(oss.str());
|
||||
continue;
|
||||
}
|
||||
for (const auto& child : sceneGraphNode->GetChildren())
|
||||
{
|
||||
searchSpace->Enqueue(child->GetEntityID());
|
||||
}
|
||||
}
|
||||
|
||||
// None here
|
||||
return results;
|
||||
}
|
||||
|
||||
generic <typename T>
|
||||
T ECS::EnsureComponent(EntityID entity)
|
||||
{
|
||||
|
@ -249,6 +315,7 @@ namespace SHADE
|
|||
static ECS::ECS()
|
||||
{
|
||||
componentMap.Add(createComponentSet<SHTransformComponent, Transform>());
|
||||
componentMap.Add(createComponentSet<SHRenderable, Renderable>());
|
||||
componentMap.Add(createComponentSet<SHColliderComponent, Collider>());
|
||||
componentMap.Add(createComponentSet<SHRigidBodyComponent, RigidBody>());
|
||||
componentMap.Add(createComponentSet<SHCameraComponent, Camera>());
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace SHADE
|
|||
generic<typename T> where T : BaseComponent
|
||||
static T GetComponent(EntityID entity);
|
||||
/// <summary>
|
||||
/// Retrieves the first Component from the specified GameObjectt's children that
|
||||
/// Retrieves the first Component from the specified GameObject's children that
|
||||
/// matches the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the Component to get.</typeparam>
|
||||
|
@ -65,6 +65,20 @@ namespace SHADE
|
|||
generic<typename T> where T : BaseComponent
|
||||
static T GetComponentInChildren(EntityID entity);
|
||||
/// <summary>
|
||||
/// Retrieves a list of Components from the specified GameObject's children that
|
||||
/// matches the specified type.
|
||||
/// This function performs allocations. If expecting only 1 component, use
|
||||
/// GetComponentInChildren() instead.
|
||||
/// This does not search the specified entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the Component to get.</typeparam>
|
||||
/// <param name="entity"> Entity object to get the Component from. </param>
|
||||
/// <returns>
|
||||
/// Newly allocated List of components. Will be null if no components are found.
|
||||
/// </returns>
|
||||
generic<typename T> where T : BaseComponent
|
||||
static System::Collections::Generic::IEnumerable<T>^ GetComponentsInChildren(EntityID entity);
|
||||
/// <summary>
|
||||
/// Ensures a Component on the specified Entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the Component to ensure.</typeparam>
|
||||
|
|
|
@ -170,6 +170,14 @@ namespace SHADE
|
|||
return ECS::GetComponentInChildren<T>(entity);
|
||||
}
|
||||
|
||||
generic<typename T>
|
||||
System::Collections::Generic::IEnumerable<T>^ GameObject::GetComponentsInChildren()
|
||||
{
|
||||
if (!valid)
|
||||
throw gcnew System::NullReferenceException();
|
||||
return ECS::GetComponentsInChildren<T>(entity);
|
||||
}
|
||||
|
||||
generic <typename T>
|
||||
T GameObject::EnsureComponent()
|
||||
{
|
||||
|
@ -212,6 +220,13 @@ namespace SHADE
|
|||
throw gcnew System::NullReferenceException();
|
||||
return ScriptStore::GetScriptInChildren<T>(entity);
|
||||
}
|
||||
generic <typename T>
|
||||
System::Collections::Generic::IEnumerable<T>^ GameObject::GetScriptsInChildren()
|
||||
{
|
||||
if (!valid)
|
||||
throw gcnew System::NullReferenceException();
|
||||
return ScriptStore::GetScriptsInChildren<T>(entity);
|
||||
}
|
||||
|
||||
generic <typename T>
|
||||
System::Collections::Generic::IEnumerable<T>^ GameObject::GetScripts()
|
||||
|
|
|
@ -153,6 +153,7 @@ namespace SHADE
|
|||
/// <summary>
|
||||
/// Retrieves the first Component from this GameObject's children that matches
|
||||
/// the specified type.
|
||||
/// Unlike Unity, we do not search this GameObject, only the children.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the Component to get.</typeparam>
|
||||
/// <returns>
|
||||
|
@ -162,6 +163,19 @@ namespace SHADE
|
|||
generic<typename T> where T : BaseComponent
|
||||
T GetComponentInChildren();
|
||||
/// <summary>
|
||||
/// Retrieves a list of Components from this GameObject's children that matches
|
||||
/// the specified type.
|
||||
/// This function performs allocations. If expecting only 1 component, use
|
||||
/// GetComponentInChildren() instead.
|
||||
/// Unlike Unity, we do not search this GameObject, only the children.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the Component to get.</typeparam>
|
||||
/// <returns>
|
||||
/// Newly allocated List of components. Will be null if no components are found.
|
||||
/// </returns>
|
||||
generic<typename T> where T : BaseComponent
|
||||
System::Collections::Generic::IEnumerable<T>^ GetComponentsInChildren();
|
||||
/// <summary>
|
||||
/// Ensures a Component on this GameObject.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the Component to ensure.</typeparam>
|
||||
|
@ -201,12 +215,26 @@ namespace SHADE
|
|||
/// Retrieves a Script of the specified type from child GameObjects.
|
||||
/// If multiple Scripts of the same specified type are added on the same
|
||||
/// child GameObject, this will retrieve the first one added.
|
||||
/// Unlike Unity, we do not search this GameObject, only the children.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of Script to retrieve.</typeparam>
|
||||
/// <returns>Reference to the Script to retrieve.</returns>
|
||||
generic<typename T> where T : ref class, Script
|
||||
T GetScriptInChildren();
|
||||
/// <summary>
|
||||
/// Retrieves a list of Scripts from this GameObject's children that matches
|
||||
/// the specified type.
|
||||
/// This function performs allocations. If expecting only 1 component, use
|
||||
/// GetComponentInChildren() instead.
|
||||
/// Unlike Unity, we do not search this GameObject, only the children.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the Component to get.</typeparam>
|
||||
/// <returns>
|
||||
/// Newly allocated List of components. Will be null if no components are found.
|
||||
/// </returns>
|
||||
generic<typename T> where T : ref class, Script
|
||||
System::Collections::Generic::IEnumerable<T>^ GetScriptsInChildren();
|
||||
/// <summary>
|
||||
/// Retrieves a immutable list of Scripts of the specified type from this
|
||||
/// GameObject.
|
||||
/// </summary>
|
||||
|
|
|
@ -42,6 +42,12 @@ namespace SHADE
|
|||
return owner.GetComponentInChildren<T>();
|
||||
}
|
||||
|
||||
generic<typename T>
|
||||
System::Collections::Generic::IEnumerable<T>^ Script::GetComponentsInChildren()
|
||||
{
|
||||
return owner.GetComponentsInChildren<T>();
|
||||
}
|
||||
|
||||
generic <typename T>
|
||||
T Script::EnsureComponent()
|
||||
{
|
||||
|
@ -72,6 +78,11 @@ namespace SHADE
|
|||
{
|
||||
return ScriptStore::GetScriptInChildren<T>(owner.GetEntity());
|
||||
}
|
||||
generic <typename T>
|
||||
System::Collections::Generic::IEnumerable<T>^ Script::GetScriptsInChildren()
|
||||
{
|
||||
return ScriptStore::GetScriptsInChildren<T>(owner.GetEntity());
|
||||
}
|
||||
|
||||
generic <typename T>
|
||||
System::Collections::Generic::IEnumerable<T>^ Script::GetScripts()
|
||||
|
|
|
@ -69,6 +69,7 @@ namespace SHADE
|
|||
/// <summary>
|
||||
/// Retrieves the first Component from this GameObject's children that matches
|
||||
/// the specified type.
|
||||
/// Unlike Unity, we do not search this GameObject, only the children.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// Type of the Component to get. Must be derived from BaseComponent.
|
||||
|
@ -77,6 +78,19 @@ namespace SHADE
|
|||
generic<typename T> where T : BaseComponent
|
||||
T GetComponentInChildren();
|
||||
/// <summary>
|
||||
/// Retrieves a list of Components from this GameObject's children that
|
||||
/// matches the specified type.
|
||||
/// This function performs allocations. If expecting only 1 component, use
|
||||
/// GetComponentInChildren() instead.
|
||||
/// Unlike Unity, we do not search this GameObject, only the children.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the Component to get.</typeparam>
|
||||
/// <returns>
|
||||
/// Newly allocated List of components. Will be null if no components are found.
|
||||
/// </returns>
|
||||
generic<typename T> where T : BaseComponent
|
||||
System::Collections::Generic::IEnumerable<T>^ GetComponentsInChildren();
|
||||
/// <summary>
|
||||
/// Ensures a Component on the GameObject that this Script belongs to.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
|
@ -121,6 +135,7 @@ namespace SHADE
|
|||
/// <summary>
|
||||
/// Retrieves the first Script from this GameObject's children that matches the
|
||||
/// specified type.
|
||||
/// Unlike Unity, we do not search this GameObject, only the children.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// Type of script to get.
|
||||
|
@ -130,6 +145,19 @@ namespace SHADE
|
|||
generic<typename T> where T : ref class, Script
|
||||
T GetScriptInChildren();
|
||||
/// <summary>
|
||||
/// Retrieves a list of Scripts from this GameObject's children that matches
|
||||
/// the specified type.
|
||||
/// This function performs allocations. If expecting only 1 component, use
|
||||
/// GetComponentInChildren() instead.
|
||||
/// Unlike Unity, we do not search this GameObject, only the children.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the Component to get.</typeparam>
|
||||
/// <returns>
|
||||
/// Newly allocated List of components. Will be null if no components are found.
|
||||
/// </returns>
|
||||
generic<typename T> where T : ref class, Script
|
||||
System::Collections::Generic::IEnumerable<T>^ GetScriptsInChildren();
|
||||
/// <summary>
|
||||
/// Retrieves a immutable list of scripts from the specified Entity that
|
||||
/// matches the specified type.
|
||||
/// <br/>
|
||||
|
|
|
@ -211,6 +211,70 @@ namespace SHADE
|
|||
return T();
|
||||
}
|
||||
|
||||
generic<typename T>
|
||||
System::Collections::Generic::IEnumerable<T>^ ScriptStore::GetScriptsInChildren(Entity entity)
|
||||
{
|
||||
System::Type^ componentType = T::typeid;
|
||||
|
||||
// Check if entity is correct
|
||||
if (!SHEntityManager::IsValidEID(entity))
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "[ScriptStore] Attempted to retrieve Script \""
|
||||
<< Convert::ToNative(componentType->Name)
|
||||
<< "\" from invalid Entity.";
|
||||
Debug::LogError(oss.str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Search all elements via a iterative breadth first search
|
||||
System::Collections::Generic::List<T>^ results;
|
||||
System::Collections::Generic::Queue<Entity>^ searchSpace = gcnew System::Collections::Generic::Queue<Entity>();
|
||||
// Start off with direct children
|
||||
SHSceneNode* entityNode = SHSceneManager::GetCurrentSceneGraph().GetNode(entity);
|
||||
if (entityNode == nullptr)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "[ScriptStore] Failed to retrieve SceneGraphNode of entity #" << entity << ". This should not happen!";
|
||||
SHLog::Warning(oss.str());
|
||||
}
|
||||
for (const auto& child : entityNode->GetChildren())
|
||||
{
|
||||
searchSpace->Enqueue(child->GetEntityID());
|
||||
}
|
||||
// Continue with all subsequent children
|
||||
while (searchSpace->Count > 0)
|
||||
{
|
||||
// Check if this entity has the component we need
|
||||
Entity curr = searchSpace->Dequeue();
|
||||
T script = GetScript<T>(curr);
|
||||
if (script != nullptr)
|
||||
{
|
||||
// We only construct if we need to
|
||||
if (results == nullptr)
|
||||
results = gcnew System::Collections::Generic::List<T>();
|
||||
results->Add(script);
|
||||
}
|
||||
|
||||
// Add children to the queue
|
||||
SHSceneNode* sceneGraphNode = SHSceneManager::GetCurrentSceneGraph().GetNode(curr);
|
||||
if (sceneGraphNode == nullptr)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "[ScriptStore] Failed to retrieve SceneGraphNode of entity #" << entity << ". This should not happen!";
|
||||
SHLog::Warning(oss.str());
|
||||
continue;
|
||||
}
|
||||
for (const auto& child : sceneGraphNode->GetChildren())
|
||||
{
|
||||
searchSpace->Enqueue(child->GetEntityID());
|
||||
}
|
||||
}
|
||||
|
||||
// None here
|
||||
return results;
|
||||
}
|
||||
|
||||
generic <typename T>
|
||||
System::Collections::Generic::IEnumerable<T>^ ScriptStore::GetScripts(Entity entity)
|
||||
{
|
||||
|
|
|
@ -137,6 +137,29 @@ namespace SHADE
|
|||
generic<typename T> where T : ref class, Script
|
||||
static T GetScriptInChildren(Entity entity);
|
||||
/// <summary>
|
||||
/// Retrieves the list of Scripts from the specified Entity and the Entity's
|
||||
/// children that matches the specified type.
|
||||
/// This function performs allocations. If expecting only 1 component, use
|
||||
/// GetScriptInChildren() instead.
|
||||
/// This does not search the specified entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// Type of script to get.
|
||||
/// This needs to be a default constructable Script.
|
||||
/// </typeparam>
|
||||
/// <param name="entity">
|
||||
/// The entity which the script to retrieve is attached.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Reference to the script. This can be null if no script of the specified
|
||||
/// type is attached.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// If the specified Entity is invalid.
|
||||
/// </exception>
|
||||
generic<typename T> where T : ref class, Script
|
||||
static System::Collections::Generic::IEnumerable<T>^ GetScriptsInChildren(Entity entity);
|
||||
/// <summary>
|
||||
/// Retrieves a immutable list of scripts from the specified Entity that
|
||||
/// matches the specified type.
|
||||
/// <br/>
|
||||
|
|
|
@ -28,7 +28,47 @@ namespace SHADE
|
|||
template<typename FieldType>
|
||||
bool SerialisationUtilities::fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Node& fieldNode)
|
||||
{
|
||||
return varInsertYamlInternal<FieldType>(fieldInfo->GetValue(object), fieldNode);
|
||||
// Handle null objects
|
||||
System::Object^ fieldObject = fieldInfo->GetValue(object);
|
||||
if (fieldObject == nullptr)
|
||||
{
|
||||
// Default construct if null
|
||||
if (fieldInfo->FieldType == FieldType::typeid)
|
||||
{
|
||||
if constexpr (std::is_same_v<FieldType, System::Enum>)
|
||||
{
|
||||
fieldNode = 0;
|
||||
}
|
||||
else if constexpr (std::is_same_v<FieldType, System::String>)
|
||||
{
|
||||
fieldNode = "";
|
||||
}
|
||||
else if constexpr (std::is_same_v<FieldType, Vector2>)
|
||||
{
|
||||
fieldNode.SetStyle(YAML::EmitterStyle::Flow);
|
||||
fieldNode.push_back(0.0f);
|
||||
fieldNode.push_back(0.0f);
|
||||
}
|
||||
else if constexpr (std::is_same_v<FieldType, Vector3>)
|
||||
{
|
||||
fieldNode.SetStyle(YAML::EmitterStyle::Flow);
|
||||
fieldNode.push_back(0.0f);
|
||||
fieldNode.push_back(0.0f);
|
||||
fieldNode.push_back(0.0f);
|
||||
}
|
||||
else if constexpr (std::is_same_v<FieldType, GameObject>)
|
||||
{
|
||||
fieldNode = MAX_EID;
|
||||
}
|
||||
else
|
||||
{
|
||||
fieldNode = FieldType();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return varInsertYamlInternal<FieldType>(fieldObject, fieldNode);
|
||||
}
|
||||
template<typename FieldType>
|
||||
bool SerialisationUtilities::varInsertYamlInternal(System::Object^ object, YAML::Node& fieldNode)
|
||||
|
|
Loading…
Reference in New Issue