mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 08:49:05 +02:00
physics collisions emit script collision events
This commit is contained in:
parent
790d07d346
commit
86583f3f3f
13 changed files with 119 additions and 53 deletions
|
@ -192,7 +192,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
_justStarted(true),
|
_justStarted(true),
|
||||||
_physicsEngine(glm::vec3(0.0f)),
|
_physicsEngine(glm::vec3(0.0f)),
|
||||||
_entities(true, this, this),
|
_entities(true, this, this),
|
||||||
_entityCollisionSystem(),
|
|
||||||
_entityClipboardRenderer(false, this, this),
|
_entityClipboardRenderer(false, this, this),
|
||||||
_entityClipboard(),
|
_entityClipboard(),
|
||||||
_viewFrustum(),
|
_viewFrustum(),
|
||||||
|
@ -1689,17 +1688,16 @@ void Application::init() {
|
||||||
_entities.init();
|
_entities.init();
|
||||||
_entities.setViewFrustum(getViewFrustum());
|
_entities.setViewFrustum(getViewFrustum());
|
||||||
|
|
||||||
EntityTree* entityTree = _entities.getTree();
|
EntityTree* tree = _entities.getTree();
|
||||||
|
_physicsEngine.setEntityTree(tree);
|
||||||
_entityCollisionSystem.init(&_entityEditSender, entityTree, &_avatarManager);
|
tree->setSimulation(&_physicsEngine);
|
||||||
|
_physicsEngine.init(&_entityEditSender);
|
||||||
entityTree->setSimulation(&_entityCollisionSystem);
|
|
||||||
|
|
||||||
connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithEntity,
|
connect(&_physicsEngine, &EntitySimulation::emitEntityCollisionWithEntity,
|
||||||
ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithEntity);
|
ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithEntity);
|
||||||
|
|
||||||
// connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts
|
// connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts
|
||||||
connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithEntity,
|
connect(&_physicsEngine, &EntitySimulation::emitEntityCollisionWithEntity,
|
||||||
&_entities, &EntityTreeRenderer::entityCollisionWithEntity);
|
&_entities, &EntityTreeRenderer::entityCollisionWithEntity);
|
||||||
|
|
||||||
// connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing
|
// connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing
|
||||||
|
@ -1723,10 +1721,6 @@ void Application::init() {
|
||||||
// save settings when avatar changes
|
// save settings when avatar changes
|
||||||
connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::bumpSettings);
|
connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::bumpSettings);
|
||||||
|
|
||||||
EntityTree* tree = _entities.getTree();
|
|
||||||
_physicsEngine.setEntityTree(tree);
|
|
||||||
tree->setSimulation(&_physicsEngine);
|
|
||||||
_physicsEngine.init(&_entityEditSender);
|
|
||||||
// make sure our texture cache knows about window size changes
|
// make sure our texture cache knows about window size changes
|
||||||
DependencyManager::get<TextureCache>()->associateWithWidget(glCanvas.data());
|
DependencyManager::get<TextureCache>()->associateWithWidget(glCanvas.data());
|
||||||
|
|
||||||
|
@ -2047,9 +2041,6 @@ void Application::update(float deltaTime) {
|
||||||
// NOTE: the _entities.update() call below will wait for lock
|
// NOTE: the _entities.update() call below will wait for lock
|
||||||
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
|
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
|
||||||
_entities.update(); // update the models...
|
_entities.update(); // update the models...
|
||||||
// The _entityCollisionSystem.updateCollisions() call below merely tries for lock,
|
|
||||||
// and on failure it skips collision detection.
|
|
||||||
_entityCollisionSystem.updateCollisions(); // collide the entities...
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -466,7 +466,6 @@ private:
|
||||||
PhysicsEngine _physicsEngine;
|
PhysicsEngine _physicsEngine;
|
||||||
|
|
||||||
EntityTreeRenderer _entities;
|
EntityTreeRenderer _entities;
|
||||||
EntityCollisionSystem _entityCollisionSystem;
|
|
||||||
EntityTreeRenderer _entityClipboardRenderer;
|
EntityTreeRenderer _entityClipboardRenderer;
|
||||||
EntityTree _entityClipboard;
|
EntityTree _entityClipboard;
|
||||||
|
|
||||||
|
|
|
@ -62,14 +62,6 @@ void EntityCollisionSystem::checkEntity(EntityItem* entity) {
|
||||||
updateCollisionWithAvatars(entity);
|
updateCollisionWithAvatars(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityCollisionSystem::emitGlobalEntityCollisionWithEntity(EntityItem* entityA,
|
|
||||||
EntityItem* entityB, const Collision& collision) {
|
|
||||||
|
|
||||||
EntityItemID idA = entityA->getEntityItemID();
|
|
||||||
EntityItemID idB = entityB->getEntityItemID();
|
|
||||||
emit entityCollisionWithEntity(idA, idB, collision);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) {
|
void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) {
|
||||||
|
|
||||||
if (entityA->getIgnoreForCollisions()) {
|
if (entityA->getIgnoreForCollisions()) {
|
||||||
|
@ -193,7 +185,10 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) {
|
||||||
Collision collision;
|
Collision collision;
|
||||||
collision.penetration = penetration;
|
collision.penetration = penetration;
|
||||||
collision.contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition());
|
collision.contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition());
|
||||||
emitGlobalEntityCollisionWithEntity(entityA, entityB, collision);
|
|
||||||
|
EntityItemID idA = entityA->getEntityItemID();
|
||||||
|
EntityItemID idB = entityB->getEntityItemID();
|
||||||
|
emitEntityCollisionWithEntity(idA, idB, collision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,7 @@ class AvatarData;
|
||||||
class EntityEditPacketSender;
|
class EntityEditPacketSender;
|
||||||
class EntityTree;
|
class EntityTree;
|
||||||
|
|
||||||
class EntityCollisionSystem : public QObject, public SimpleEntitySimulation {
|
class EntityCollisionSystem : public SimpleEntitySimulation {
|
||||||
Q_OBJECT
|
|
||||||
public:
|
public:
|
||||||
EntityCollisionSystem();
|
EntityCollisionSystem();
|
||||||
|
|
||||||
|
@ -45,19 +44,13 @@ public:
|
||||||
void checkEntity(EntityItem* Entity);
|
void checkEntity(EntityItem* Entity);
|
||||||
void updateCollisionWithEntities(EntityItem* Entity);
|
void updateCollisionWithEntities(EntityItem* Entity);
|
||||||
void updateCollisionWithAvatars(EntityItem* Entity);
|
void updateCollisionWithAvatars(EntityItem* Entity);
|
||||||
void queueEntityPropertiesUpdate(EntityItem* Entity);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo);
|
void applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo);
|
||||||
|
|
||||||
static bool updateOperation(OctreeElement* element, void* extraData);
|
static bool updateOperation(OctreeElement* element, void* extraData);
|
||||||
void emitGlobalEntityCollisionWithEntity(EntityItem* entityA, EntityItem* entityB, const Collision& penetration);
|
|
||||||
|
|
||||||
EntityEditPacketSender* _packetSender;
|
EntityEditPacketSender* _packetSender;
|
||||||
AbstractAudioInterface* _audio;
|
|
||||||
AvatarHashMap* _avatars;
|
AvatarHashMap* _avatars;
|
||||||
CollisionList _collisions;
|
CollisionList _collisions;
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#ifndef hifi_EntitySimulation_h
|
#ifndef hifi_EntitySimulation_h
|
||||||
#define hifi_EntitySimulation_h
|
#define hifi_EntitySimulation_h
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
@ -31,7 +32,8 @@ const int DIRTY_SIMULATION_FLAGS =
|
||||||
EntityItem::DIRTY_LIFETIME |
|
EntityItem::DIRTY_LIFETIME |
|
||||||
EntityItem::DIRTY_UPDATEABLE;
|
EntityItem::DIRTY_UPDATEABLE;
|
||||||
|
|
||||||
class EntitySimulation {
|
class EntitySimulation : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
EntitySimulation() : _mutex(QMutex::Recursive), _entityTree(NULL) { }
|
EntitySimulation() : _mutex(QMutex::Recursive), _entityTree(NULL) { }
|
||||||
virtual ~EntitySimulation() { setEntityTree(NULL); }
|
virtual ~EntitySimulation() { setEntityTree(NULL); }
|
||||||
|
@ -61,6 +63,9 @@ public:
|
||||||
|
|
||||||
EntityTree* getEntityTree() { return _entityTree; }
|
EntityTree* getEntityTree() { return _entityTree; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void emitEntityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// These pure virtual methods are protected because they are not to be called will-nilly. The base class
|
// These pure virtual methods are protected because they are not to be called will-nilly. The base class
|
||||||
|
|
29
libraries/physics/src/ContactInfo.cpp
Normal file
29
libraries/physics/src/ContactInfo.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
// ContactEvent.cpp
|
||||||
|
// libraries/physcis/src
|
||||||
|
//
|
||||||
|
// Created by Andrew Meadows 2015.01.20
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "BulletUtil.h"
|
||||||
|
#include "ContactInfo.h"
|
||||||
|
|
||||||
|
void ContactInfo::update(uint32_t currentStep, btManifoldPoint& p, const glm::vec3& worldOffset) {
|
||||||
|
_lastStep = currentStep;
|
||||||
|
++_numSteps;
|
||||||
|
contactPoint = bulletToGLM(p.m_positionWorldOnB) + worldOffset;
|
||||||
|
penetration = bulletToGLM(p.m_distance1 * p.m_normalWorldOnB);
|
||||||
|
// TODO: also report normal
|
||||||
|
//_normal = bulletToGLM(p.m_normalWorldOnB);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactEventType ContactInfo::computeType(uint32_t thisStep) {
|
||||||
|
if (_lastStep != thisStep) {
|
||||||
|
return CONTACT_EVENT_TYPE_END;
|
||||||
|
}
|
||||||
|
return (_numSteps == 1) ? CONTACT_EVENT_TYPE_START : CONTACT_EVENT_TYPE_CONTINUE;
|
||||||
|
}
|
37
libraries/physics/src/ContactInfo.h
Normal file
37
libraries/physics/src/ContactInfo.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
//
|
||||||
|
// ContactEvent.h
|
||||||
|
// libraries/physcis/src
|
||||||
|
//
|
||||||
|
// Created by Andrew Meadows 2015.01.20
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_ContactEvent_h
|
||||||
|
#define hifi_ContactEvent_h
|
||||||
|
|
||||||
|
#include <btBulletDynamicsCommon.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include "RegisteredMetaTypes.h"
|
||||||
|
|
||||||
|
enum ContactEventType {
|
||||||
|
CONTACT_EVENT_TYPE_START,
|
||||||
|
CONTACT_EVENT_TYPE_CONTINUE,
|
||||||
|
CONTACT_EVENT_TYPE_END
|
||||||
|
};
|
||||||
|
|
||||||
|
class ContactInfo : public Collision
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void update(uint32_t currentStep, btManifoldPoint& p, const glm::vec3& worldOffset);
|
||||||
|
ContactEventType computeType(uint32_t thisStep);
|
||||||
|
private:
|
||||||
|
uint32_t _lastStep = 0;
|
||||||
|
uint32_t _numSteps = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // hifi_ContactEvent_h
|
|
@ -33,6 +33,7 @@ void EntityMotionState::enqueueOutgoingEntity(EntityItem* entity) {
|
||||||
|
|
||||||
EntityMotionState::EntityMotionState(EntityItem* entity)
|
EntityMotionState::EntityMotionState(EntityItem* entity)
|
||||||
: _entity(entity) {
|
: _entity(entity) {
|
||||||
|
_type = MOTION_STATE_TYPE_ENTITY;
|
||||||
assert(entity != NULL);
|
assert(entity != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,8 @@ public:
|
||||||
uint32_t getIncomingDirtyFlags() const;
|
uint32_t getIncomingDirtyFlags() const;
|
||||||
void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); }
|
void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); }
|
||||||
|
|
||||||
|
EntityItem* getEntity() const { return _entity; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
EntityItem* _entity;
|
EntityItem* _entity;
|
||||||
};
|
};
|
||||||
|
|
|
@ -171,14 +171,6 @@ void ObjectMotionState::removeKinematicController() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectMotionState::handleContactEvent(ContactEventType type, ObjectMotionState* otherState) {
|
|
||||||
if (type == CONTACT_TYPE_START) {
|
|
||||||
std::cout << "adebug start " << (void*)(this) << " vs " << (void*)(otherState) << std::endl; // adebug
|
|
||||||
} else if (type == CONTACT_TYPE_END) {
|
|
||||||
std::cout << "adebug end " << (void*)(this) << " vs " << (void*)(otherState) << std::endl; // adebug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectMotionState::setRigidBody(btRigidBody* body) {
|
void ObjectMotionState::setRigidBody(btRigidBody* body) {
|
||||||
// give the body a (void*) back-pointer to this ObjectMotionState
|
// give the body a (void*) back-pointer to this ObjectMotionState
|
||||||
if (_body != body) {
|
if (_body != body) {
|
||||||
|
|
|
@ -26,6 +26,12 @@ enum MotionType {
|
||||||
MOTION_TYPE_KINEMATIC // keyframed motion
|
MOTION_TYPE_KINEMATIC // keyframed motion
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum MotionStateType {
|
||||||
|
MOTION_STATE_TYPE_UNKNOWN,
|
||||||
|
MOTION_STATE_TYPE_ENTITY,
|
||||||
|
MOTION_STATE_TYPE_AVATAR
|
||||||
|
};
|
||||||
|
|
||||||
// The update flags trigger two varieties of updates: "hard" which require the body to be pulled
|
// The update flags trigger two varieties of updates: "hard" which require the body to be pulled
|
||||||
// and re-added to the physics engine and "easy" which just updates the body properties.
|
// and re-added to the physics engine and "easy" which just updates the body properties.
|
||||||
const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE);
|
const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE);
|
||||||
|
@ -59,6 +65,7 @@ public:
|
||||||
virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0;
|
virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0;
|
||||||
virtual void updateObjectVelocities() = 0;
|
virtual void updateObjectVelocities() = 0;
|
||||||
|
|
||||||
|
MotionStateType getType() const { return _type; }
|
||||||
virtual MotionType getMotionType() const { return _motionType; }
|
virtual MotionType getMotionType() const { return _motionType; }
|
||||||
|
|
||||||
virtual void computeShapeInfo(ShapeInfo& info) = 0;
|
virtual void computeShapeInfo(ShapeInfo& info) = 0;
|
||||||
|
@ -89,14 +96,14 @@ public:
|
||||||
virtual void addKinematicController() = 0;
|
virtual void addKinematicController() = 0;
|
||||||
virtual void removeKinematicController();
|
virtual void removeKinematicController();
|
||||||
|
|
||||||
virtual void handleContactEvent(ContactEventType type, ObjectMotionState* otherState);
|
|
||||||
|
|
||||||
btRigidBody* getRigidBody() const { return _body; }
|
btRigidBody* getRigidBody() const { return _body; }
|
||||||
|
|
||||||
friend class PhysicsEngine;
|
friend class PhysicsEngine;
|
||||||
protected:
|
protected:
|
||||||
void setRigidBody(btRigidBody* body);
|
void setRigidBody(btRigidBody* body);
|
||||||
|
|
||||||
|
MotionStateType _type = MOTION_STATE_TYPE_UNKNOWN;
|
||||||
|
|
||||||
// TODO: move these materials properties outside of ObjectMotionState
|
// TODO: move these materials properties outside of ObjectMotionState
|
||||||
float _friction;
|
float _friction;
|
||||||
float _restitution;
|
float _restitution;
|
||||||
|
|
|
@ -256,8 +256,9 @@ void PhysicsEngine::computeCollisionEvents() {
|
||||||
|
|
||||||
void* a = objectA->getUserPointer();
|
void* a = objectA->getUserPointer();
|
||||||
void* b = objectB->getUserPointer();
|
void* b = objectB->getUserPointer();
|
||||||
if (a || b ) {
|
if (a || b) {
|
||||||
_contactMap[ContactKey(a, b)].update(_numSubsteps);
|
// the manifold has up to 4 distinct points, but only extract info from the first
|
||||||
|
_contactMap[ContactKey(a, b)].update(_numSubsteps, contactManifold->getContactPoint(0), _originOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,16 +266,28 @@ void PhysicsEngine::computeCollisionEvents() {
|
||||||
// scan known contacts and trigger events
|
// scan known contacts and trigger events
|
||||||
ContactMap::iterator contactItr = _contactMap.begin();
|
ContactMap::iterator contactItr = _contactMap.begin();
|
||||||
while (contactItr != _contactMap.end()) {
|
while (contactItr != _contactMap.end()) {
|
||||||
ContactEventType type = contactItr->second.computeType(_numSubsteps);
|
|
||||||
ObjectMotionState* A = static_cast<ObjectMotionState*>(contactItr->first._a);
|
ObjectMotionState* A = static_cast<ObjectMotionState*>(contactItr->first._a);
|
||||||
ObjectMotionState* B = static_cast<ObjectMotionState*>(contactItr->first._b);
|
ObjectMotionState* B = static_cast<ObjectMotionState*>(contactItr->first._b);
|
||||||
if (A) {
|
|
||||||
A->handleContactEvent(type, B);
|
// TODO: make triggering these events clean and efficient. The code at this context shouldn't
|
||||||
|
// have to figure out what kind of object (entity, avatar, etc) these are in order to properly
|
||||||
|
// emit a collision event.
|
||||||
|
if (A && A->getType() == MOTION_STATE_TYPE_ENTITY) {
|
||||||
|
EntityItemID idA = static_cast<EntityMotionState*>(A)->getEntity()->getEntityItemID();
|
||||||
|
EntityItemID idB;
|
||||||
|
if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) {
|
||||||
|
idB = static_cast<EntityMotionState*>(B)->getEntity()->getEntityItemID();
|
||||||
|
}
|
||||||
|
emitEntityCollisionWithEntity(idA, idB, contactItr->second);
|
||||||
|
} else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) {
|
||||||
|
EntityItemID idA;
|
||||||
|
EntityItemID idB = static_cast<EntityMotionState*>(B)->getEntity()->getEntityItemID();
|
||||||
|
emitEntityCollisionWithEntity(idA, idB, contactItr->second);
|
||||||
}
|
}
|
||||||
if (B) {
|
|
||||||
B->handleContactEvent(type, A);
|
// TODO: enable scripts to filter based on contact event type
|
||||||
}
|
ContactEventType type = contactItr->second.computeType(_numSubsteps);
|
||||||
if (type == CONTACT_TYPE_END) {
|
if (type == CONTACT_EVENT_TYPE_END) {
|
||||||
ContactMap::iterator iterToDelete = contactItr;
|
ContactMap::iterator iterToDelete = contactItr;
|
||||||
++contactItr;
|
++contactItr;
|
||||||
_contactMap.erase(iterToDelete);
|
_contactMap.erase(iterToDelete);
|
||||||
|
|
|
@ -38,11 +38,13 @@ public:
|
||||||
ContactKey() = delete;
|
ContactKey() = delete;
|
||||||
ContactKey(void* a, void* b) : _a(a), _b(b) {}
|
ContactKey(void* a, void* b) : _a(a), _b(b) {}
|
||||||
bool operator<(const ContactKey& other) const { return _a < other._a || (_a == other._a && _b < other._b); }
|
bool operator<(const ContactKey& other) const { return _a < other._a || (_a == other._a && _b < other._b); }
|
||||||
|
bool operator==(const ContactKey& other) const { return _a == other._a && _b == other._b; }
|
||||||
void* _a;
|
void* _a;
|
||||||
void* _b;
|
void* _b;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<ContactKey, ContactInfo> ContactMap;
|
typedef std::map<ContactKey, ContactInfo> ContactMap;
|
||||||
|
typedef std::pair<ContactKey, ContactInfo> ContactMapElement;
|
||||||
|
|
||||||
class PhysicsEngine : public EntitySimulation {
|
class PhysicsEngine : public EntitySimulation {
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in a new issue