diff --git a/examples/example/games/billiards.js b/examples/example/games/billiards.js index d4bc71ba37..8e890515c0 100644 --- a/examples/example/games/billiards.js +++ b/examples/example/games/billiards.js @@ -39,126 +39,130 @@ hitSounds.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "Collisions-ballhitsandc HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var screenSize = Controller.getViewportDimensions(); var reticle = Overlays.addOverlay("image", { - x: screenSize.x / 2 - 16, - y: screenSize.y / 2 - 16, - width: 32, - height: 32, - imageURL: HIFI_PUBLIC_BUCKET + "images/billiardsReticle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); + x: screenSize.x / 2 - 16, + y: screenSize.y / 2 - 16, + width: 32, + height: 32, + imageURL: HIFI_PUBLIC_BUCKET + "images/billiardsReticle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 +}); function makeTable(pos) { - // Top - tableParts.push(Entities.addEntity( + // Top + tableParts.push(Entities.addEntity( { type: "Box", - position: pos, - dimensions: { x: LENGTH * SCALE, y: HEIGHT, z: WIDTH * SCALE }, - color: { red: 0, green: 255, blue: 0 } })); - // Long Bumpers - tableParts.push(Entities.addEntity( + position: pos, + dimensions: { x: LENGTH * SCALE, y: HEIGHT, z: WIDTH * SCALE }, + color: { red: 0, green: 255, blue: 0 } })); + // Long Bumpers + tableParts.push(Entities.addEntity( { type: "Box", - position: { x: pos.x - LENGTH / 2.0, - y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), - z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, - dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, - color: { red: 237, green: 201, blue: 175 } })); - tableParts.push(Entities.addEntity( + position: { x: pos.x - LENGTH / 2.0, + y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), + z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, + dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, + color: { red: 237, green: 201, blue: 175 } })); + tableParts.push(Entities.addEntity( { type: "Box", - position: { x: pos.x + LENGTH / 2.0, - y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), - z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, - dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, - color: { red: 237, green: 201, blue: 175 } })); + position: { x: pos.x + LENGTH / 2.0, + y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), + z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, + dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, + color: { red: 237, green: 201, blue: 175 } })); - tableParts.push(Entities.addEntity( + tableParts.push(Entities.addEntity( { type: "Box", - position: { x: pos.x - LENGTH / 2.0, - y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), - z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, - dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, - color: { red: 237, green: 201, blue: 175 } })); - tableParts.push(Entities.addEntity( + position: { x: pos.x - LENGTH / 2.0, + y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), + z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, + dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, + color: { red: 237, green: 201, blue: 175 } })); + tableParts.push(Entities.addEntity( { type: "Box", - position: { x: pos.x + LENGTH / 2.0, - y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), - z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, - dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, - color: { red: 237, green: 201, blue: 175 } })); - // End bumpers - tableParts.push(Entities.addEntity( + position: { x: pos.x + LENGTH / 2.0, + y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), + z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE }, + dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE }, + color: { red: 237, green: 201, blue: 175 } })); + // End bumpers + tableParts.push(Entities.addEntity( { type: "Box", - position: { x: pos.x + (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE, - y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), - z: pos.z }, - dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE }, - color: { red: 237, green: 201, blue: 175 } })); + position: { x: pos.x + (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE, + y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), + z: pos.z }, + dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE }, + color: { red: 237, green: 201, blue: 175 } })); - tableParts.push(Entities.addEntity( + tableParts.push(Entities.addEntity( { type: "Box", - position: { x: pos.x - (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE, - y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), - z: pos.z }, - dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE }, - color: { red: 237, green: 201, blue: 175 } })); + position: { x: pos.x - (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE, + y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0), + z: pos.z }, + dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE }, + color: { red: 237, green: 201, blue: 175 } })); } function makeBalls(pos) { - // Object balls + // Object balls var whichBall = [ 1, 14, 15, 4, 8, 7, 12, 9, 3, 13, 10, 5, 6, 11, 2 ]; var ballNumber = 0; - var ballPosition = { x: pos.x + (LENGTH / 4.0) * SCALE, y: pos.y + HEIGHT / 2.0 + DROP_HEIGHT, z: pos.z }; - for (var row = 1; row <= 5; row++) { - ballPosition.z = pos.z - ((row - 1.0) / 2.0 * (BALL_SIZE + BALL_GAP) * SCALE); - for (var spot = 0; spot < row; spot++) { - balls.push(Entities.addEntity( + var ballPosition = { x: pos.x + (LENGTH / 4.0) * SCALE, y: pos.y + HEIGHT / 2.0 + DROP_HEIGHT, z: pos.z }; + for (var row = 1; row <= 5; row++) { + ballPosition.z = pos.z - ((row - 1.0) / 2.0 * (BALL_SIZE + BALL_GAP) * SCALE); + for (var spot = 0; spot < row; spot++) { + balls.push(Entities.addEntity( { type: "Model", - modelURL: "https://s3.amazonaws.com/hifi-public/models/props/Pool/ball_" + whichBall[ballNumber].toString() + ".fbx", - position: ballPosition, - dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE }, - rotation: Quat.fromPitchYawRollDegrees((Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20), - color: { red: 255, green: 255, blue: 255 }, - gravity: { x: 0, y: GRAVITY, z: 0 }, - ignoreCollisions: false, - damping: 0.50, - shapeType: "sphere", - collisionsWillMove: true })); - ballPosition.z += (BALL_SIZE + BALL_GAP) * SCALE; + modelURL: "https://s3.amazonaws.com/hifi-public/models/props/Pool/ball_" + + whichBall[ballNumber].toString() + ".fbx", + position: ballPosition, + dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE }, + rotation: Quat.fromPitchYawRollDegrees((Math.random() - 0.5) * 20, + (Math.random() - 0.5) * 20, + (Math.random() - 0.5) * 20), + color: { red: 255, green: 255, blue: 255 }, + gravity: { x: 0, y: GRAVITY, z: 0 }, + velocity: {x: 0, y: -0.2, z: 0 }, + ignoreCollisions: false, + damping: 0.50, + shapeType: "sphere", + collisionsWillMove: true })); + ballPosition.z += (BALL_SIZE + BALL_GAP) * SCALE; ballNumber++; - } - ballPosition.x += (BALL_GAP + Math.sqrt(3.0) / 2.0 * BALL_SIZE) * SCALE; } + ballPosition.x += (BALL_GAP + Math.sqrt(3.0) / 2.0 * BALL_SIZE) * SCALE; + } // Cue Ball cuePosition = { x: pos.x - (LENGTH / 4.0) * SCALE, y: pos.y + HEIGHT / 2.0 + DROP_HEIGHT, z: pos.z }; cueBall = Entities.addEntity( - { type: "Model", - modelURL: "https://s3.amazonaws.com/hifi-public/models/props/Pool/cue_ball.fbx", - position: cuePosition, - dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE }, - color: { red: 255, green: 255, blue: 255 }, - gravity: { x: 0, y: GRAVITY, z: 0 }, - angularVelocity: { x: 0, y: 0, z: 0 }, - velocity: {x: 0, y: 0, z: 0 }, - ignoreCollisions: false, - damping: 0.50, - shapeType: "sphere", - collisionsWillMove: true }); - + { type: "Model", + modelURL: "https://s3.amazonaws.com/hifi-public/models/props/Pool/cue_ball.fbx", + position: cuePosition, + dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE }, + color: { red: 255, green: 255, blue: 255 }, + gravity: { x: 0, y: GRAVITY, z: 0 }, + angularVelocity: { x: 0, y: 0, z: 0 }, + velocity: {x: 0, y: -0.2, z: 0 }, + ignoreCollisions: false, + damping: 0.50, + shapeType: "sphere", + collisionsWillMove: true }); + } function isObjectBall(id) { - for (var i; i < balls.length; i++) { - if (balls[i].id == id) { - return true; - } - } - return false; + for (var i; i < balls.length; i++) { + if (balls[i].id == id) { + return true; + } + } + return false; } function shootCue(velocity) { - var DISTANCE_FROM_CAMERA = BALL_SIZE * 5.0 * SCALE; + var DISTANCE_FROM_CAMERA = BALL_SIZE * 5.0 * SCALE; var camera = Camera.getPosition(); var forwardVector = Quat.getFront(Camera.getOrientation()); var cuePosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA)); @@ -180,14 +184,14 @@ function shootCue(velocity) { density: 8000, ignoreCollisions: false, collisionsWillMove: true - }); + }); print("Shot, velocity = " + velocity); } function keyReleaseEvent(event) { - if ((startStroke > 0) && event.text == "SPACE") { - var endTime = new Date().getTime(); - var delta = endTime - startStroke; + if ((startStroke > 0) && event.text == "SPACE") { + var endTime = new Date().getTime(); + var delta = endTime - startStroke; shootCue(delta / 100.0); startStroke = 0; } @@ -201,49 +205,49 @@ function keyPressEvent(event) { } function cleanup() { - for (var i = 0; i < tableParts.length; i++) { - if (!tableParts[i].isKnownID) { - tableParts[i] = Entities.identifyEntity(tableParts[i]); - } - Entities.deleteEntity(tableParts[i]); + for (var i = 0; i < tableParts.length; i++) { + if (!tableParts[i].isKnownID) { + tableParts[i] = Entities.identifyEntity(tableParts[i]); } - for (var i = 0; i < balls.length; i++) { - if (!balls[i].isKnownID) { - balls[i] = Entities.identifyEntity(balls[i]); - } - Entities.deleteEntity(balls[i]); + Entities.deleteEntity(tableParts[i]); + } + for (var i = 0; i < balls.length; i++) { + if (!balls[i].isKnownID) { + balls[i] = Entities.identifyEntity(balls[i]); } - Overlays.deleteOverlay(reticle); - Entities.deleteEntity(cueBall); + Entities.deleteEntity(balls[i]); + } + Overlays.deleteOverlay(reticle); + Entities.deleteEntity(cueBall); } function update(deltaTime) { - if (!cueBall.isKnownID) { - cueBall = Entities.identifyEntity(cueBall); - } else { - // Check if cue ball has fallen off table, re-drop if so - var cueProperties = Entities.getEntityProperties(cueBall); - if (cueProperties.position.y < tableCenter.y) { - // Replace the cueball - Entities.editEntity(cueBall, { position: cuePosition } ); + if (!cueBall.isKnownID) { + cueBall = Entities.identifyEntity(cueBall); + } else { + // Check if cue ball has fallen off table, re-drop if so + var cueProperties = Entities.getEntityProperties(cueBall); + if (cueProperties.position.y < tableCenter.y) { + // Replace the cueball + Entities.editEntity(cueBall, { position: cuePosition } ); - } } + } } function entityCollisionWithEntity(entity1, entity2, collision) { - /* - NOT WORKING YET - if ((entity1.id == cueBall.id) || (entity2.id == cueBall.id)) { - print("Cue ball collision!"); - //audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); - //Audio.playSound(hitSounds[0], { position: Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())) }); - } + /* + NOT WORKING YET + if ((entity1.id == cueBall.id) || (entity2.id == cueBall.id)) { + print("Cue ball collision!"); + //audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); + //Audio.playSound(hitSounds[0], { position: Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())) }); + } - else if (isObjectBall(entity1.id) || isObjectBall(entity2.id)) { - print("Object ball collision"); - } */ + else if (isObjectBall(entity1.id) || isObjectBall(entity2.id)) { + print("Object ball collision"); + } */ } tableCenter = Vec3.sum(MyAvatar.position, Vec3.multiply(4.0, Quat.getFront(Camera.getOrientation()))); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index b1bf25ae9d..f968244ab3 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -27,75 +27,53 @@ bool EntityItem::_sendPhysicsUpdates = true; -void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { - _id = entityItemID.id; - _creatorTokenID = entityItemID.creatorTokenID; - - // init values with defaults before calling setProperties +EntityItem::EntityItem(const EntityItemID& entityItemID) : + _type(EntityTypes::Unknown), + _id(entityItemID.id), + _creatorTokenID(entityItemID.creatorTokenID), + _newlyCreated(false), + _lastSimulated(0), + _lastUpdated(0), + _lastEdited(0), + _lastEditedFromRemote(0), + _lastEditedFromRemoteInRemoteTime(0), + _created(UNKNOWN_CREATED_TIME), + _changedOnServer(0), + _position(ENTITY_ITEM_ZERO_VEC3), + _dimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS), + _rotation(ENTITY_ITEM_DEFAULT_ROTATION), + _glowLevel(ENTITY_ITEM_DEFAULT_GLOW_LEVEL), + _localRenderAlpha(ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA), + _density(ENTITY_ITEM_DEFAULT_DENSITY), + _volumeMultiplier(1.0f), + _velocity(ENTITY_ITEM_DEFAULT_VELOCITY), + _gravity(ENTITY_ITEM_DEFAULT_GRAVITY), + _acceleration(ENTITY_ITEM_DEFAULT_ACCELERATION), + _damping(ENTITY_ITEM_DEFAULT_DAMPING), + _lifetime(ENTITY_ITEM_DEFAULT_LIFETIME), + _script(ENTITY_ITEM_DEFAULT_SCRIPT), + _registrationPoint(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT), + _angularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY), + _angularDamping(ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING), + _visible(ENTITY_ITEM_DEFAULT_VISIBLE), + _ignoreForCollisions(ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS), + _collisionsWillMove(ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE), + _locked(ENTITY_ITEM_DEFAULT_LOCKED), + _userData(ENTITY_ITEM_DEFAULT_USER_DATA), + _simulatorID(ENTITY_ITEM_DEFAULT_SIMULATOR_ID), + _simulatorIDChangedTime(0), + _marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), + _physicsInfo(NULL), + _dirtyFlags(0), + _element(NULL) +{ quint64 now = usecTimestampNow(); _lastSimulated = now; _lastUpdated = now; - _lastEdited = 0; - _lastEditedFromRemote = 0; - _lastEditedFromRemoteInRemoteTime = 0; - _created = UNKNOWN_CREATED_TIME; - _changedOnServer = 0; - - _position = ENTITY_ITEM_ZERO_VEC3; - _dimensions = ENTITY_ITEM_DEFAULT_DIMENSIONS; - _density = ENTITY_ITEM_DEFAULT_DENSITY; - _rotation = ENTITY_ITEM_DEFAULT_ROTATION; - _glowLevel = ENTITY_ITEM_DEFAULT_GLOW_LEVEL; - _localRenderAlpha = ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA; - _velocity = ENTITY_ITEM_DEFAULT_VELOCITY; - _gravity = ENTITY_ITEM_DEFAULT_GRAVITY; - _acceleration = ENTITY_ITEM_DEFAULT_ACCELERATION; - _damping = ENTITY_ITEM_DEFAULT_DAMPING; - _lifetime = ENTITY_ITEM_DEFAULT_LIFETIME; - _script = ENTITY_ITEM_DEFAULT_SCRIPT; - _registrationPoint = ENTITY_ITEM_DEFAULT_REGISTRATION_POINT; - _angularVelocity = ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY; - _angularDamping = ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING; - _visible = ENTITY_ITEM_DEFAULT_VISIBLE; - _ignoreForCollisions = ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS; - _collisionsWillMove = ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE; - _locked = ENTITY_ITEM_DEFAULT_LOCKED; - _userData = ENTITY_ITEM_DEFAULT_USER_DATA; - _simulatorID = ENTITY_ITEM_DEFAULT_SIMULATOR_ID; - _marketplaceID = ENTITY_ITEM_DEFAULT_MARKETPLACE_ID; } -EntityItem::EntityItem(const EntityItemID& entityItemID) { - _type = EntityTypes::Unknown; - quint64 now = usecTimestampNow(); - _lastSimulated = now; - _lastUpdated = now; - _lastEdited = 0; - _lastEditedFromRemote = 0; - _lastEditedFromRemoteInRemoteTime = 0; - _created = UNKNOWN_CREATED_TIME; - _dirtyFlags = 0; - _changedOnServer = 0; - _element = NULL; - _simulatorIDChangedTime = 0; - _shouldClaimSimulationOwnership = false; - initFromEntityItemID(entityItemID); -} - -EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) { - _type = EntityTypes::Unknown; - quint64 now = usecTimestampNow(); - _lastSimulated = now; - _lastUpdated = now; - _lastEdited = 0; - _lastEditedFromRemote = 0; - _lastEditedFromRemoteInRemoteTime = 0; - _created = UNKNOWN_CREATED_TIME; - _dirtyFlags = 0; - _changedOnServer = 0; - _element = NULL; - _simulatorIDChangedTime = 0; - initFromEntityItemID(entityItemID); +EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : EntityItem(entityItemID) +{ setProperties(properties); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 0ebcd06a77..fda8167564 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -244,8 +244,6 @@ public: QUuid getSimulatorID() const { return _simulatorID; } void setSimulatorID(const QUuid& value); quint64 getSimulatorIDChangedTime() const { return _simulatorIDChangedTime; } - void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } - bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } const QString& getMarketplaceID() const { return _marketplaceID; } void setMarketplaceID(const QString& value) { _marketplaceID = value; } @@ -305,9 +303,6 @@ public: protected: static bool _sendPhysicsUpdates; - - virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init - EntityTypes::EntityType _type; QUuid _id; uint32_t _creatorTokenID; @@ -347,7 +342,6 @@ protected: QString _userData; QUuid _simulatorID; // id of Node which is currently responsible for simulating this Entity quint64 _simulatorIDChangedTime; // when was _simulatorID last updated? - bool _shouldClaimSimulationOwnership; QString _marketplaceID; // NOTE: Damping is applied like this: v *= pow(1 - damping, dt) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 13e6b83393..04da26a1ff 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -65,17 +65,8 @@ void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) { void setSimId(EntityItemProperties& propertiesWithSimID, EntityItem* entity) { auto nodeList = DependencyManager::get(); const QUuid myNodeID = nodeList->getSessionUUID(); - - // if this entity has non-zero physics/simulation related values, claim simulation ownership - if (propertiesWithSimID.velocityChanged() || - propertiesWithSimID.rotationChanged() || - propertiesWithSimID.containsPositionChange()) { - propertiesWithSimID.setSimulatorID(myNodeID); - entity->setSimulatorID(myNodeID); - } else if (entity->getSimulatorID() == myNodeID) { - propertiesWithSimID.setSimulatorID(QUuid()); // give up simulation ownership - entity->setSimulatorID(QUuid()); - } + propertiesWithSimID.setSimulatorID(myNodeID); + entity->setSimulatorID(myNodeID); } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index e5a12a2b66..d1571fbcc5 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -18,7 +18,8 @@ #include "PhysicsHelpers.h" #include "PhysicsLogging.h" -static const float MEASURED_ACCELERATION_CLOSE_TO_ZERO = 0.05f; +static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; +static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4; QSet* _outgoingEntityList; @@ -34,8 +35,11 @@ void EntityMotionState::enqueueOutgoingEntity(EntityItem* entity) { _outgoingEntityList->insert(entity); } -EntityMotionState::EntityMotionState(EntityItem* entity) - : _entity(entity) { +EntityMotionState::EntityMotionState(EntityItem* entity) : + _entity(entity), + _accelerationNearlyGravityCount(0), + _shouldClaimSimulationOwnership(false) +{ _type = MOTION_STATE_TYPE_ENTITY; assert(entity != NULL); } @@ -191,7 +195,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { return false; } - if (_entity->getShouldClaimSimulationOwnership()) { + if (getShouldClaimSimulationOwnership()) { return true; } @@ -199,7 +203,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) { const QUuid& myNodeID = nodeList->getSessionUUID(); const QUuid& simulatorID = _entity->getSimulatorID(); - if (!simulatorID.isNull() && simulatorID != myNodeID) { + if (simulatorID != myNodeID) { // some other Node owns the simulating of this, so don't broadcast the results of local simulation. return false; } @@ -214,10 +218,26 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (_outgoingPacketFlags) { EntityItemProperties properties = _entity->getProperties(); - if (glm::length(_measuredAcceleration) < MEASURED_ACCELERATION_CLOSE_TO_ZERO) { - _entity->setAcceleration(glm::vec3(0.0f)); + float gravityLength = glm::length(_entity->getGravity()); + float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); + if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { + // acceleration measured during the most recent simulation step was close to gravity. + if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { + // only increment this if we haven't reached the threshold yet. this is to avoid + // overflowing the counter. + incrementAccelerationNearlyGravityCount(); + } } else { + // acceleration wasn't similar to this entities gravity, so reset the went-ballistic counter + resetAccelerationNearlyGravityCount(); + } + + // if this entity has been accelerated at close to gravity for a certain number of simulation-steps, let + // the entity server's estimates include gravity. + if (getAccelerationNearlyGravityCount() >= STEPS_TO_DECIDE_BALLISTIC) { _entity->setAcceleration(_entity->getGravity()); + } else { + _entity->setAcceleration(glm::vec3(0.0f)); } if (_outgoingPacketFlags & EntityItem::DIRTY_POSITION) { @@ -266,16 +286,13 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ QUuid myNodeID = nodeList->getSessionUUID(); QUuid simulatorID = _entity->getSimulatorID(); - if (_entity->getShouldClaimSimulationOwnership()) { + if (getShouldClaimSimulationOwnership()) { _entity->setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID); - _entity->setShouldClaimSimulationOwnership(false); + setShouldClaimSimulationOwnership(false); } - else if (simulatorID.isNull() && !(zeroSpeed && zeroSpin)) { - // The object is moving and nobody thinks they own the motion. set this Node as the simulator - _entity->setSimulatorID(myNodeID); - properties.setSimulatorID(myNodeID); - } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { + + if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { // we are the simulator and the object has stopped. give up "simulator" status _entity->setSimulatorID(QUuid()); properties.setSimulatorID(QUuid()); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 2b965a39d3..07f82aaa42 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -62,10 +62,18 @@ public: virtual uint32_t getIncomingDirtyFlags() const; virtual void clearIncomingDirtyFlags(uint32_t flags) { _entity->clearDirtyFlags(flags); } - EntityItem* getEntity() const { return _entity; } + void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; } + void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } + quint8 getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } + + virtual EntityItem* getEntity() const { return _entity; } + virtual void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; } + virtual bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; } protected: EntityItem* _entity; + quint8 _accelerationNearlyGravityCount; + bool _shouldClaimSimulationOwnership; }; #endif // hifi_EntityMotionState_h diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index ad9ef861b9..9e0917a3ab 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -111,6 +111,12 @@ public: virtual bool isMoving() const = 0; friend class PhysicsEngine; + + // these are here so we can call into EntityMotionObject with a base-class pointer + virtual EntityItem* getEntity() const { return NULL; } + virtual void setShouldClaimSimulationOwnership(bool value) { } + virtual bool getShouldClaimSimulationOwnership() { return false; } + protected: void setRigidBody(btRigidBody* body); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 44bba990ac..45f3c97e30 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -348,10 +348,10 @@ void PhysicsEngine::stepSimulation() { _characterController->postSimulation(); } + computeCollisionEvents(); + unlock(); _entityTree->unlock(); - - computeCollisionEvents(); } } @@ -369,6 +369,9 @@ void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { void PhysicsEngine::computeCollisionEvents() { BT_PROFILE("computeCollisionEvents"); + auto nodeList = DependencyManager::get(); + QUuid myNodeID = nodeList->getSessionUUID(); + const btCollisionObject* characterCollisionObject = _characterController ? _characterController->getCollisionObject() : NULL; @@ -388,21 +391,31 @@ void PhysicsEngine::computeCollisionEvents() { continue; } - void* a = objectA->getUserPointer(); - void* b = objectB->getUserPointer(); + ObjectMotionState* a = static_cast(objectA->getUserPointer()); + ObjectMotionState* b = static_cast(objectB->getUserPointer()); + EntityItem* entityA = a ? a->getEntity() : NULL; + EntityItem* entityB = b ? b->getEntity() : NULL; + bool aIsDynamic = entityA && !objectA->isStaticOrKinematicObject(); + bool bIsDynamic = entityB && !objectB->isStaticOrKinematicObject(); + if (a || b) { // the manifold has up to 4 distinct points, but only extract info from the first _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); - - // if our character capsule is colliding with something dynamic, claim simulation ownership. - // see EntityMotionState::sendUpdate - if (objectA == characterCollisionObject && !objectB->isStaticOrKinematicObject() && b) { - EntityItem* entityB = static_cast(b)->getEntity(); - entityB->setShouldClaimSimulationOwnership(true); + } + // collisions cause infectious spread of simulation-ownership. we also attempt to take + // ownership of anything that collides with our avatar. + if ((aIsDynamic && entityA->getSimulatorID() == myNodeID) || + (a && a->getShouldClaimSimulationOwnership()) || + (objectA == characterCollisionObject)) { + if (bIsDynamic) { + b->setShouldClaimSimulationOwnership(true); } - if (objectB == characterCollisionObject && !objectA->isStaticOrKinematicObject() && a) { - EntityItem* entityA = static_cast(a)->getEntity(); - entityA->setShouldClaimSimulationOwnership(true); + } + if ((bIsDynamic && entityB->getSimulatorID() == myNodeID) || + (b && b->getShouldClaimSimulationOwnership()) || + (objectB == characterCollisionObject)) { + if (aIsDynamic) { + a->setShouldClaimSimulationOwnership(true); } } } @@ -413,7 +426,6 @@ void PhysicsEngine::computeCollisionEvents() { // scan known contacts and trigger events ContactMap::iterator contactItr = _contactMap.begin(); - while (contactItr != _contactMap.end()) { ObjectMotionState* A = static_cast(contactItr->first._a); ObjectMotionState* B = static_cast(contactItr->first._b); @@ -521,9 +533,55 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap motionState->resetMeasuredAcceleration(); } +void PhysicsEngine::bump(EntityItem* bumpEntity) { + // If this node is doing something like deleting an entity, scan for contacts involving the + // entity. For each found, flag the other entity involved as being simulated by this node. + lock(); + int numManifolds = _collisionDispatcher->getNumManifolds(); + for (int i = 0; i < numManifolds; ++i) { + btPersistentManifold* contactManifold = _collisionDispatcher->getManifoldByIndexInternal(i); + if (contactManifold->getNumContacts() > 0) { + const btCollisionObject* objectA = static_cast(contactManifold->getBody0()); + const btCollisionObject* objectB = static_cast(contactManifold->getBody1()); + if (objectA && objectB) { + void* a = objectA->getUserPointer(); + void* b = objectB->getUserPointer(); + if (a && b) { + EntityMotionState* entityMotionStateA = static_cast(a); + EntityMotionState* entityMotionStateB = static_cast(b); + EntityItem* entityA = entityMotionStateA ? entityMotionStateA->getEntity() : NULL; + EntityItem* entityB = entityMotionStateB ? entityMotionStateB->getEntity() : NULL; + if (entityA && entityB) { + if (entityA == bumpEntity) { + entityMotionStateB->setShouldClaimSimulationOwnership(true); + if (!objectB->isActive()) { + objectB->setActivationState(ACTIVE_TAG); + } + } + if (entityB == bumpEntity) { + entityMotionStateA->setShouldClaimSimulationOwnership(true); + if (!objectA->isActive()) { + objectA->setActivationState(ACTIVE_TAG); + } + } + } + } + } + } + } + unlock(); +} + void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) { assert(motionState); btRigidBody* body = motionState->getRigidBody(); + + // set the about-to-be-deleted entity active in order to wake up the island it's part of. this is done + // so that anything resting on top of it will fall. + // body->setActivationState(ACTIVE_TAG); + EntityItem* entity = static_cast(motionState)->getEntity(); + bump(entity); + if (body) { const btCollisionShape* shape = body->getCollisionShape(); _dynamicsWorld->removeRigidBody(body); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 6e1f430237..148261c6d2 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -98,6 +98,7 @@ private: // return 'true' of update was successful bool updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); + void bump(EntityItem* bumpEntity); btClock _clock; btDefaultCollisionConfiguration* _collisionConfig = NULL;