make main ragdoll and entity special

also addded some logic (unused) to add ragdolls of other avatars
This commit is contained in:
Andrew Meadows 2014-08-06 10:43:56 -07:00
parent a1fccdb177
commit cb8c0792b2
3 changed files with 121 additions and 84 deletions

View file

@ -85,12 +85,12 @@ MyAvatar::MyAvatar() :
_skeletonModel.setEnableShapes(true); _skeletonModel.setEnableShapes(true);
// The skeleton is both a PhysicsEntity and Ragdoll, so we add it to the simulation once for each type. // The skeleton is both a PhysicsEntity and Ragdoll, so we add it to the simulation once for each type.
_physicsSimulation.addEntity(&_skeletonModel); _physicsSimulation.addEntity(&_skeletonModel);
_physicsSimulation.addRagdoll(&_skeletonModel); _physicsSimulation.setRagdoll(&_skeletonModel);
} }
MyAvatar::~MyAvatar() { MyAvatar::~MyAvatar() {
_physicsSimulation.setRagdoll(NULL);
_physicsSimulation.removeEntity(&_skeletonModel); _physicsSimulation.removeEntity(&_skeletonModel);
_physicsSimulation.removeRagdoll(&_skeletonModel);
_lookAtTargetAvatar.clear(); _lookAtTargetAvatar.clear();
} }
@ -1532,7 +1532,31 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
} }
float myBoundingRadius = getBoundingRadius(); float myBoundingRadius = getBoundingRadius();
const float BODY_COLLISION_RESOLUTION_FACTOR = glm::max(1.0f, deltaTime / BODY_COLLISION_RESOLUTION_TIMESCALE); // find nearest avatar
float nearestDistance2 = std::numeric_limits<float>::max();
Avatar* nearestAvatar = NULL;
foreach (const AvatarSharedPointer& avatarPointer, avatars) {
Avatar* avatar = static_cast<Avatar*>(avatarPointer.data());
if (static_cast<Avatar*>(this) == avatar) {
// don't collide with ourselves
continue;
}
float distance2 = glm::distance2(_position, avatar->getPosition());
if (nearestDistance2 > distance2) {
nearestDistance2 = distance2;
nearestAvatar = avatar;
}
}
_distanceToNearestAvatar = glm::sqrt(nearestDistance2);
if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) {
if (nearestAvatar != NULL) {
if (_distanceToNearestAvatar > myBoundingRadius + nearestAvatar->getBoundingRadius()) {
// they aren't close enough to put into the _physicsSimulation
// so we clear the pointer
nearestAvatar = NULL;
}
}
foreach (const AvatarSharedPointer& avatarPointer, avatars) { foreach (const AvatarSharedPointer& avatarPointer, avatars) {
Avatar* avatar = static_cast<Avatar*>(avatarPointer.data()); Avatar* avatar = static_cast<Avatar*>(avatarPointer.data());
@ -1540,33 +1564,21 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
// don't collide with ourselves // don't collide with ourselves
continue; continue;
} }
float distance = glm::length(_position - avatar->getPosition()); SkeletonModel* skeleton = &(avatar->getSkeletonModel());
if (_distanceToNearestAvatar > distance) { PhysicsSimulation* simulation = skeleton->getSimulation();
_distanceToNearestAvatar = distance; if (avatar == nearestAvatar) {
if (simulation != &(_physicsSimulation)) {
std::cout << "adebug adding other avatar " << avatar << " to simulation" << std::endl; // adebug
skeleton->setEnableShapes(true);
_physicsSimulation.addEntity(skeleton);
_physicsSimulation.addRagdoll(skeleton);
} }
float theirBoundingRadius = avatar->getBoundingRadius(); } else if (simulation == &(_physicsSimulation)) {
if (distance < myBoundingRadius + theirBoundingRadius) { std::cout << "adebug removing other avatar " << avatar << " from simulation" << std::endl; // adebug
// collide our body against theirs _physicsSimulation.removeRagdoll(skeleton);
QVector<const Shape*> myShapes; _physicsSimulation.removeEntity(skeleton);
_skeletonModel.getBodyShapes(myShapes); skeleton->setEnableShapes(false);
QVector<const Shape*> theirShapes;
avatar->getSkeletonModel().getBodyShapes(theirShapes);
CollisionInfo collision;
if (ShapeCollider::collideShapesCoarse(myShapes, theirShapes, collision)) {
float penetrationDepth = glm::length(collision._penetration);
if (penetrationDepth > myBoundingRadius) {
qDebug() << "WARNING: ignoring avatar-avatar penetration depth " << penetrationDepth;
} }
else if (penetrationDepth > EPSILON) {
setPosition(getPosition() - BODY_COLLISION_RESOLUTION_FACTOR * collision._penetration);
_lastBodyPenetration += collision._penetration;
emit collisionWithAvatar(getSessionUUID(), avatar->getSessionUUID(), collision);
}
}
// collide their hands against us
avatar->getHand()->collideAgainstAvatar(this, false);
} }
} }
} }

View file

@ -24,19 +24,37 @@ int MAX_ENTITIES_PER_SIMULATION = 64;
int MAX_COLLISIONS_PER_SIMULATION = 256; int MAX_COLLISIONS_PER_SIMULATION = 256;
PhysicsSimulation::PhysicsSimulation() : _frame(0), _collisions(MAX_COLLISIONS_PER_SIMULATION) { PhysicsSimulation::PhysicsSimulation() : _frame(0), _entity(NULL), _ragdoll(NULL), _collisions(MAX_COLLISIONS_PER_SIMULATION) {
} }
PhysicsSimulation::~PhysicsSimulation() { PhysicsSimulation::~PhysicsSimulation() {
// entities have a backpointer to this simulator that must be cleaned up // entities have a backpointer to this simulator that must be cleaned up
int numEntities = _entities.size(); int numEntities = _otherEntities.size();
for (int i = 0; i < numEntities; ++i) { for (int i = 0; i < numEntities; ++i) {
_entities[i]->_simulation = NULL; _otherEntities[i]->_simulation = NULL;
}
_otherEntities.clear();
if (_entity) {
_entity->_simulation = NULL;
} }
_entities.clear();
// but Ragdolls do not // but Ragdolls do not
_dolls.clear(); _ragdoll = NULL;
_otherRagdolls.clear();
}
void PhysicsSimulation::setEntity(PhysicsEntity* entity) {
if (_entity != entity) {
if (_entity) {
assert(_entity->_simulation == this);
_entity->_simulation = NULL;
}
_entity = entity;
if (_entity) {
assert(!(_entity->_simulation));
_entity->_simulation = this;
}
}
} }
bool PhysicsSimulation::addEntity(PhysicsEntity* entity) { bool PhysicsSimulation::addEntity(PhysicsEntity* entity) {
@ -44,25 +62,24 @@ bool PhysicsSimulation::addEntity(PhysicsEntity* entity) {
return false; return false;
} }
if (entity->_simulation == this) { if (entity->_simulation == this) {
int numEntities = _entities.size(); int numEntities = _otherEntities.size();
for (int i = 0; i < numEntities; ++i) { for (int i = 0; i < numEntities; ++i) {
if (entity == _entities.at(i)) { if (entity == _otherEntities.at(i)) {
// already in list // already in list
assert(entity->_simulation == this);
return true; return true;
} }
} }
// belongs to some other simulation // belongs to some other simulation
return false; return false;
} }
int numEntities = _entities.size(); int numEntities = _otherEntities.size();
if (numEntities > MAX_ENTITIES_PER_SIMULATION) { if (numEntities > MAX_ENTITIES_PER_SIMULATION) {
// list is full // list is full
return false; return false;
} }
// add to list // add to list
entity->_simulation = this; entity->_simulation = this;
_entities.push_back(entity); _otherEntities.push_back(entity);
return true; return true;
} }
@ -71,17 +88,17 @@ void PhysicsSimulation::removeEntity(PhysicsEntity* entity) {
return; return;
} }
removeShapes(entity); removeShapes(entity);
int numEntities = _entities.size(); int numEntities = _otherEntities.size();
for (int i = 0; i < numEntities; ++i) { for (int i = 0; i < numEntities; ++i) {
if (entity == _entities.at(i)) { if (entity == _otherEntities.at(i)) {
if (i == numEntities - 1) { if (i == numEntities - 1) {
// remove it // remove it
_entities.pop_back(); _otherEntities.pop_back();
} else { } else {
// swap the last for this one // swap the last for this one
PhysicsEntity* lastEntity = _entities[numEntities - 1]; PhysicsEntity* lastEntity = _otherEntities[numEntities - 1];
_entities.pop_back(); _otherEntities.pop_back();
_entities[i] = lastEntity; _otherEntities[i] = lastEntity;
} }
entity->_simulation = NULL; entity->_simulation = NULL;
break; break;
@ -105,34 +122,34 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) {
if (!doll) { if (!doll) {
return false; return false;
} }
int numDolls = _dolls.size(); int numDolls = _otherRagdolls.size();
if (numDolls > MAX_DOLLS_PER_SIMULATION) { if (numDolls > MAX_DOLLS_PER_SIMULATION) {
// list is full // list is full
return false; return false;
} }
for (int i = 0; i < numDolls; ++i) { for (int i = 0; i < numDolls; ++i) {
if (doll == _dolls[i]) { if (doll == _otherRagdolls[i]) {
// already in list // already in list
return true; return true;
} }
} }
// add to list // add to list
_dolls.push_back(doll); _otherRagdolls.push_back(doll);
return true; return true;
} }
void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { void PhysicsSimulation::removeRagdoll(Ragdoll* doll) {
int numDolls = _dolls.size(); int numDolls = _otherRagdolls.size();
for (int i = 0; i < numDolls; ++i) { for (int i = 0; i < numDolls; ++i) {
if (doll == _dolls[i]) { if (doll == _otherRagdolls[i]) {
if (i == numDolls - 1) { if (i == numDolls - 1) {
// remove it // remove it
_dolls.pop_back(); _otherRagdolls.pop_back();
} else { } else {
// swap the last for this one // swap the last for this one
Ragdoll* lastDoll = _dolls[numDolls - 1]; Ragdoll* lastDoll = _otherRagdolls[numDolls - 1];
_dolls.pop_back(); _otherRagdolls.pop_back();
_dolls[i] = lastDoll; _otherRagdolls[i] = lastDoll;
} }
break; break;
} }
@ -141,17 +158,21 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) {
void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIterations, quint64 maxUsec) { void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIterations, quint64 maxUsec) {
++_frame; ++_frame;
if (!_ragdoll) {
return;
}
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
quint64 startTime = now; quint64 startTime = now;
quint64 expiry = startTime + maxUsec; quint64 expiry = startTime + maxUsec;
moveRagdolls(deltaTime); moveRagdolls(deltaTime);
buildContactConstraints(); buildContactConstraints();
int numDolls = _dolls.size(); int numDolls = _otherRagdolls.size();
{ {
PerformanceTimer perfTimer("enforce"); PerformanceTimer perfTimer("enforce");
_ragdoll->enforceRagdollConstraints();
for (int i = 0; i < numDolls; ++i) { for (int i = 0; i < numDolls; ++i) {
_dolls[i]->enforceRagdollConstraints(); _otherRagdolls[i]->enforceRagdollConstraints();
} }
} }
@ -164,9 +185,9 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter
{ // enforce constraints { // enforce constraints
PerformanceTimer perfTimer("enforce"); PerformanceTimer perfTimer("enforce");
error = 0.0f; error = _ragdoll->enforceRagdollConstraints();
for (int i = 0; i < numDolls; ++i) { for (int i = 0; i < numDolls; ++i) {
error = glm::max(error, _dolls[i]->enforceRagdollConstraints()); error = glm::max(error, _otherRagdolls[i]->enforceRagdollConstraints());
} }
} }
enforceContactConstraints(); enforceContactConstraints();
@ -180,42 +201,40 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter
void PhysicsSimulation::moveRagdolls(float deltaTime) { void PhysicsSimulation::moveRagdolls(float deltaTime) {
PerformanceTimer perfTimer("integrate"); PerformanceTimer perfTimer("integrate");
int numDolls = _dolls.size(); _ragdoll->stepRagdollForward(deltaTime);
int numDolls = _otherRagdolls.size();
for (int i = 0; i < numDolls; ++i) { for (int i = 0; i < numDolls; ++i) {
_dolls.at(i)->stepRagdollForward(deltaTime); _otherRagdolls.at(i)->stepRagdollForward(deltaTime);
} }
} }
void PhysicsSimulation::computeCollisions() { void PhysicsSimulation::computeCollisions() {
PerformanceTimer perfTimer("collide"); PerformanceTimer perfTimer("collide");
_collisions.clear(); _collisions.clear();
// TODO: keep track of QSet<PhysicsEntity*> collidedEntities;
int numEntities = _entities.size(); const QVector<Shape*> shapes = _entity->getShapes();
for (int i = 0; i < numEntities; ++i) {
PhysicsEntity* entity = _entities.at(i);
const QVector<Shape*> shapes = entity->getShapes();
int numShapes = shapes.size(); int numShapes = shapes.size();
// collide with self // collide with self
for (int j = 0; j < numShapes; ++j) { for (int i = 0; i < numShapes; ++i) {
const Shape* shape = shapes.at(j); const Shape* shape = shapes.at(i);
if (!shape) { if (!shape) {
continue; continue;
} }
for (int k = j+1; k < numShapes; ++k) { for (int j = i+1; j < numShapes; ++j) {
const Shape* otherShape = shapes.at(k); const Shape* otherShape = shapes.at(j);
if (otherShape && entity->collisionsAreEnabled(j, k)) { if (otherShape && _entity->collisionsAreEnabled(i, j)) {
ShapeCollider::collideShapes(shape, otherShape, _collisions); ShapeCollider::collideShapes(shape, otherShape, _collisions);
} }
} }
} }
// collide with others // collide with others
for (int j = i+1; j < numEntities; ++j) { int numEntities = _otherEntities.size();
const QVector<Shape*> otherShapes = _entities.at(j)->getShapes(); for (int i = 0; i < numEntities; ++i) {
const QVector<Shape*> otherShapes = _otherEntities.at(i)->getShapes();
ShapeCollider::collideShapesWithShapes(shapes, otherShapes, _collisions); ShapeCollider::collideShapesWithShapes(shapes, otherShapes, _collisions);
} }
} }
}
void PhysicsSimulation::resolveCollisions() { void PhysicsSimulation::resolveCollisions() {
PerformanceTimer perfTimer("resolve"); PerformanceTimer perfTimer("resolve");

View file

@ -28,6 +28,9 @@ public:
PhysicsSimulation(); PhysicsSimulation();
~PhysicsSimulation(); ~PhysicsSimulation();
void setRagdoll(Ragdoll* ragdoll) { _ragdoll = ragdoll; }
void setEntity(PhysicsEntity* entity);
/// \return true if entity was added to or is already in the list /// \return true if entity was added to or is already in the list
bool addEntity(PhysicsEntity* entity); bool addEntity(PhysicsEntity* entity);
@ -58,8 +61,11 @@ protected:
private: private:
quint32 _frame; quint32 _frame;
QVector<Ragdoll*> _dolls; PhysicsEntity* _entity;
QVector<PhysicsEntity*> _entities; Ragdoll* _ragdoll;
QVector<Ragdoll*> _otherRagdolls;
QVector<PhysicsEntity*> _otherEntities;
CollisionList _collisions; CollisionList _collisions;
QMap<quint64, ContactPoint> _contacts; QMap<quint64, ContactPoint> _contacts;
}; };