diff --git a/examples/editModels.js b/examples/editModels.js index 356b228380..43e73104e2 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -2907,8 +2907,6 @@ function handeMenuEvent(menuItem) { index++; array.push({ label: "Linear Damping:", value: properties.damping.toFixed(decimals) }); index++; - array.push({ label: "Mass:", value: properties.mass.toFixed(decimals) }); - index++; array.push({ label: "Angular Pitch:", value: properties.angularVelocity.x.toFixed(decimals) }); index++; array.push({ label: "Angular Yaw:", value: properties.angularVelocity.y.toFixed(decimals) }); @@ -2925,6 +2923,15 @@ function handeMenuEvent(menuItem) { array.push({ label: "Gravity Z:", value: properties.gravity.z.toFixed(decimals) }); index++; + array.push({ label: "Collisions:", type: "header" }); + index++; + array.push({ label: "Mass:", value: properties.mass.toFixed(decimals) }); + index++; + array.push({ label: "Ignore for Collisions:", value: properties.ignoreForCollisions }); + index++; + array.push({ label: "Collisions Will Move:", value: properties.collisionsWillMove }); + index++; + array.push({ label: "Lifetime:", value: properties.lifetime.toFixed(decimals) }); index++; @@ -3055,7 +3062,6 @@ Window.nonBlockingFormClosed.connect(function() { properties.velocity.y = array[index++].value; properties.velocity.z = array[index++].value; properties.damping = array[index++].value; - properties.mass = array[index++].value; properties.angularVelocity.x = array[index++].value; properties.angularVelocity.y = array[index++].value; @@ -3065,6 +3071,12 @@ Window.nonBlockingFormClosed.connect(function() { properties.gravity.x = array[index++].value; properties.gravity.y = array[index++].value; properties.gravity.z = array[index++].value; + + index++; // skip header + properties.mass = array[index++].value; + properties.ignoreForCollisions = array[index++].value; + properties.collisionsWillMove = array[index++].value; + properties.lifetime = array[index++].value; properties.visible = array[index++].value; diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 2a5450e91f..609b91f3a1 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -105,10 +105,15 @@ void EntityCollisionSystem::updateCollisionWithVoxels(EntityItem* entity) { } void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { + + if (entityA->getIgnoreForCollisions()) { + return; // bail early if this entity is to be ignored... + } + glm::vec3 penetration; EntityItem* entityB = NULL; - const float MAX_COLLISIONS_PER_ENTITY = 32; + const int MAX_COLLISIONS_PER_ENTITY = 32; CollisionList collisions(MAX_COLLISIONS_PER_ENTITY); bool shapeCollisionsAccurate = false; @@ -134,8 +139,13 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { // we don't want to count this as a collision. glm::vec3 relativeVelocity = entityA->getVelocity() - entityB->getVelocity(); + bool wantToMoveA = entityA->getCollisionsWillMove(); + bool wantToMoveB = entityB->getCollisionsWillMove(); bool movingTowardEachOther = glm::dot(relativeVelocity, penetrationInTreeUnits) > 0.0f; - bool doCollisions = movingTowardEachOther; // don't do collisions if the entities are moving away from each other + + // only do collisions if the entities are moving toward each other and one or the other + // of the entities are movable from collisions + bool doCollisions = movingTowardEachOther && (wantToMoveA || wantToMoveB); if (doCollisions) { quint64 now = usecTimestampNow(); @@ -152,35 +162,53 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { float massA = entityA->getMass(); float massB = entityB->getMass(); float totalMass = massA + massB; + float massRatioA = (2.0f * massB / totalMass); + float massRatioB = (2.0f * massA / totalMass); - // handle Entity A - glm::vec3 newVelocityA = entityA->getVelocity() - axialVelocity * (2.0f * massB / totalMass); - glm::vec3 newPositionA = entityA->getPosition() - 0.5f * penetrationInTreeUnits; + // in the event that one of our entities is non-moving, then fix up these ratios + if (wantToMoveA && !wantToMoveB) { + massRatioA = 2.0f; + massRatioB = 0.0f; + } - EntityItemProperties propertiesA = entityA->getProperties(); - EntityItemID idA(entityA->getID()); - propertiesA.setVelocity(newVelocityA * (float)TREE_SCALE); - propertiesA.setPosition(newPositionA * (float)TREE_SCALE); - propertiesA.setLastEdited(now); + if (!wantToMoveA && wantToMoveB) { + massRatioA = 0.0f; + massRatioB = 2.0f; + } - _entities->updateEntity(idA, propertiesA); - _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idA, propertiesA); + // unless the entity is configured to not be moved by collision, calculate it's new position + // and velocity and apply it + if (wantToMoveA) { + // handle Entity A + glm::vec3 newVelocityA = entityA->getVelocity() - axialVelocity * massRatioA; + glm::vec3 newPositionA = entityA->getPosition() - 0.5f * penetrationInTreeUnits; - glm::vec3 newVelocityB = entityB->getVelocity() + axialVelocity * (2.0f * massA / totalMass); - glm::vec3 newPositionB = entityB->getPosition() + 0.5f * penetrationInTreeUnits; + EntityItemProperties propertiesA = entityA->getProperties(); + EntityItemID idA(entityA->getID()); + propertiesA.setVelocity(newVelocityA * (float)TREE_SCALE); + propertiesA.setPosition(newPositionA * (float)TREE_SCALE); + propertiesA.setLastEdited(now); + + _entities->updateEntity(idA, propertiesA); + _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idA, propertiesA); + } - EntityItemProperties propertiesB = entityB->getProperties(); + // unless the entity is configured to not be moved by collision, calculate it's new position + // and velocity and apply it + if (wantToMoveB) { + glm::vec3 newVelocityB = entityB->getVelocity() + axialVelocity * massRatioB; + glm::vec3 newPositionB = entityB->getPosition() + 0.5f * penetrationInTreeUnits; - EntityItemID idB(entityB->getID()); - propertiesB.setVelocity(newVelocityB * (float)TREE_SCALE); - propertiesB.setPosition(newPositionB * (float)TREE_SCALE); - propertiesB.setLastEdited(now); + EntityItemProperties propertiesB = entityB->getProperties(); - _entities->updateEntity(idB, propertiesB); - _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idB, propertiesB); - - // TODO: Do we need this? - //_packetSender->releaseQueuedMessages(); + EntityItemID idB(entityB->getID()); + propertiesB.setVelocity(newVelocityB * (float)TREE_SCALE); + propertiesB.setPosition(newPositionB * (float)TREE_SCALE); + propertiesB.setLastEdited(now); + + _entities->updateEntity(idB, propertiesB); + _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idB, propertiesB); + } } } } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 84ba0bd45d..86fac0997e 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -42,6 +42,8 @@ const glm::vec3 EntityItem::NO_ANGULAR_VELOCITY = glm::vec3(0.0f, 0.0f, 0.0f); const glm::vec3 EntityItem::DEFAULT_ANGULAR_VELOCITY = NO_ANGULAR_VELOCITY; const float EntityItem::DEFAULT_ANGULAR_DAMPING = 0.5f; const bool EntityItem::DEFAULT_VISIBLE = true; +const bool EntityItem::DEFAULT_IGNORE_FOR_COLLISIONS = false; +const bool EntityItem::DEFAULT_COLLISIONS_WILL_MOVE = false; void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _id = entityItemID.id; @@ -70,6 +72,8 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _angularVelocity = DEFAULT_ANGULAR_VELOCITY; _angularDamping = DEFAULT_ANGULAR_DAMPING; _visible = DEFAULT_VISIBLE; + _ignoreForCollisions = DEFAULT_IGNORE_FOR_COLLISIONS; + _collisionsWillMove = DEFAULT_COLLISIONS_WILL_MOVE; recalculateCollisionShape(); } @@ -111,6 +115,8 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_ANGULAR_VELOCITY; requestedProperties += PROP_ANGULAR_DAMPING; requestedProperties += PROP_VISIBLE; + requestedProperties += PROP_IGNORE_FOR_COLLISIONS; + requestedProperties += PROP_COLLISIONS_WILL_MOVE; return requestedProperties; } @@ -224,6 +230,8 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, appendValue, getAngularVelocity()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, appendValue, getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, getVisible()); + APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, getIgnoreForCollisions()); + APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, getCollisionsWillMove()); appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -484,10 +492,14 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, _angularVelocity); READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, _angularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, _visible); + READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, _ignoreForCollisions); + READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, _collisionsWillMove); if (wantDebug) { qDebug() << " readEntityDataFromBuffer() _registrationPoint:" << _registrationPoint; qDebug() << " readEntityDataFromBuffer() _visible:" << _visible; + qDebug() << " readEntityDataFromBuffer() _ignoreForCollisions:" << _ignoreForCollisions; + qDebug() << " readEntityDataFromBuffer() _collisionsWillMove:" << _collisionsWillMove; } bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); @@ -734,6 +746,8 @@ EntityItemProperties EntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularDamping, getAngularDamping); COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel); COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignoreForCollisions, getIgnoreForCollisions); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionsWillMove, getCollisionsWillMove); properties._defaultSettings = false; @@ -766,6 +780,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, setAngularDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel); SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, setIgnoreForCollisions); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, setCollisionsWillMove); if (somethingChanged) { somethingChangedNotification(); // notify derived classes that something has changed diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index bdd0d572d3..621bd94287 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -230,6 +230,14 @@ public: void setVisible(bool value) { _visible = value; } bool isVisible() const { return _visible; } bool isInvisible() const { return !_visible; } + + static const bool DEFAULT_IGNORE_FOR_COLLISIONS; + bool getIgnoreForCollisions() const { return _ignoreForCollisions; } + void setIgnoreForCollisions(bool value) { _ignoreForCollisions = value; } + + static const bool DEFAULT_COLLISIONS_WILL_MOVE; + bool getCollisionsWillMove() const { return _collisionsWillMove; } + void setCollisionsWillMove(bool value) { _collisionsWillMove = value; } // TODO: We need to get rid of these users of getRadius()... float getRadius() const; @@ -265,6 +273,8 @@ protected: glm::vec3 _angularVelocity; float _angularDamping; bool _visible; + bool _ignoreForCollisions; + bool _collisionsWillMove; // NOTE: Radius support is obsolete, but these private helper functions are available for this class to // parse old data streams diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 207ed376d8..f54ce274f9 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -41,6 +41,8 @@ EntityItemProperties::EntityItemProperties() : _angularVelocity(EntityItem::DEFAULT_ANGULAR_VELOCITY), _angularDamping(EntityItem::DEFAULT_ANGULAR_DAMPING), _visible(EntityItem::DEFAULT_VISIBLE), + _ignoreForCollisions(EntityItem::DEFAULT_IGNORE_FOR_COLLISIONS), + _collisionsWillMove(EntityItem::DEFAULT_COLLISIONS_WILL_MOVE), _positionChanged(false), _dimensionsChanged(false), @@ -55,6 +57,8 @@ EntityItemProperties::EntityItemProperties() : _angularVelocityChanged(false), _angularDampingChanged(false), _visibleChanged(false), + _ignoreForCollisionsChanged(false), + _collisionsWillMoveChanged(false), _color(), _modelURL(""), @@ -112,6 +116,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_REGISTRATION_POINT, registrationPoint); CHECK_PROPERTY_CHANGE(PROP_ANGULAR_VELOCITY, angularVelocity); CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping); + CHECK_PROPERTY_CHANGE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); + CHECK_PROPERTY_CHANGE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); return changedProperties; } @@ -150,6 +156,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(animationFrameIndex); COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS); COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); + COPY_PROPERTY_TO_QSCRIPTVALUE(ignoreForCollisions); + COPY_PROPERTY_TO_QSCRIPTVALUE(collisionsWillMove); // Sitting properties support QScriptValue sittingPoints = engine->newObject(); @@ -194,6 +202,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFrameIndex, setAnimationFrameIndex); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(glowLevel, setGlowLevel); + COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(ignoreForCollisions, setIgnoreForCollisions); + COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(collisionsWillMove, setCollisionsWillMove); _lastEdited = usecTimestampNow(); } @@ -342,6 +352,8 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, appendValue, properties.getAngularVelocity()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, appendValue, properties.getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, properties.getVisible()); + APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, properties.getIgnoreForCollisions()); + APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, properties.getCollisionsWillMove()); } if (propertyCount > 0) { int endOfEntityItemData = packetData->getUncompressedByteOffset(); @@ -538,6 +550,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_VELOCITY, glm::vec3, setAngularVelocity); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_DAMPING, float, setAngularDamping); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_FOR_COLLISIONS, bool, setIgnoreForCollisions); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove); return valid; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index f4f9343f76..0d993acda9 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -62,8 +62,10 @@ enum EntityPropertyList { PROP_REGISTRATION_POINT, PROP_ANGULAR_VELOCITY, PROP_ANGULAR_DAMPING, + PROP_IGNORE_FOR_COLLISIONS, + PROP_COLLISIONS_WILL_MOVE, - PROP_LAST_ITEM = PROP_ANGULAR_DAMPING + PROP_LAST_ITEM = PROP_COLLISIONS_WILL_MOVE }; typedef PropertyFlags EntityPropertyFlags; @@ -221,6 +223,12 @@ public: bool getVisible() const { return _visible; } void setVisible(bool value) { _visible = value; _visibleChanged = true; } + bool getIgnoreForCollisions() const { return _ignoreForCollisions; } + void setIgnoreForCollisions(bool value) { _ignoreForCollisions = value; _ignoreForCollisionsChanged = true; } + + bool getCollisionsWillMove() const { return _collisionsWillMove; } + void setCollisionsWillMove(bool value) { _collisionsWillMove = value; _collisionsWillMoveChanged = true; } + void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; } private: @@ -247,6 +255,8 @@ private: glm::vec3 _angularVelocity; float _angularDamping; bool _visible; + bool _ignoreForCollisions; + bool _collisionsWillMove; bool _positionChanged; bool _dimensionsChanged; @@ -261,6 +271,8 @@ private: bool _angularVelocityChanged; bool _angularDampingChanged; bool _visibleChanged; + bool _ignoreForCollisionsChanged; + bool _collisionsWillMoveChanged; // TODO: this need to be more generic. for now, we're going to have the properties class support these as // named getter/setters, but we want to move them to generic types... diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 6e9ecbbd9a..5df98d43a8 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -555,8 +555,10 @@ bool EntityTreeElement::findShapeCollisions(const Shape* shape, CollisionList& c QList::const_iterator entityEnd = _entityItems->end(); while(entityItr != entityEnd) { EntityItem* entity = (*entityItr); + + // entities that are set for ignore for collisions then don't consider them for collision const Shape* otherCollisionShape = &entity->getCollisionShapeInMeters(); - if (shape != otherCollisionShape) { + if (shape != otherCollisionShape && !entity->getIgnoreForCollisions()) { if (ShapeCollider::collideShapes(shape, otherCollisionShape, collisions)) { CollisionInfo* lastCollision = collisions.getLastCollision(); lastCollision->_extraData = entity;