2014-07-28 11:00:55 +02:00
|
|
|
/*
|
|
|
|
Copyright 2014 Michele "King_DuckZ" Santullo
|
|
|
|
|
|
|
|
This file is part of CloonelJump.
|
|
|
|
|
|
|
|
CloonelJump is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
CloonelJump is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with CloonelJump. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "collider.hpp"
|
2014-07-31 20:13:13 +02:00
|
|
|
#include "horzcollisionbar.hpp"
|
|
|
|
#include "line.hpp"
|
2016-11-02 18:25:40 +01:00
|
|
|
#include "vectypes.hpp"
|
2014-08-13 22:45:37 +02:00
|
|
|
#include "collisionbarset.hpp"
|
2016-11-02 18:25:40 +01:00
|
|
|
#include "vectorwrapper/vectorops.hpp"
|
2014-07-31 20:13:13 +02:00
|
|
|
#include "vectormath.hpp"
|
2014-07-28 11:00:55 +02:00
|
|
|
#include <vector>
|
|
|
|
#include <ciso646>
|
|
|
|
#include <cassert>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#if defined(WITH_VERBOSE_COLLIDER) && !defined(NDEBUG)
|
|
|
|
#define VERBOSE_COLLIDER
|
|
|
|
#include <iostream>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace cloonel {
|
|
|
|
namespace {
|
2014-07-31 20:13:13 +02:00
|
|
|
typedef std::vector<const CollisionBar*> CollisionBarListType;
|
|
|
|
typedef std::vector<std::pair<Collider::GroupIDType, CollisionBarListType>> CollisionBarGroupListType;
|
2014-08-13 22:45:37 +02:00
|
|
|
typedef std::vector<const CollisionBarSet*> CollisionBarSetListType;
|
|
|
|
typedef std::vector<std::pair<Collider::GroupIDType, CollisionBarSetListType>> CollisionBarSetsListType;
|
|
|
|
|
|
|
|
const CollisionBarListType g_emptyBars;
|
|
|
|
const CollisionBarSetListType g_emptySets;
|
2014-07-31 20:13:13 +02:00
|
|
|
|
|
|
|
///----------------------------------------------------------------------
|
|
|
|
///----------------------------------------------------------------------
|
|
|
|
const CollisionBarListType& findGroup (const CollisionBarGroupListType& parList, Collider::GroupIDType parID) {
|
|
|
|
for (const auto& itm : parList) {
|
|
|
|
if (itm.first == parID) {
|
|
|
|
return itm.second;
|
|
|
|
}
|
|
|
|
}
|
2014-08-13 22:45:37 +02:00
|
|
|
return g_emptyBars;
|
|
|
|
}
|
|
|
|
|
2014-08-14 12:09:44 +02:00
|
|
|
#if !defined(NDEBUG)
|
2014-08-13 22:45:37 +02:00
|
|
|
///----------------------------------------------------------------------
|
|
|
|
///----------------------------------------------------------------------
|
|
|
|
const CollisionBarSetListType& findGroup (const CollisionBarSetsListType& parList, Collider::GroupIDType parID) {
|
|
|
|
for (const auto& itm : parList) {
|
|
|
|
if (itm.first == parID) {
|
|
|
|
return itm.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return g_emptySets;
|
2014-07-31 20:13:13 +02:00
|
|
|
}
|
2014-08-14 12:09:44 +02:00
|
|
|
#endif
|
2014-07-31 20:13:13 +02:00
|
|
|
|
|
|
|
#if !defined(NDEBUG)
|
|
|
|
///----------------------------------------------------------------------
|
|
|
|
///----------------------------------------------------------------------
|
|
|
|
bool isGroupRegistered (const CollisionBarGroupListType& parList, Collider::GroupIDType parID) {
|
|
|
|
const CollisionBarListType& result = findGroup(parList, parID);
|
2014-08-13 22:45:37 +02:00
|
|
|
return &g_emptyBars != &result;
|
|
|
|
}
|
2014-08-14 12:09:44 +02:00
|
|
|
#endif
|
2014-08-13 22:45:37 +02:00
|
|
|
|
2014-08-14 12:09:44 +02:00
|
|
|
#if !defined(NDEBUG)
|
2014-08-13 22:45:37 +02:00
|
|
|
///----------------------------------------------------------------------
|
|
|
|
///----------------------------------------------------------------------
|
|
|
|
bool isGroupRegistered (const CollisionBarSetsListType& parList, Collider::GroupIDType parID) {
|
|
|
|
const CollisionBarSetListType& result = findGroup(parList, parID);
|
|
|
|
return &g_emptySets != &result;
|
2014-07-31 20:13:13 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
///----------------------------------------------------------------------
|
|
|
|
///----------------------------------------------------------------------
|
2014-08-13 22:45:37 +02:00
|
|
|
template <typename L>
|
|
|
|
typename L::value_type::second_type& findOrAddGroup (L& parList, Collider::GroupIDType parID) {
|
2014-07-31 20:13:13 +02:00
|
|
|
for (auto& itm : parList) {
|
|
|
|
if (itm.first == parID) {
|
|
|
|
return itm.second;
|
|
|
|
}
|
|
|
|
}
|
2014-08-13 22:45:37 +02:00
|
|
|
parList.push_back(std::make_pair(parID, typename L::value_type::second_type()));
|
2014-07-31 20:13:13 +02:00
|
|
|
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)
|
2014-08-01 00:50:49 +02:00
|
|
|
std::cout << "Collider: Collision ";
|
2014-07-31 20:13:13 +02:00
|
|
|
std::cout << "between " << bar1 << " and " << bar2 << "\n";
|
|
|
|
#endif
|
2014-08-03 15:13:54 +02:00
|
|
|
const auto& offs1 = bar1->GetOffset();
|
|
|
|
const auto& offs2 = bar2->GetOffset();
|
|
|
|
float2 dir1, dir2;
|
|
|
|
if (offs1 == float2(0.0f) and offs2 == float2(0.0f)) {
|
|
|
|
dir1 = dir2 = float2(0.0f);
|
|
|
|
}
|
|
|
|
else if (offs1 == float2(0.0f)) {
|
|
|
|
dir2 = normalized(offs2);
|
|
|
|
dir1 = -1.0f * dir2;
|
|
|
|
}
|
|
|
|
else if (offs2 == float2(0.0f)) {
|
|
|
|
dir1 = normalized(offs1);
|
|
|
|
dir2 = -1.0f * dir1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dir1 = normalized(offs1);
|
|
|
|
dir2 = normalized(offs2);
|
|
|
|
}
|
2014-07-31 20:13:13 +02:00
|
|
|
bar1->InvokeCallback(overlap, dir1);
|
|
|
|
bar2->InvokeCallback(overlap, dir2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-28 11:00:55 +02:00
|
|
|
} //unnamed namespace
|
|
|
|
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
Collider::Collider() {
|
|
|
|
}
|
|
|
|
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
Collider::~Collider() noexcept {
|
|
|
|
}
|
|
|
|
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
///--------------------------------------------------------------------------
|
2014-07-31 20:13:13 +02:00
|
|
|
void Collider::RunCollisionTests (float parDeltaT) const {
|
2014-08-13 22:45:37 +02:00
|
|
|
CollisionBarGroupListType collectedGroups;
|
|
|
|
//For each CollisionBarSet list+ID
|
|
|
|
for (const auto& set : m_collisionBarSets) {
|
|
|
|
//Get or make a list for the currend ID
|
|
|
|
CollisionBarListType& newList = findOrAddGroup(collectedGroups, set.first);
|
|
|
|
//For each CollisionBarSet with the current ID
|
|
|
|
for (auto setObject : set.second) {
|
|
|
|
#if !defined(NDEBUG)
|
|
|
|
const size_t oldListSize = newList.size();
|
|
|
|
const CollisionBar* const lastCollisionBar = (oldListSize == 0 ? nullptr : newList.back());
|
|
|
|
#endif
|
|
|
|
//Get the collision bars in the current list
|
|
|
|
setObject->CopyBars(newList);
|
|
|
|
|
|
|
|
//Make sure the CollisionBarSet didn't tamper with elements already in the list
|
|
|
|
assert(oldListSize <= newList.size());
|
|
|
|
assert(0 == oldListSize or newList[oldListSize - 1] == lastCollisionBar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-31 20:13:13 +02:00
|
|
|
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));
|
2014-08-13 22:45:37 +02:00
|
|
|
const CollisionBarListType& group1a = findGroup(collectedGroups, relationship.first);
|
|
|
|
const CollisionBarListType& group2a = (relationship.first == relationship.second ? group1a : findGroup(collectedGroups, relationship.second));
|
2014-07-31 20:13:13 +02:00
|
|
|
|
|
|
|
collide(parDeltaT, group1, group2);
|
2014-08-13 22:45:37 +02:00
|
|
|
collide(parDeltaT, group1, group2a);
|
|
|
|
collide(parDeltaT, group1a, group2);
|
|
|
|
collide(parDeltaT, group1a, group2a);
|
2014-07-31 20:13:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
void Collider::TieGroups (GroupIDType parGroup1, GroupIDType parGroup2) {
|
2014-08-01 00:50:49 +02:00
|
|
|
#if defined(VERBOSE_COLLIDER)
|
|
|
|
std::cout << "Collider: Tying group " << parGroup1 << " to " << parGroup2 << " for collision tests\n";
|
|
|
|
#endif
|
2014-07-31 20:13:13 +02:00
|
|
|
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)));
|
2014-08-13 22:45:37 +02:00
|
|
|
assert(isGroupRegistered(m_collisionBars, parGroup1) or isGroupRegistered(m_collisionBarSets, parGroup1));
|
|
|
|
assert(isGroupRegistered(m_collisionBars, parGroup2) or isGroupRegistered(m_collisionBarSets, parGroup2));
|
2014-07-31 20:13:13 +02:00
|
|
|
m_relationships.push_back(std::make_pair(parGroup1, parGroup2));
|
|
|
|
}
|
|
|
|
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
void Collider::RegisterBar (GroupIDType parGroup, const CollisionBar* parBar) {
|
2014-08-01 00:50:49 +02:00
|
|
|
#if defined(VERBOSE_COLLIDER)
|
|
|
|
std::cout << "Collider: Registering bar " << parBar << " in group " << parGroup << "\n";
|
|
|
|
#endif
|
2014-07-31 20:13:13 +02:00
|
|
|
CollisionBarListType& group = findOrAddGroup(m_collisionBars, parGroup);
|
|
|
|
assert(isGroupRegistered(m_collisionBars, parGroup));
|
|
|
|
assert(parBar);
|
|
|
|
group.push_back(parBar);
|
2014-07-28 11:00:55 +02:00
|
|
|
}
|
2014-08-01 00:50:49 +02:00
|
|
|
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
void Collider::UnregisterBar (GroupIDType parGroup, const CollisionBar* parBar) {
|
|
|
|
assert(isGroupRegistered(m_collisionBars, parGroup));
|
|
|
|
CollisionBarListType& group = findOrAddGroup(m_collisionBars, parGroup);
|
|
|
|
auto itdele = std::find(group.begin(), group.end(), parBar);
|
|
|
|
assert(itdele != group.end());
|
|
|
|
group.erase(itdele);
|
|
|
|
}
|
|
|
|
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
void Collider::Reset() noexcept {
|
|
|
|
m_relationships.clear();
|
|
|
|
m_collisionBars.clear();
|
2014-08-13 22:45:37 +02:00
|
|
|
m_collisionBarSets.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
void Collider::RegisterBarSet (GroupIDType parGroup, const CollisionBarSet* parSet) {
|
|
|
|
#if defined(VERBOSE_COLLIDER)
|
|
|
|
std::cout << "Collider: Registering bar set " << parSet << " in group " << parGroup << "\n";
|
|
|
|
#endif
|
|
|
|
CollisionBarSetListType& group = findOrAddGroup(m_collisionBarSets, parGroup);
|
|
|
|
assert(isGroupRegistered(m_collisionBarSets, parGroup));
|
|
|
|
assert(parSet);
|
|
|
|
group.push_back(parSet);
|
|
|
|
}
|
|
|
|
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
///--------------------------------------------------------------------------
|
|
|
|
void Collider::UnregisterBarSet (GroupIDType parGroup, const CollisionBarSet* parSet) {
|
|
|
|
assert(isGroupRegistered(m_collisionBarSets, parGroup));
|
|
|
|
CollisionBarSetListType& group = findOrAddGroup(m_collisionBarSets, parGroup);
|
|
|
|
auto itdele = std::find(group.begin(), group.end(), parSet);
|
|
|
|
assert(itdele != group.end());
|
|
|
|
group.erase(itdele);
|
2014-08-01 00:50:49 +02:00
|
|
|
}
|
2014-07-28 11:00:55 +02:00
|
|
|
} //namespace cloonel
|
|
|
|
|
|
|
|
#if defined(VERBOSE_COLLIDER)
|
|
|
|
#undef VERBOSE_COLLIDER
|
|
|
|
#endif
|