C++程序  |  130行  |  3.93 KB

#include "ContactCache.h"

ContactCache *currentContactCache = 0;

inline void ContactCacheStarted_CB(btPersistentManifold* const &manifold) {
	currentContactCache->contactStarted(manifold);
}
inline void ContactCacheEnded_CB(btPersistentManifold* const &manifold) {
	currentContactCache->contactEnded(manifold);
}

struct ContactPair {
	const btCollisionObject *object0;
	const btCollisionObject *object1;
	float time;

	ContactPair() : object0(0), object1(0), time(0) {}

	ContactPair(const ContactPair &rhs) : object0(rhs.object0), object1(rhs.object1), time(rhs.time) {}

	ContactPair(const btCollisionObject* const &object0, const btCollisionObject* const &object1, const float &time) : object0(object0), object1(object1), time(time) {}

	ContactPair &operator=(const ContactPair &rhs) {
		object0 = rhs.object0;
		object1 = rhs.object1;
		time = rhs.time;
		return *this;
	}

	inline bool operator==(const ContactPair &rhs) const {
		return ((rhs.object0 == object0) && (rhs.object1 == object1)) || ((rhs.object0 == object1) && (rhs.object1 == object0));
	}

	inline bool operator<(const ContactPair &rhs) const {
		if (*this == rhs)
			return false;
		return object0 < rhs.object0;
	}

	inline bool equals(const btCollisionObject* const &obj0, const btCollisionObject* const &obj1) const {
		return ((obj0 == object0) && (obj1 == object1)) || ((obj0 == object1) && (obj1 == object0));
	}
};

ContactCache::ContactCache(bool dummy)
	: events(0), cacheTime(0.2f), filter(true) {}

ContactCache::~ContactCache() {
	disable();
}

void ContactCache::setEvents(const int &events) {
	this->events = events;
}

void ContactCache::enable() {
	currentContactCache = this;
	gContactStartedCallback = ContactCacheStarted_CB;
	gContactEndedCallback = ContactCacheEnded_CB;
}

void ContactCache::disable() {
	if (currentContactCache == this) {
		currentContactCache = 0;
		if (gContactStartedCallback == ContactCacheStarted_CB)
			gContactStartedCallback = 0;
		if (gContactEndedCallback == ContactCacheEnded_CB)
			gContactEndedCallback = 0;
	}
}

bool ContactCache::isEnabled() {
	return (currentContactCache == this) && (gContactStartedCallback == ContactCacheStarted_CB) && (gContactEndedCallback == ContactCacheEnded_CB);
}

void ContactCache::clear() {
	cache.clear();
}

void ContactCache::update(float delta) {
	for (int i = cache.size() - 1; i >= 0; --i) {
		ContactPair &pair = cache.at(i);
		if ((pair.time -= delta) < 0) {
			const btCollisionObject* const &object0 = pair.object0;
			const btCollisionObject* const &object1 = pair.object1;
			const bool match0 = gdxCheckFilter(object0, object1);
			const bool match1 = gdxCheckFilter(object1, object0);
			if (!filter || match0 || match1)
				onContactEnded(object0, match0, object1, match1);
			cache.swap(i, cache.size()-1);
			cache.pop_back();
		}
	}
}

int ContactCache::indexOf(const btCollisionObject* const &obj0, const btCollisionObject* const &obj1) {
	for (int i = cache.size() - 1; i >= 0; --i) {
		ContactPair &pair = cache.at(i);
		if (pair.equals(obj0, obj1))
			return i;
	}
	return -1;
}

void ContactCache::contactStarted(btPersistentManifold* manifold) {
	const bool match0 = gdxCheckFilter(manifold->getBody0(), manifold->getBody1());
	const bool match1 = gdxCheckFilter(manifold->getBody1(), manifold->getBody0());
	if (filter && !match0 && !match1)
		return;
	const int idx = indexOf(manifold->getBody0(), manifold->getBody1());
	if (idx >= 0) {
		cache.swap(idx, cache.size()-1);
		cache.pop_back();
	}
	else
		onContactStarted(manifold, match0, match1);
}

void ContactCache::contactEnded(btPersistentManifold* manifold) {
	const bool match0 = gdxCheckFilter(manifold->getBody0(), manifold->getBody1());
	const bool match1 = gdxCheckFilter(manifold->getBody1(), manifold->getBody0());
	if (filter && !match0 && !match1)
		return;
	const int idx = indexOf(manifold->getBody0(), manifold->getBody1());
	if (idx >= 0)
		cache[idx].time = cacheTime;
	else
		cache.push_back(ContactPair(manifold->getBody0(), manifold->getBody1(), cacheTime));
}