diff --git a/include/Nazara/Physics2D/PhysWorld2D.hpp b/include/Nazara/Physics2D/PhysWorld2D.hpp index f116b7729..3f4c3e696 100644 --- a/include/Nazara/Physics2D/PhysWorld2D.hpp +++ b/include/Nazara/Physics2D/PhysWorld2D.hpp @@ -31,6 +31,7 @@ namespace Nz public: struct Callback; struct NearestQueryResult; + struct RaycastHit; PhysWorld2D(); PhysWorld2D(const PhysWorld2D&) = delete; @@ -44,6 +45,9 @@ namespace Nz bool NearestBodyQuery(const Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RigidBody2D** nearestBody = nullptr); bool NearestBodyQuery(const Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result); + bool RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* hitInfos); + bool RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo = nullptr); + void RegisterCallbacks(unsigned int collisionId, const Callback& callbacks); void RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, const Callback& callbacks); @@ -72,6 +76,14 @@ namespace Nz float distance; }; + struct RaycastHit + { + Nz::RigidBody2D* nearestBody; + Nz::Vector2f hitPos; + Nz::Vector2f hitNormal; + float fraction; + }; + NazaraSignal(OnPhysWorld2DPreStep, const PhysWorld2D* /*physWorld*/); NazaraSignal(OnPhysWorld2DPostStep, const PhysWorld2D* /*physWorld*/); diff --git a/src/Nazara/Physics2D/PhysWorld2D.cpp b/src/Nazara/Physics2D/PhysWorld2D.cpp index 1383f931b..6b18dbdd8 100644 --- a/src/Nazara/Physics2D/PhysWorld2D.cpp +++ b/src/Nazara/Physics2D/PhysWorld2D.cpp @@ -81,6 +81,58 @@ namespace Nz } } + bool PhysWorld2D::RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* hitInfos) + { + auto callback = [](cpShape* shape, cpVect point, cpVect normal, cpFloat alpha, void* data) + { + std::vector* results = reinterpret_cast*>(data); + + RaycastHit hitInfo; + hitInfo.fraction = alpha; + hitInfo.hitNormal.Set(normal.x, normal.y); + hitInfo.hitPos.Set(point.x, point.y); + hitInfo.nearestBody = static_cast(cpShapeGetUserData(shape)); + + results->emplace_back(std::move(hitInfo)); + }; + + cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask); + + std::size_t previousSize = hitInfos->size(); + cpSpaceSegmentQuery(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, callback, hitInfos); + + return hitInfos->size() != previousSize; + } + + bool PhysWorld2D::RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo) + { + cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask); + + if (hitInfo) + { + cpSegmentQueryInfo queryInfo; + + if (cpShape* shape = cpSpaceSegmentQueryFirst(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, &queryInfo)) + { + hitInfo->fraction = queryInfo.alpha; + hitInfo->hitNormal.Set(queryInfo.normal.x, queryInfo.normal.y); + hitInfo->hitPos.Set(queryInfo.point.x, queryInfo.point.y); + hitInfo->nearestBody = static_cast(cpShapeGetUserData(queryInfo.shape)); + + return true; + } + else + return false; + } + else + { + if (cpShape* shape = cpSpaceSegmentQueryFirst(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, nullptr)) + return true; + else + return false; + } + } + void PhysWorld2D::RegisterCallbacks(unsigned int collisionId, const Callback& callbacks) { InitCallbacks(cpSpaceAddWildcardHandler(m_handle, collisionId), callbacks);