From 42fb50e93edb575acafa23bf2b0daefd49586ba1 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Thu, 31 Jul 2014 20:13:13 +0200 Subject: [PATCH] Add the collision grouping logic. --- src/collider.cpp | 93 +++++++++++++++++++++++++++++++++++++++- src/collider.hpp | 15 ++++++- src/gameplayscene.cpp | 2 +- src/horzcollisionbar.cpp | 16 ++++--- src/horzcollisionbar.hpp | 16 ++++--- 5 files changed, 129 insertions(+), 13 deletions(-) diff --git a/src/collider.cpp b/src/collider.cpp index eb54051..e07113d 100644 --- a/src/collider.cpp +++ b/src/collider.cpp @@ -18,6 +18,10 @@ */ #include "collider.hpp" +#include "horzcollisionbar.hpp" +#include "line.hpp" +#include "vector.hpp" +#include "vectormath.hpp" #include #include #include @@ -30,6 +34,68 @@ namespace cloonel { namespace { + typedef std::vector CollisionBarListType; + typedef std::vector> CollisionBarGroupListType; + const CollisionBarListType g_empty; + + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + const CollisionBarListType& findGroup (const CollisionBarGroupListType& parList, Collider::GroupIDType parID) { + for (const auto& itm : parList) { + if (itm.first == parID) { + return itm.second; + } + } + assert(false); + return g_empty; + } + +#if !defined(NDEBUG) + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + bool isGroupRegistered (const CollisionBarGroupListType& parList, Collider::GroupIDType parID) { + const CollisionBarListType& result = findGroup(parList, parID); + return &g_empty != &result; + } +#endif + + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + CollisionBarListType& findOrAddGroup (CollisionBarGroupListType& parList, Collider::GroupIDType parID) { + for (auto& itm : parList) { + if (itm.first == parID) { + return itm.second; + } + } + parList.push_back(std::make_pair(parID, CollisionBarListType())); + assert(parList.back().first == parID); + return parList.back().second; + } + + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + void collide (float parDeltaT, const CollisionBarListType& parGroup1, const CollisionBarListType& parGroup2) { + Line overlap; + for (const auto& bar1 : parGroup1) { + assert(bar1); + for (const auto& bar2 : parGroup2) { + assert(bar2); + if (bar2 == bar1) + continue; + + if (Collide(parDeltaT, *bar1, *bar2, overlap)) { +#if defined(VERBOSE_COLLIDER) + std::cout << "Collider: Collision while testing group " << parGroup1 << " and " << parGroup2 << " "; + std::cout << "between " << bar1 << " and " << bar2 << "\n"; +#endif + const auto dir1 = normalized(bar1->GetPos() - bar1->From()); + bar1->InvokeCallback(overlap, dir1); + const auto dir2 = normalized(bar2->GetPos() - bar2->From()); + bar2->InvokeCallback(overlap, dir2); + } + } + } + } } //unnamed namespace ///-------------------------------------------------------------------------- @@ -44,7 +110,32 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - void Collider::RunCollisionTests() { + void Collider::RunCollisionTests (float parDeltaT) const { + for (const auto& relationship : m_relationships) { + const CollisionBarListType& group1 = findGroup(m_collisionBars, relationship.first); + const CollisionBarListType& group2 = (relationship.first == relationship.second ? group1 : findGroup(m_collisionBars, relationship.second)); + + collide(parDeltaT, group1, group2); + } + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void Collider::TieGroups (GroupIDType parGroup1, GroupIDType parGroup2) { + assert(m_relationships.end() == std::find(m_relationships.begin(), m_relationships.end(), std::make_pair(parGroup1, parGroup2))); + assert(m_relationships.end() == std::find(m_relationships.begin(), m_relationships.end(), std::make_pair(parGroup2, parGroup1))); + assert(isGroupRegistered(m_collisionBars, parGroup1)); + assert(isGroupRegistered(m_collisionBars, parGroup2)); + m_relationships.push_back(std::make_pair(parGroup1, parGroup2)); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void Collider::RegisterBar (GroupIDType parGroup, const CollisionBar* parBar) { + CollisionBarListType& group = findOrAddGroup(m_collisionBars, parGroup); + assert(isGroupRegistered(m_collisionBars, parGroup)); + assert(parBar); + group.push_back(parBar); } } //namespace cloonel diff --git a/src/collider.hpp b/src/collider.hpp index a43bcff..55af143 100644 --- a/src/collider.hpp +++ b/src/collider.hpp @@ -22,18 +22,31 @@ #include "observersmanager.hpp" #include +#include +#include namespace cloonel { class HorzCollisionBar; + typedef HorzCollisionBar CollisionBar; + class Collider { public: + typedef int GroupIDType; + Collider ( void ); ~Collider ( void ) noexcept; - void RunCollisionTests ( void ); + void RunCollisionTests ( float parDeltaT ) const; + void TieGroups ( GroupIDType parGroup1, GroupIDType parGroup2 ); + void RegisterBar ( GroupIDType parGroup, const CollisionBar* parBar ); private: + typedef std::vector>> CollisionBarGroupListType; + typedef std::vector> RelationshipListType; + + RelationshipListType m_relationships; + CollisionBarGroupListType m_collisionBars; }; } //namespace cloonel diff --git a/src/gameplayscene.cpp b/src/gameplayscene.cpp index 9826819..7bb5ba7 100644 --- a/src/gameplayscene.cpp +++ b/src/gameplayscene.cpp @@ -35,7 +35,7 @@ namespace cloonel { for (auto itMover : m_movers) { itMover->Update(parDelta); } - m_collider.RunCollisionTests(); + m_collider.RunCollisionTests(parDelta); } ///-------------------------------------------------------------------------- diff --git a/src/horzcollisionbar.cpp b/src/horzcollisionbar.cpp index 04f9bf8..de706cf 100644 --- a/src/horzcollisionbar.cpp +++ b/src/horzcollisionbar.cpp @@ -26,10 +26,10 @@ namespace cloonel { namespace { - typedef Line Line2D; + typedef HorzCollisionBar::Line2D Line2D; float calculateOverlappingTime ( float parDeltaT, float parAY, float parBY, float parDeltaA, float parDeltaB ) __attribute__((pure)); - void DoNothing ( void ) __attribute__((pure)); + void DoNothing ( const Line2D&, const float2& ) __attribute__((pure)); std::pair getOverlap ( float parDeltaT, const Line2D& parA, const Line2D& parB, const float2& parDeltaA, const float2& parDeltaB ) __attribute__((pure)); ///---------------------------------------------------------------------- @@ -73,7 +73,7 @@ namespace cloonel { ///---------------------------------------------------------------------- ///no-op ///---------------------------------------------------------------------- - void DoNothing() { + void DoNothing (const HorzCollisionBar::Line2D&, const float2&) { } } //unnamed namespace @@ -89,7 +89,7 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - void HorzCollisionBar::SetCallback (std::function parCallback) { + void HorzCollisionBar::SetCallback (CallbackType parCallback) { m_callback = parCallback; } @@ -101,7 +101,13 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - bool Collide (float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line& parOut) { + void HorzCollisionBar::InvokeCallback (const Line2D& parOverlap, const float2& parDirection) const { + m_callback(parOverlap, parDirection); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + bool Collide (float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, HorzCollisionBar::Line2D& parOut) { const auto offsetA = parA.GetPos() - parA.m_segment.Start(); const auto offsetB = parB.GetPos() - parB.m_segment.Start(); const auto overlap(getOverlap(parDeltaT, parA.m_segment, parB.m_segment, offsetA, offsetB)); diff --git a/src/horzcollisionbar.hpp b/src/horzcollisionbar.hpp index 88c13c5..f3eb933 100644 --- a/src/horzcollisionbar.hpp +++ b/src/horzcollisionbar.hpp @@ -29,7 +29,10 @@ namespace cloonel { class HorzCollisionBar; class HorzCollisionBar : public Placeable { - friend bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line& parOut ); + public: + typedef Line Line2D; + typedef std::function CallbackType; + public: HorzCollisionBar ( const float2& parFrom, float parLength ); ~HorzCollisionBar ( void ) noexcept = default; @@ -37,14 +40,17 @@ namespace cloonel { float2 From ( void ) const { return this->GetPos(); } float2 To ( void ) const; - void SetCallback ( std::function parCallback ); + void SetCallback ( CallbackType parCallback ); + void InvokeCallback ( const Line2D& parOverlap, const float2& parDirection ) const; private: - Line m_segment; - std::function m_callback; + friend bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line2D& parOut ); + + Line2D m_segment; + CallbackType m_callback; }; - bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line& parOut ) __attribute__((pure)); + bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, HorzCollisionBar::Line2D& parOut ) __attribute__((pure)); } //namespace cloonel #endif