Add the collision grouping logic.
This commit is contained in:
parent
1037e2e141
commit
42fb50e93e
5 changed files with 129 additions and 13 deletions
|
@ -18,6 +18,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "collider.hpp"
|
#include "collider.hpp"
|
||||||
|
#include "horzcollisionbar.hpp"
|
||||||
|
#include "line.hpp"
|
||||||
|
#include "vector.hpp"
|
||||||
|
#include "vectormath.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <ciso646>
|
#include <ciso646>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
@ -30,6 +34,68 @@
|
||||||
|
|
||||||
namespace cloonel {
|
namespace cloonel {
|
||||||
namespace {
|
namespace {
|
||||||
|
typedef std::vector<const CollisionBar*> CollisionBarListType;
|
||||||
|
typedef std::vector<std::pair<Collider::GroupIDType, CollisionBarListType>> 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<float, 2> 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
|
} //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
|
} //namespace cloonel
|
||||||
|
|
||||||
|
|
|
@ -22,18 +22,31 @@
|
||||||
|
|
||||||
#include "observersmanager.hpp"
|
#include "observersmanager.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace cloonel {
|
namespace cloonel {
|
||||||
class HorzCollisionBar;
|
class HorzCollisionBar;
|
||||||
|
|
||||||
|
typedef HorzCollisionBar CollisionBar;
|
||||||
|
|
||||||
class Collider {
|
class Collider {
|
||||||
public:
|
public:
|
||||||
|
typedef int GroupIDType;
|
||||||
|
|
||||||
Collider ( void );
|
Collider ( void );
|
||||||
~Collider ( void ) noexcept;
|
~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:
|
private:
|
||||||
|
typedef std::vector<std::pair<GroupIDType, std::vector<const CollisionBar*>>> CollisionBarGroupListType;
|
||||||
|
typedef std::vector<std::pair<GroupIDType, GroupIDType>> RelationshipListType;
|
||||||
|
|
||||||
|
RelationshipListType m_relationships;
|
||||||
|
CollisionBarGroupListType m_collisionBars;
|
||||||
};
|
};
|
||||||
} //namespace cloonel
|
} //namespace cloonel
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace cloonel {
|
||||||
for (auto itMover : m_movers) {
|
for (auto itMover : m_movers) {
|
||||||
itMover->Update(parDelta);
|
itMover->Update(parDelta);
|
||||||
}
|
}
|
||||||
m_collider.RunCollisionTests();
|
m_collider.RunCollisionTests(parDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
///--------------------------------------------------------------------------
|
///--------------------------------------------------------------------------
|
||||||
|
|
|
@ -26,10 +26,10 @@
|
||||||
|
|
||||||
namespace cloonel {
|
namespace cloonel {
|
||||||
namespace {
|
namespace {
|
||||||
typedef Line<float, 2> Line2D;
|
typedef HorzCollisionBar::Line2D Line2D;
|
||||||
|
|
||||||
float calculateOverlappingTime ( float parDeltaT, float parAY, float parBY, float parDeltaA, float parDeltaB ) __attribute__((pure));
|
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<bool, Line2D> getOverlap ( float parDeltaT, const Line2D& parA, const Line2D& parB, const float2& parDeltaA, const float2& parDeltaB ) __attribute__((pure));
|
std::pair<bool, Line2D> 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
|
///no-op
|
||||||
///----------------------------------------------------------------------
|
///----------------------------------------------------------------------
|
||||||
void DoNothing() {
|
void DoNothing (const HorzCollisionBar::Line2D&, const float2&) {
|
||||||
}
|
}
|
||||||
} //unnamed namespace
|
} //unnamed namespace
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ namespace cloonel {
|
||||||
|
|
||||||
///--------------------------------------------------------------------------
|
///--------------------------------------------------------------------------
|
||||||
///--------------------------------------------------------------------------
|
///--------------------------------------------------------------------------
|
||||||
void HorzCollisionBar::SetCallback (std::function<void()> parCallback) {
|
void HorzCollisionBar::SetCallback (CallbackType parCallback) {
|
||||||
m_callback = parCallback;
|
m_callback = parCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,13 @@ namespace cloonel {
|
||||||
|
|
||||||
///--------------------------------------------------------------------------
|
///--------------------------------------------------------------------------
|
||||||
///--------------------------------------------------------------------------
|
///--------------------------------------------------------------------------
|
||||||
bool Collide (float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line<float, 2>& 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 offsetA = parA.GetPos() - parA.m_segment.Start();
|
||||||
const auto offsetB = parB.GetPos() - parB.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));
|
const auto overlap(getOverlap(parDeltaT, parA.m_segment, parB.m_segment, offsetA, offsetB));
|
||||||
|
|
|
@ -29,7 +29,10 @@ namespace cloonel {
|
||||||
class HorzCollisionBar;
|
class HorzCollisionBar;
|
||||||
|
|
||||||
class HorzCollisionBar : public Placeable {
|
class HorzCollisionBar : public Placeable {
|
||||||
friend bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line<float, 2>& parOut );
|
public:
|
||||||
|
typedef Line<float, 2> Line2D;
|
||||||
|
typedef std::function<void(const Line2D&, const float2&)> CallbackType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HorzCollisionBar ( const float2& parFrom, float parLength );
|
HorzCollisionBar ( const float2& parFrom, float parLength );
|
||||||
~HorzCollisionBar ( void ) noexcept = default;
|
~HorzCollisionBar ( void ) noexcept = default;
|
||||||
|
@ -37,14 +40,17 @@ namespace cloonel {
|
||||||
float2 From ( void ) const { return this->GetPos(); }
|
float2 From ( void ) const { return this->GetPos(); }
|
||||||
float2 To ( void ) const;
|
float2 To ( void ) const;
|
||||||
|
|
||||||
void SetCallback ( std::function<void()> parCallback );
|
void SetCallback ( CallbackType parCallback );
|
||||||
|
void InvokeCallback ( const Line2D& parOverlap, const float2& parDirection ) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Line<float, 2> m_segment;
|
friend bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line2D& parOut );
|
||||||
std::function<void()> m_callback;
|
|
||||||
|
Line2D m_segment;
|
||||||
|
CallbackType m_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line<float, 2>& parOut ) __attribute__((pure));
|
bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, HorzCollisionBar::Line2D& parOut ) __attribute__((pure));
|
||||||
} //namespace cloonel
|
} //namespace cloonel
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue