Implemented a custom physics engine #316

Merged
direnbharwani merged 95 commits from SHPhysics into main 2023-01-23 15:55:45 +08:00
15 changed files with 627 additions and 293 deletions
Showing only changes of commit 58a44997b2 - Show all commits

View File

@ -66,7 +66,7 @@
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: -1.45715916, y: 7, z: 0.319963396}
Translate: {x: -1.45715916, y: 7, z: 0.64831841}
Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 1, y: 1, z: 1}
IsActive: true

View File

@ -84,9 +84,27 @@ namespace SHADE
// Sphere VS Convex
static FaceQuery findClosestFace (const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron) noexcept;
static int32_t findClosestPoint (const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron, int32_t faceIndex) noexcept;
static int32_t findVoronoiRegion (const SHSphereCollisionShape& sphere, const SHVec3& faceVertex, const SHVec3& faceNormal, const SHVec3& tangent1, const SHVec3& tangent2) noexcept;
static FaceQuery findClosestFace
(
const SHSphereCollisionShape& sphere
, const SHConvexPolyhedronCollisionShape& polyhedron
) noexcept;
static int32_t findClosestPoint
(
const SHSphereCollisionShape& sphere
, const SHConvexPolyhedronCollisionShape& polyhedron
, int32_t faceIndex
) noexcept;
static int32_t findVoronoiRegion
(
const SHSphereCollisionShape& sphere
, const SHVec3& faceVertex
, const SHVec3& faceNormal
, const SHVec3& tangent1
, const SHVec3& tangent2
) noexcept;
// Capsule VS Convex

View File

@ -185,7 +185,11 @@ namespace SHADE
/* Private Member Functions Definitions */
/*-----------------------------------------------------------------------------------*/
SHCollision::FaceQuery SHCollision::findClosestFace(const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron) noexcept
SHCollision::FaceQuery SHCollision::findClosestFace
(
const SHSphereCollisionShape& sphere
, const SHConvexPolyhedronCollisionShape& polyhedron
) noexcept
{
FaceQuery faceQuery;
@ -227,7 +231,12 @@ namespace SHADE
return faceQuery;
}
int32_t SHCollision::findClosestPoint(const SHSphereCollisionShape& sphere, const SHConvexPolyhedronCollisionShape& polyhedron, int32_t faceIndex) noexcept
int32_t SHCollision::findClosestPoint
(
const SHSphereCollisionShape& sphere
, const SHConvexPolyhedronCollisionShape& polyhedron
, int32_t faceIndex
) noexcept
{
// Find closest point on face
int32_t closestPointIndex = -1;
@ -253,7 +262,14 @@ namespace SHADE
return closestPointIndex;
}
int32_t SHCollision::findVoronoiRegion(const SHSphereCollisionShape& sphere, const SHVec3& faceVertex, const SHVec3& faceNormal, const SHVec3& tangent1, const SHVec3& tangent2) noexcept
int32_t SHCollision::findVoronoiRegion
(
const SHSphereCollisionShape& sphere
, const SHVec3& faceVertex
, const SHVec3& faceNormal
, const SHVec3& tangent1
, const SHVec3& tangent2
) noexcept
{
static constexpr int NUM_TANGENTS = 2;

View File

@ -160,44 +160,53 @@ namespace SHADE
contactManager->Update();
}
const SHCollisionSpace::RaycastHits& SHCollisionSpace::Raycast(const SHRay& ray, float distance, uint16_t layer) noexcept
const SHCollisionSpace::RaycastResults& SHCollisionSpace::Raycast(const RaycastInfo& info) noexcept
{
raycastHits.clear();
static RaycastResults results;
results.clear();
const bool FILTER_COLLIDER = info.colliderEntityID.has_value();
// Cast ray into the broadphase scene
const auto& POTENTIAL_HITS = broadphase.Query(info.ray, info.distance);
const auto& POTENTIAL_HITS = broadphase.Query(ray, distance);
if (POTENTIAL_HITS.empty())
return raycastHits;
return results;
// Test potential hits individually
// Cull entities that are on different layers
for (auto& shapeID : POTENTIAL_HITS)
// Iterate through all potential hits
const int NUM_HITS = static_cast<int>(POTENTIAL_HITS.size());
for (const int i : std::ranges::views::iota(0, NUM_HITS))
{
const auto HIT_ID = POTENTIAL_HITS[i];
const EntityID EID = HIT_ID.GetEntityID();
if (FILTER_COLLIDER && EID == info.colliderEntityID.value())
continue;
// Get shape
const EntityID EID = shapeID.GetEntityID();
const uint32_t IDX = shapeID.GetShapeIndex();
const uint32_t IDX = HIT_ID.GetShapeIndex();
const auto* SHAPE = colliders.find(EID)->second->GetCollisionShape(IDX);
const auto* COLLIDER = colliders.find(EID)->second;
const auto* SHAPE = COLLIDER->GetCollisionShape(IDX);
// Cull by layer
const bool LAYER_MATCH = SHAPE->GetCollisionTag().GetMask() & layer;
// Filter the layers
const bool LAYER_MATCH = SHAPE->GetCollisionTag().GetMask() & info.layers;
if (!LAYER_MATCH)
continue;
// Well this is awkward...I honestly don't have the mental capacity to solve this oversight right now.
// Cast the underlying shape to raycast. Convex hulls do not have an inherited raycast function
// We cast to the underlying shape. THis is done because a convex hull will not have an inherited raycast method.
// Kinda awkward oversight...oops
SHRaycastResult result;
SHRaycastResult baseResult;
switch (SHAPE->GetType())
{
case SHCollisionShape::Type::SPHERE:
{
result = dynamic_cast<const SHSphereCollisionShape*>(SHAPE)->Raycast(ray);
baseResult = dynamic_cast<const SHSphereCollisionShape*>(SHAPE)->Raycast(info.ray);
break;
}
case SHCollisionShape::Type::BOX:
{
result = dynamic_cast<const SHBoxCollisionShape*>(SHAPE)->Raycast(ray);
baseResult = dynamic_cast<const SHBoxCollisionShape*>(SHAPE)->Raycast(info.ray);
break;
}
case SHCollisionShape::Type::CAPSULE:
@ -205,118 +214,25 @@ namespace SHADE
// TODO
break;
}
default: break;
default: continue; // Redundant case
}
// If distance is greater than specified, skip this result
if (!result || result.distance > distance)
if (!baseResult || baseResult.distance > info.distance)
continue;
SHPhysicsRaycastResult physicsResult;
physicsResult.hit = result.hit;
physicsResult.distance = result.distance;
physicsResult.angle = result.angle;
physicsResult.position = result.position;
physicsResult.normal = result.normal;
physicsResult.entityHit = EID;
physicsResult.shapeIndex = IDX;
// Copy to a physics raycast result
SHPhysicsRaycastResult result;
memcpy_s(&result, sizeof(SHRaycastResult), &baseResult, sizeof(SHRaycastResult));
raycastHits.emplace_back(physicsResult);
result.entityHit = EID;
result.shapeIndex = IDX;
results.emplace_back(result);
}
// Sort by distance
std::ranges::sort(raycastHits.begin(), raycastHits.end(), [](const SHPhysicsRaycastResult& lhs, const SHPhysicsRaycastResult& rhs)
{
return lhs.distance < rhs.distance;
});
return raycastHits;
return results;
}
const SHCollisionSpace::RaycastHits& SHCollisionSpace::Linecast(const SHVec3& start, const SHVec3& end, uint16_t layer) noexcept
{
// Create bounded ray and reuse the raycast function
const SHRay BOUNDED_RAY{ start, SHVec3::Normalise(end - start) };
const float DISTANCE = SHVec3::Distance(end, start);
return Raycast(BOUNDED_RAY, DISTANCE, layer);
}
const SHCollisionSpace::RaycastHits& SHCollisionSpace::ColliderRaycast(EntityID colliderEID, const SHRay& ray, float distance, uint16_t layer) noexcept
{
raycastHits.clear();
const auto& POTENTIAL_HITS = broadphase.Query(ray, distance);
if (POTENTIAL_HITS.empty())
return raycastHits;
// Test potential hits individually
// Cull entities that are on different layers
for (auto& shapeID : POTENTIAL_HITS)
{
// Get shape
const EntityID EID = shapeID.GetEntityID();
const auto* COLLIDER = colliders.find(EID)->second;
// Cull any shapes on the same entity
if (EID == colliderEID)
continue;
const uint32_t IDX = shapeID.GetShapeIndex();
const auto* SHAPE = COLLIDER->GetCollisionShape(IDX);
// Cull by layer
const bool LAYER_MATCH = SHAPE->GetCollisionTag().GetMask() & layer;
if (!LAYER_MATCH)
continue;
// Well this is awkward...I honestly don't have the mental capacity to solve this oversight right now.
// Cast the underlying shape to raycast. Convex hulls do not have an inherited raycast function
SHRaycastResult result;
switch (SHAPE->GetType())
{
case SHCollisionShape::Type::SPHERE:
{
result = dynamic_cast<const SHSphereCollisionShape*>(SHAPE)->Raycast(ray);
break;
}
case SHCollisionShape::Type::BOX:
{
result = dynamic_cast<const SHBoxCollisionShape*>(SHAPE)->Raycast(ray);
break;
}
case SHCollisionShape::Type::CAPSULE:
{
// TODO
break;
}
default: break;
}
// If distance is greater than specified, skip this result
if (!result || result.distance > distance)
continue;
SHPhysicsRaycastResult physicsResult;
physicsResult.hit = result.hit;
physicsResult.distance = result.distance;
physicsResult.angle = result.angle;
physicsResult.position = result.position;
physicsResult.normal = result.normal;
physicsResult.entityHit = EID;
physicsResult.shapeIndex = IDX;
raycastHits.emplace_back(physicsResult);
}
// Sort by distance
std::ranges::sort(raycastHits.begin(), raycastHits.end(), [](const SHPhysicsRaycastResult& lhs, const SHPhysicsRaycastResult& rhs)
{
return lhs.distance < rhs.distance;
});
return raycastHits;
}
/*-----------------------------------------------------------------------------------*/
/* Private Member Functions Definitions */

View File

@ -13,12 +13,15 @@
#pragma once
#include <optional>
// Project Headers
#include "Broadphase/SHDynamicAABBTree.h"
#include "Physics/Dynamics/SHContactManager.h"
#include "SHCollider.h"
#include "SHPhysicsRaycastResult.h"
#include "CollisionTags/SHCollisionTags.h"
#include "CollisionTags/SHCollisionTags.h"
namespace SHADE
{
@ -38,7 +41,52 @@ namespace SHADE
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using RaycastHits = std::vector<SHPhysicsRaycastResult>;
/**
* @brief
* Contains information to cast a ray into the collision space.
* The collider entityID and shape index is optional.
*/
struct RaycastInfo
{
private:
/*-------------------------------------------------------------------------------*/
/* Friends */
/*-------------------------------------------------------------------------------*/
friend class SHCollisionSpace;
public:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
bool continuous = false;
uint16_t layers = static_cast<uint16_t>(SHCollisionTag::Layer::ALL);
float distance = std::numeric_limits<float>::infinity();
SHRay ray;
/*-------------------------------------------------------------------------------*/
/* Setter Functions */
/*-------------------------------------------------------------------------------*/
/**
* @brief
* Sets the collider ID for the raycast. Setting this specifies that the ray
* should ignore this collider.
* @param eid
* The entity ID of the collider.
*/
void SetColliderID(EntityID eid) noexcept { colliderEntityID = eid; }
private:
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
std::optional<EntityID> colliderEntityID;
};
using RaycastResults = std::vector<SHPhysicsRaycastResult>;
/*---------------------------------------------------------------------------------*/
/* Constructors & Destructor */
@ -98,68 +146,13 @@ namespace SHADE
/**
* @brief
* Casts a ray into the collision space.
* @param ray
* The ray to cast. The direction of the ray must be normalised.
* @param distance
* The distance to cast the ray. Defaults to infinity.
* @param layer
* The layer(s) the ray is casting on. Defaults to all layers.
* @param info
* Contains the information for the raycast.
* @return
* A container of all the objects the raycast hit, ordered by distance. <br/>
* The first object in the container is the first object hit etc.
* A container of the objects hit by the ray. If nothing was hit, the container
* will be empty.
*/
[[nodiscard]] const RaycastHits& Raycast
(
const SHRay& ray
, float distance = std::numeric_limits<float>::infinity()
, uint16_t layer = static_cast<uint16_t>(SHCollisionTag::Layer::ALL)
) noexcept;
/**
* @brief
* Casts a bounded ray into the collision space.
* @param start
* The origin of the ray.
* @param end
* The end of the ray.
* @param layer
* The layer(s) the ray is casting on. Defaults to all layers.
* @return
* A container of all the objects the raycast hit, ordered by distance. <br/>
* The first object in the container is the first object hit etc.
*/
[[nodiscard]] const RaycastHits& Linecast
(
const SHVec3& start
, const SHVec3& end
, uint16_t layer = static_cast<uint16_t>(SHCollisionTag::Layer::ALL)
) noexcept;
/**
* @brief
* Casts a ray into the collision space from a collider's position. <br/>
* The collider and all it's shapes will be ignored.
* @param colliderEID
* The entityID of the collider to cast from.
* @param ray
* The ray to cast. <br/>
* The position of the ray is the position offset from the collider's position. <br/>
* The direction of the ray must be normalised.
* @param distance
* The distance to cast the ray. Defaults to infinity.
* @param layer
* The layer(s) the ray is casting on. Defaults to all layers.
* @return
* A container of all the objects the raycast hit, ordered by distance. <br/>
* The first object in the container is the first object hit etc.
*/
[[nodiscard]] const RaycastHits& ColliderRaycast
(
EntityID colliderEID
, const SHRay& ray
, float distance = std::numeric_limits<float>::infinity()
, uint16_t layer = static_cast<uint16_t>(SHCollisionTag::Layer::ALL)
) noexcept;
[[nodiscard]] const RaycastResults& Raycast(const RaycastInfo& info) noexcept;
private:
/*---------------------------------------------------------------------------------*/
@ -184,25 +177,20 @@ namespace SHADE
Colliders colliders;
NarrowphaseBatch narrowphaseBatch;
RaycastHits raycastHits; // Reusable container for raycast results
SHAABBTree broadphase;
/*---------------------------------------------------------------------------------*/
/* Member Functions */
/*---------------------------------------------------------------------------------*/
// Broadphase helpers
void broadphaseQuery (SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept;
void broadphaseQuery (SHRigidBody::Type rigidBodyType, SHCollider* collider) noexcept;
// Narrowphase helpers
void collideTriggers (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept;
void collideManifolds (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept;
void collideTriggers (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept;
void collideManifolds (const SHCollisionKey& key, NarrowphasePair& narrowphasePair) const noexcept;
};
} // namespace SHADE

View File

@ -19,6 +19,7 @@
#include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h"
#include "Physics/Collision/SHCollisionSpace.h"
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
#include "Physics/Interface/SHColliderComponent.h"
#include "Scripting/SHScriptEngine.h"
@ -189,6 +190,25 @@ namespace SHADE
}
}
const std::vector<SHPhysicsRaycastResult>& SHPhysicsSystem::Raycast(const SHCollisionSpace::RaycastInfo& info) noexcept
{
auto& results = collisionSpace->Raycast(info);
// Load start and end points into the container for debug drawing
#ifdef SHEDITOR
SHVec3 endPos = info.ray.position + info.ray.direction * SHRay::MAX_RAYCAST_DIST;
if (!results.empty())
endPos = results.back().position;
raycastHits.emplace_back(info.ray.position, endPos);
#endif
return results;
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/

View File

@ -76,8 +76,25 @@ namespace SHADE
*/
void Init() override;
void Exit() override;
/**
* @brief
* Forces the world to take a single step. Interpolation of bodies cannot be done when
* forcing an update.
*/
void ForceUpdate();
/**
* @brief
* Casts a ray into the collision space.
* @param info
* Contains the information for the raycast.
* @return
* A container of the objects hit by the ray. If nothing was hit, the container
* will be empty.
*/
[[nodiscard]] const std::vector<SHPhysicsRaycastResult>& Raycast(const SHCollisionSpace::RaycastInfo& info) noexcept;
/*---------------------------------------------------------------------------------*/
/* System Routines */
/*---------------------------------------------------------------------------------*/
@ -129,6 +146,12 @@ namespace SHADE
using EventFunctionPair = std::pair<SHEventHandle(SHPhysicsSystem::*)(SHEventPtr), SHEventIdentifier>;
struct RaycastHit
{
SHVec3 start;
SHVec3 end;
};
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
@ -149,6 +172,11 @@ namespace SHADE
SHCollisionSpace* collisionSpace;
SHPhysicsObjectManager physicsObjectManager;
// For the debug drawer to draw rays
#ifdef SHEDITOR
std::vector<RaycastHit> raycastHits;
#endif
/*---------------------------------------------------------------------------------*/
/* Function Members */
/*---------------------------------------------------------------------------------*/

View File

@ -67,4 +67,16 @@ namespace SHADE
return 0.0;
}
const std::vector<SHPhysicsRaycastResult>& SHPhysicsSystemInterface::Raycast(const SHCollisionSpace::RaycastInfo& info) noexcept
{
static std::vector<SHPhysicsRaycastResult> emptyVec;
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (physicsSystem)
return physicsSystem->Raycast(info);
SHLOGV_WARNING("Failed to get fixed update rate. 0.0 returned instead.");
return emptyVec;
}
}

View File

@ -14,6 +14,7 @@ of DigiPen Institute of Technology is prohibited.
// Project Headers
#include "ECS_Base/Entity/SHEntity.h"
#include "Physics/Collision/SHCollisionSpace.h"
#include "Physics/Collision/Contacts/SHCollisionEvents.h"
@ -26,6 +27,7 @@ namespace SHADE
class SHVec3;
struct SHRay;
struct SHPhysicsRaycastResult;
struct SHCollisionSpace::RaycastInfo;
/*-----------------------------------------------------------------------------------*/
@ -47,9 +49,12 @@ namespace SHADE
/* Static Usage Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] static const std::vector<SHCollisionEvent>& GetCollisionInfo () noexcept;
[[nodiscard]] static const std::vector<SHTriggerEvent>& GetTriggerInfo () noexcept;
[[nodiscard]] static double GetFixedDT () noexcept;
[[nodiscard]] static int GetFixedUpdateRate () noexcept;
[[nodiscard]] static const std::vector<SHCollisionEvent>& GetCollisionInfo () noexcept;
[[nodiscard]] static const std::vector<SHTriggerEvent>& GetTriggerInfo () noexcept;
[[nodiscard]] static double GetFixedDT () noexcept;
[[nodiscard]] static int GetFixedUpdateRate () noexcept;
[[nodiscard]] static const std::vector<SHPhysicsRaycastResult>& Raycast (const SHCollisionSpace::RaycastInfo& info) noexcept;
};
}

View File

@ -128,39 +128,19 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
Vector3 BoxCollider::Center::get()
{
//return Convert::ToCLI(getNativeCollisionShape<SHAABB>().GetCenter());
return Vector3::Zero;
}
void BoxCollider::Center::set(Vector3 value)
{
//getNativeCollisionShape<SHAABB>().SetCenter(Convert::ToNative(value));
return Convert::ToCLI(getNativeCollisionShape<SHBoxCollisionShape>().GetCenter());
}
Vector3 BoxCollider::HalfExtents::get()
{
//return Convert::ToCLI(getNativeCollisionShape<SHAABB>().GetExtents());
return Vector3::Zero;
return Convert::ToCLI(getNativeCollisionShape<SHBoxCollisionShape>().GetWorldExtents());
}
void BoxCollider::HalfExtents::set(Vector3 value)
{
//getNativeCollisionShape<SHAABB>().SetExtents(Convert::ToNative(value));
getNativeCollisionShape<SHBoxCollisionShape>().SetWorldExtents(Convert::ToNative(value));
}
Vector3 BoxCollider::Min::get()
Quaternion BoxCollider::Orientation::get()
{
//return Convert::ToCLI(getNativeCollisionShape<SHAABB>().GetMin());
return Vector3::Zero;
}
void BoxCollider::Min::set(Vector3 value)
{
//getNativeCollisionShape<SHAABB>().SetMin(Convert::ToNative(value));
}
Vector3 BoxCollider::Max::get()
{
//return Convert::ToCLI(getNativeCollisionShape<SHAABB>().GetMax());
return Vector3::Zero;
}
void BoxCollider::Max::set(Vector3 value)
{
//getNativeCollisionShape<SHAABB>().SetMax(Convert::ToNative(value));
return Convert::ToCLI(getNativeCollisionShape<SHBoxCollisionShape>().GetOrientation());
}
/*---------------------------------------------------------------------------------*/
@ -184,10 +164,6 @@ namespace SHADE
{
return Convert::ToCLI(getNativeCollisionShape<SHSphereCollisionShape>().GetCenter());
}
void SphereCollider::Center::set(Vector3 value)
{
getNativeCollisionShape<SHSphereCollisionShape>().SetCenter(Convert::ToNative(value));
}
float SphereCollider::Radius::get()
{
return getNativeCollisionShape<SHSphereCollisionShape>().GetWorldRadius();

View File

@ -142,15 +142,14 @@ namespace SHADE
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Center of the Bounding Box formed by this bound.
/// Center of the box collider.
/// </summary>
property Vector3 Center
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Half of the scale of the Bounding Box formed by this bound.
/// Half of the scale of the box collider.
/// </summary>
property Vector3 HalfExtents
{
@ -158,22 +157,11 @@ namespace SHADE
void set(Vector3 value);
}
/// <summary>
/// Position of the bottom left back corner of the Bounding Box formed by this
/// bound.
/// The orientation of the box.
/// </summary>
property Vector3 Min
property Quaternion Orientation
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Position of the top right front corner of the Bounding Box formed by this
/// bound.
/// </summary>
property Vector3 Max
{
Vector3 get();
void set(Vector3 value);
Quaternion get();
}
/*-----------------------------------------------------------------------------*/
@ -201,12 +189,11 @@ namespace SHADE
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Center of the Bounding Sphere formed by this bound.
/// Center of the sphere.
/// </summary>
property Vector3 Center
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Radius of the Bounding Sphere formed by this bound.

View File

@ -15,10 +15,15 @@
// External Dependencies
#include "Physics/System/SHPhysicsSystemInterface.h"
// Project Header
#include "Components/Collider.hxx"
#include "Components/Transform.hxx"
#include "Engine/GameObject.hxx"
#include "Physics/Collision/SHCollisionSpace.h"
#include "Utility/Convert.hxx"
#include "Utility/Debug.hxx"
using namespace System::Collections::Generic;
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
@ -41,49 +46,301 @@ namespace SHADE
/* Raycast Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
RaycastHit Physics::Raycast(Ray ray)
List<RaycastHit>^ Physics::Raycast(Ray ray, bool continuous)
{
return RaycastHit{};
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Cast natively
SHCollisionSpace::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.continuous = continuous;
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
RaycastHit Physics::Raycast(Ray ray, float distance)
List<RaycastHit>^ Physics::Raycast(Ray ray, float distance, bool continuous)
{
return RaycastHit{};
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Cast natively
SHCollisionSpace::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.distance = distance;
raycastInfo.continuous = continuous;
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
RaycastHit Physics::Linecast(Vector3 start, Vector3 end)
List<RaycastHit>^ Physics::Linecast(Vector3 start, Vector3 end, bool continuous)
{
return RaycastHit{};
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Cast natively
Vector3 direction = end - start;
direction.Normalise();
const Ray CLI_RAY( start, direction );
SHCollisionSpace::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(CLI_RAY);
raycastInfo.distance = (end - start).GetMagnitude();
raycastInfo.continuous = continuous;
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray)
List<RaycastHit>^ Physics::ColliderRaycast(GameObject object, Ray ray, bool continuous)
{
return RaycastHit{};
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position (same as the transform)
Transform^ managedTransform = object.GetComponent<Transform^>();
if (!managedTransform)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform.");
const Vector3 COLLIDER_POS = managedTransform->GlobalPosition;
ray.Position += COLLIDER_POS;
SHCollisionSpace::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.continuous = continuous;
raycastInfo.SetColliderID(object.EntityId);
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
RaycastHit Physics::ColliderRaycast(GameObject object, Ray ray, float distance)
List<RaycastHit>^ Physics::ColliderRaycast(GameObject object, Ray ray, float distance, bool continuous)
{
return RaycastHit{};
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position (same as the transform)
Transform^ managedTransform = object.GetComponent<Transform^>();
if (!managedTransform)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform.");
const Vector3 COLLIDER_POS = managedTransform->GlobalPosition;
ray.Position += COLLIDER_POS;
SHCollisionSpace::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.distance = distance;
raycastInfo.continuous = continuous;
raycastInfo.SetColliderID(object.EntityId);
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray)
List<RaycastHit>^ Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, bool continuous)
{
return RaycastHit{};
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position
Vector3 shapePos = Vector3::Zero;
Collider^ managedCollider = object.GetComponent<Collider^>();
if (!managedCollider)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Collider.");
CollisionShape^ managedShape = managedCollider->GetCollisionShape(shapeIndex);
if (!managedShape)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape.");
const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape();
switch (NATIVE_SHAPE.GetType())
{
case SHCollisionShape::Type::SPHERE:
{
shapePos = Convert::ToCLI(dynamic_cast<const SHSphereCollisionShape&>(NATIVE_SHAPE).GetCenter());
break;
}
case SHCollisionShape::Type::BOX:
{
shapePos = Convert::ToCLI(dynamic_cast<const SHBoxCollisionShape&>(NATIVE_SHAPE).GetCenter());
break;
}
default: break;
}
ray.Position += shapePos;
SHCollisionSpace::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.continuous = continuous;
raycastInfo.SetColliderID(object.EntityId);
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
RaycastHit Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance)
List<RaycastHit>^ Physics::ColliderRaycast(GameObject object, int shapeIndex, Ray ray, float distance, bool continuous)
{
return RaycastHit{};
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position
Vector3 shapePos = Vector3::Zero;
Collider^ managedCollider = object.GetComponent<Collider^>();
if (!managedCollider)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Collider.");
CollisionShape^ managedShape = managedCollider->GetCollisionShape(shapeIndex);
if (!managedShape)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape.");
const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape();
switch (NATIVE_SHAPE.GetType())
{
case SHCollisionShape::Type::SPHERE:
{
shapePos = Convert::ToCLI(dynamic_cast<const SHSphereCollisionShape&>(NATIVE_SHAPE).GetCenter());
break;
}
case SHCollisionShape::Type::BOX:
{
shapePos = Convert::ToCLI(dynamic_cast<const SHBoxCollisionShape&>(NATIVE_SHAPE).GetCenter());
break;
}
default: break;
}
ray.Position += shapePos;
SHCollisionSpace::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(ray);
raycastInfo.continuous = continuous;
raycastInfo.distance = distance;
raycastInfo.SetColliderID(object.EntityId);
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
RaycastHit Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end)
List<RaycastHit>^ Physics::ColliderLineCast(GameObject object, Vector3 start, Vector3 end, bool continuous)
{
return RaycastHit{};
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position (same as the transform)
Transform^ managedTransform = object.GetComponent<Transform^>();
if (!managedTransform)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Transform.");
const Vector3 COLLIDER_POS = managedTransform->GlobalPosition;
start += COLLIDER_POS;
Vector3 direction = end - start;
direction.Normalise();
const Ray CLI_RAY( start, direction );
SHCollisionSpace::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(CLI_RAY);
raycastInfo.distance = (end - start).GetMagnitude();
raycastInfo.continuous = continuous;
raycastInfo.SetColliderID(object.EntityId);
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
RaycastHit Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end)
List<RaycastHit>^ Physics::ColliderLineCast(GameObject object, int shapeIndex, Vector3 start, Vector3 end, bool continuous)
{
return RaycastHit{};
List<RaycastHit>^ results = gcnew List<RaycastHit>();
// Get the collider's position
Vector3 shapePos = Vector3::Zero;
Collider^ managedCollider = object.GetComponent<Collider^>();
if (!managedCollider)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid Collider.");
CollisionShape^ managedShape = managedCollider->GetCollisionShape(shapeIndex);
if (!managedShape)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape.");
const auto& NATIVE_SHAPE = managedShape->getNativeCollisionShape();
switch (NATIVE_SHAPE.GetType())
{
case SHCollisionShape::Type::SPHERE:
{
shapePos = Convert::ToCLI(dynamic_cast<const SHSphereCollisionShape&>(NATIVE_SHAPE).GetCenter());
break;
}
case SHCollisionShape::Type::BOX:
{
shapePos = Convert::ToCLI(dynamic_cast<const SHBoxCollisionShape&>(NATIVE_SHAPE).GetCenter());
break;
}
default: break;
}
start += shapePos;
Vector3 direction = end - start;
direction.Normalise();
const Ray CLI_RAY( start, direction );
SHCollisionSpace::RaycastInfo raycastInfo;
raycastInfo.ray = Convert::ToNative(CLI_RAY);
raycastInfo.continuous = continuous;
raycastInfo.distance = (end - start).GetMagnitude();
raycastInfo.SetColliderID(object.EntityId);
const auto& NATIVE_RESULTS = SHPhysicsSystemInterface::Raycast(raycastInfo);
if (!NATIVE_RESULTS.empty())
{
for (const auto& nativeResult : NATIVE_RESULTS)
results->Add(Convert::ToCLI(nativeResult));
}
return results;
}
/*-----------------------------------------------------------------------------------*/

View File

@ -10,6 +10,7 @@
#pragma once
// Project Includes
#include "Math/Ray.hxx"
#include "RaycastHit.hxx"
@ -39,83 +40,146 @@ namespace SHADE
/* Raycast Function Members */
/*---------------------------------------------------------------------------------*/
// TODO(Diren): Add layers for raycasting
/// <summary>
/// Casts an infinite ray into the world.
/// Casts an infinite ray into the world. <br/>
/// This raycast will stop at the first object hit.
/// </summary>
/// <param name="ray">The ray to cast.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit Raycast (Ray ray);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ Raycast (Ray ray, bool continuous);
/// <summary>
/// Casts a ray for a given distance into the world.
/// </summary>
/// <param name="ray">The ray to cast.</param>
/// <param name="distance">The distance to cast the ray.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit Raycast (Ray ray, float distance);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ Raycast (Ray ray, float distance, bool continuous);
/// <summary>
/// Casts a bounded ray into the world.
/// </summary>
/// <param name="start">The start of the bounded ray.</param>
/// <param name="end">The end of the bounded ray.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit Linecast (Vector3 start, Vector3 end);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ Linecast (Vector3 start, Vector3 end, bool continuous);
/// <summary>
/// Casts an infinite ray w.r.t a GameObject.
/// </summary>
/// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="ray">The ray to cast.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit ColliderRaycast (GameObject object, Ray ray);
/// <param name="ray">
/// The ray to cast. <br/>
/// The position of the ray is offset from the collider's position.
/// </param>
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderRaycast (GameObject object, Ray ray, bool continuous);
/// <summary>
/// Casts a ray for a given distance w.r.t a GameObject.
/// </summary>
/// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="ray">The ray to cast.</param>
/// <param name="ray">
/// The ray to cast. <br/>
/// The position of the ray is offset from the collider's position.
/// </param>
/// <param name="distance">The distance to cast the ray.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit ColliderRaycast (GameObject object, Ray ray, float distance);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderRaycast (GameObject object, Ray ray, float distance, bool continuous);
/// <summary>
/// Casts an infinite ray w.r.t a specific collider on a GameObject.
/// </summary>
/// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="shapeIndex">The collision shape index on the collider to cast to.</param>
/// <param name="ray">The ray to cast.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray);
/// <param name="ray">
/// The ray to cast. <br/>
/// The position of the ray is offset from the collider's position.
/// </param>
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderRaycast (GameObject object, int shapeIndex, Ray ray, bool continuous);
/// <summary>
/// Casts a ray for a given distance w.r.t a specific collider on a GameObject.
/// </summary>
/// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="shapeIndex">The collision shape index on the collider to cast to.</param>
/// <param name="ray">The ray to cast.</param>
/// <param name="ray">
/// The ray to cast. <br/>
/// The position of the ray is offset from the collider's position.
/// </param>
/// <param name="distance">The distance to cast the ray.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderRaycast (GameObject object, int shapeIndex, Ray ray, float distance, bool continuous);
/// <summary>
/// Casts a bounded ray w.r.t a GameObject.
/// </summary>
/// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="start">The start of the bounded ray.</param>
/// <param name="start">
/// The start of the bounded ray. <br/>
/// The start of the ray is offset from the collider's position. </param>
/// <param name="end"></param>
/// <returns>The result of the raycast.</returns>
static RaycastHit ColliderLineCast (GameObject object, Vector3 start, Vector3 end);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned.
/// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderLineCast (GameObject object, Vector3 start, Vector3 end, bool continuous);
/// <summary>
/// Casts a bounded ray w.r.t a specific collider on a GameObject.
/// </summary>
/// <param name="object">The GameObject to cast the ray to.</param>
/// <param name="shapeIndex">The collision shape index on the collider to cast to.</param>
/// <param name="start">The start of the bounded ray.</param>
/// <param name="start">
/// The start of the bounded ray. <br/>
/// The start of the ray is offset from the collider's position. </param>
/// <param name="end">The end of the bounded ray.</param>
/// <returns>The result of the raycast.</returns>
static RaycastHit ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end);
/// <param name="continuous">
/// Whether or not the raycast should stop at the first object hit.
/// </param>
/// <returns>
/// The results of the raycast. If nothing was hit, an empty list is returned./// </returns>
static System::Collections::Generic::List<RaycastHit>^ ColliderLineCast (GameObject object, int shapeIndex, Vector3 start, Vector3 end, bool continuous);
private:
/*---------------------------------------------------------------------------------*/

View File

@ -103,6 +103,39 @@ namespace SHADE
/* Physics Conversions */
/*---------------------------------------------------------------------------------*/
SHPhysicsRaycastResult Convert::ToNative(RaycastHit cli)
{
// This function shouldn't be used anyway, so we leave the entityHit empty.
SHPhysicsRaycastResult native;
native.hit = cli.Hit;
native.position = ToNative(cli.Position);
native.normal = ToNative(cli.Normal);
native.distance = cli.Distance;
native.shapeIndex = cli.CollisionShapeIndex;
return native;
}
RaycastHit Convert::ToCLI(const SHPhysicsRaycastResult& native)
{
RaycastHit cli;
cli.Hit = native.hit;
cli.Position = ToCLI(native.position);
cli.Normal = ToCLI(native.normal);
cli.Distance = native.distance;
cli.CollisionShapeIndex = native.shapeIndex;
cli.Other = SHEntityManager::IsValidEID(native.entityHit)
? GameObject(native.entityHit)
: System::Nullable<GameObject>();
return cli;
}
/*---------------------------------------------------------------------------------*/
/* Handle Conversions */
/*---------------------------------------------------------------------------------*/

View File

@ -141,6 +141,20 @@ namespace SHADE
/* Physics Conversions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Converts from a managed RaycastHit to a native SHPhysicsRaycastResult
/// </summary>
/// <param name="cli">The managed RaycastHit to convert from.</param>
/// <returns>Native copy of a managed RaycastHit.</returns>
static SHPhysicsRaycastResult ToNative(RaycastHit cli);
/// <summary>
/// Converts from a native SHPhysicsRaycastResult to a managed RaycastHit
/// </summary>
/// <param name="cli">The native SHPhysicsRaycastResult to convert from.</param>
/// <returns>Managed copy of a native SHPhysicsRaycastResult.</returns>
static RaycastHit ToCLI(const SHPhysicsRaycastResult& native);
/*-----------------------------------------------------------------------------*/
/* Handle Conversions */
/*-----------------------------------------------------------------------------*/