mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 08:39:43 +02:00
commit
45aa78702c
3 changed files with 111 additions and 6 deletions
|
@ -17,11 +17,14 @@
|
||||||
#include "CharacterController.h"
|
#include "CharacterController.h"
|
||||||
|
|
||||||
const uint16_t AvatarActionHold::holdVersion = 1;
|
const uint16_t AvatarActionHold::holdVersion = 1;
|
||||||
|
const int AvatarActionHold::velocitySmoothFrames = 6;
|
||||||
|
|
||||||
|
|
||||||
AvatarActionHold::AvatarActionHold(const QUuid& id, EntityItemPointer ownerEntity) :
|
AvatarActionHold::AvatarActionHold(const QUuid& id, EntityItemPointer ownerEntity) :
|
||||||
ObjectActionSpring(id, ownerEntity)
|
ObjectActionSpring(id, ownerEntity)
|
||||||
{
|
{
|
||||||
_type = ACTION_TYPE_HOLD;
|
_type = ACTION_TYPE_HOLD;
|
||||||
|
_measuredLinearVelocities.resize(AvatarActionHold::velocitySmoothFrames);
|
||||||
#if WANT_DEBUG
|
#if WANT_DEBUG
|
||||||
qDebug() << "AvatarActionHold::AvatarActionHold";
|
qDebug() << "AvatarActionHold::AvatarActionHold";
|
||||||
#endif
|
#endif
|
||||||
|
@ -204,8 +207,38 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
|
||||||
}
|
}
|
||||||
|
|
||||||
withWriteLock([&]{
|
withWriteLock([&]{
|
||||||
|
if (_previousSet) {
|
||||||
|
glm::vec3 oneFrameVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep;
|
||||||
|
_measuredLinearVelocities[_measuredLinearVelocitiesIndex++] = oneFrameVelocity;
|
||||||
|
if (_measuredLinearVelocitiesIndex >= AvatarActionHold::velocitySmoothFrames) {
|
||||||
|
_measuredLinearVelocitiesIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 measuredLinearVelocity;
|
||||||
|
for (int i = 0; i < AvatarActionHold::velocitySmoothFrames; i++) {
|
||||||
|
// there is a bit of lag between when someone releases the trigger and when the software reacts to
|
||||||
|
// the release. we calculate the velocity from previous frames but we don't include several
|
||||||
|
// of the most recent.
|
||||||
|
//
|
||||||
|
// if _measuredLinearVelocitiesIndex is
|
||||||
|
// 0 -- ignore i of 3 4 5
|
||||||
|
// 1 -- ignore i of 4 5 0
|
||||||
|
// 2 -- ignore i of 5 0 1
|
||||||
|
// 3 -- ignore i of 0 1 2
|
||||||
|
// 4 -- ignore i of 1 2 3
|
||||||
|
// 5 -- ignore i of 2 3 4
|
||||||
|
if ((i + 1) % 6 == _measuredLinearVelocitiesIndex ||
|
||||||
|
(i + 2) % 6 == _measuredLinearVelocitiesIndex ||
|
||||||
|
(i + 3) % 6 == _measuredLinearVelocitiesIndex) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
measuredLinearVelocity += _measuredLinearVelocities[i];
|
||||||
|
}
|
||||||
|
measuredLinearVelocity /= (float)(AvatarActionHold::velocitySmoothFrames - 3); // 3 because of the 3 we skipped, above
|
||||||
|
|
||||||
if (_kinematicSetVelocity) {
|
if (_kinematicSetVelocity) {
|
||||||
rigidBody->setLinearVelocity(glmToBullet(_linearVelocityTarget));
|
rigidBody->setLinearVelocity(glmToBullet(measuredLinearVelocity));
|
||||||
rigidBody->setAngularVelocity(glmToBullet(_angularVelocityTarget));
|
rigidBody->setAngularVelocity(glmToBullet(_angularVelocityTarget));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,10 @@ private:
|
||||||
glm::vec3 _palmOffsetFromRigidBody;
|
glm::vec3 _palmOffsetFromRigidBody;
|
||||||
// leaving this here for future refernece.
|
// leaving this here for future refernece.
|
||||||
// glm::quat _palmRotationFromRigidBody;
|
// glm::quat _palmRotationFromRigidBody;
|
||||||
|
|
||||||
|
static const int velocitySmoothFrames;
|
||||||
|
QVector<glm::vec3> _measuredLinearVelocities;
|
||||||
|
int _measuredLinearVelocitiesIndex { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AvatarActionHold_h
|
#endif // hifi_AvatarActionHold_h
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
/* global setEntityCustomData, getEntityCustomData, vec3toStr, flatten, Xform */
|
/* global setEntityCustomData, getEntityCustomData, vec3toStr, flatten, Xform */
|
||||||
|
|
||||||
Script.include("/~/system/libraries/utils.js");
|
Script.include("/~/system/libraries/utils.js");
|
||||||
Script.include("../libraries/Xform.js");
|
Script.include("/~/system/libraries/Xform.js");
|
||||||
|
|
||||||
//
|
//
|
||||||
// add lines where the hand ray picking is happening
|
// add lines where the hand ray picking is happening
|
||||||
|
@ -33,6 +33,8 @@ var TRIGGER_ON_VALUE = 0.4; // Squeezed just enough to activate search or near
|
||||||
var TRIGGER_GRAB_VALUE = 0.85; // Squeezed far enough to complete distant grab
|
var TRIGGER_GRAB_VALUE = 0.85; // Squeezed far enough to complete distant grab
|
||||||
var TRIGGER_OFF_VALUE = 0.15;
|
var TRIGGER_OFF_VALUE = 0.15;
|
||||||
|
|
||||||
|
var COLLIDE_WITH_AV_AFTER_RELEASE_DELAY = 0.25; // seconds
|
||||||
|
|
||||||
var BUMPER_ON_VALUE = 0.5;
|
var BUMPER_ON_VALUE = 0.5;
|
||||||
|
|
||||||
var THUMB_ON_VALUE = 0.5;
|
var THUMB_ON_VALUE = 0.5;
|
||||||
|
@ -179,6 +181,10 @@ var COLLIDES_WITH_WHILE_MULTI_GRABBED = "dynamic";
|
||||||
var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC;
|
var HEART_BEAT_INTERVAL = 5 * MSECS_PER_SEC;
|
||||||
var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC;
|
var HEART_BEAT_TIMEOUT = 15 * MSECS_PER_SEC;
|
||||||
|
|
||||||
|
var delayedDeactivateFunc;
|
||||||
|
var delayedDeactivateTimeout;
|
||||||
|
var delayedDeactivateEntityID;
|
||||||
|
|
||||||
var CONTROLLER_STATE_MACHINE = {};
|
var CONTROLLER_STATE_MACHINE = {};
|
||||||
|
|
||||||
CONTROLLER_STATE_MACHINE[STATE_OFF] = {
|
CONTROLLER_STATE_MACHINE[STATE_OFF] = {
|
||||||
|
@ -263,6 +269,17 @@ function propsArePhysical(props) {
|
||||||
return isPhysical;
|
return isPhysical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeMyAvatarFromCollidesWith(origCollidesWith) {
|
||||||
|
var collidesWithSplit = origCollidesWith.split(",");
|
||||||
|
// remove myAvatar from the array
|
||||||
|
for (var i = collidesWithSplit.length - 1; i >= 0; i--) {
|
||||||
|
if (collidesWithSplit[i] === "myAvatar") {
|
||||||
|
collidesWithSplit.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collidesWithSplit.join();
|
||||||
|
}
|
||||||
|
|
||||||
// If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here,
|
// If another script is managing the reticle (as is done by HandControllerPointer), we should not be setting it here,
|
||||||
// and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode.
|
// and we should not be showing lasers when someone else is using the Reticle to indicate a 2D minor mode.
|
||||||
var EXTERNALLY_MANAGED_2D_MINOR_MODE = true;
|
var EXTERNALLY_MANAGED_2D_MINOR_MODE = true;
|
||||||
|
@ -2061,6 +2078,17 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
this.entityActivated = true;
|
this.entityActivated = true;
|
||||||
|
|
||||||
|
if (delayedDeactivateTimeout && delayedDeactivateEntityID == entityID) {
|
||||||
|
// we have a timeout waiting to set collisions with myAvatar back on (so that when something
|
||||||
|
// is thrown it doesn't collide with the avatar's capsule the moment it's released). We've
|
||||||
|
// regrabbed the entity before the timeout fired, so cancel the timeout, run the function now
|
||||||
|
// and adjust the grabbedProperties. This will make the saved set of properties (the ones that
|
||||||
|
// get re-instated after all the grabs have been released) be correct.
|
||||||
|
Script.clearTimeout(delayedDeactivateTimeout);
|
||||||
|
delayedDeactivateTimeout = null;
|
||||||
|
grabbedProperties["collidesWith"] = delayedDeactivateFunc();
|
||||||
|
}
|
||||||
|
|
||||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
|
|
||||||
|
@ -2128,7 +2156,27 @@ function MyController(hand) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.deactivateEntity = function (entityID, noVelocity) {
|
this.delayedDeactivateEntity = function (entityID, collidesWith) {
|
||||||
|
// If, before the grab started, the held entity collided with myAvatar, we do the deactivation in
|
||||||
|
// two parts. Most of it is done in deactivateEntity(), but the final collidesWith and refcount
|
||||||
|
// are delayed a bit. This keeps thrown things from colliding with the avatar's capsule so often.
|
||||||
|
// The refcount is handled in this delayed fashion so things don't get confused if someone else
|
||||||
|
// grabs the entity before the timeout fires.
|
||||||
|
Entities.editEntity(entityID, { collidesWith: collidesWith });
|
||||||
|
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||||
|
if (data && data["refCount"]) {
|
||||||
|
data["refCount"] = data["refCount"] - 1;
|
||||||
|
if (data["refCount"] < 1) {
|
||||||
|
data = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.deactivateEntity = function (entityID, noVelocity, delayed) {
|
||||||
var deactiveProps;
|
var deactiveProps;
|
||||||
|
|
||||||
if (!this.entityActivated) {
|
if (!this.entityActivated) {
|
||||||
|
@ -2137,18 +2185,37 @@ function MyController(hand) {
|
||||||
this.entityActivated = false;
|
this.entityActivated = false;
|
||||||
|
|
||||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||||
|
var doDelayedDeactivate = false;
|
||||||
if (data && data["refCount"]) {
|
if (data && data["refCount"]) {
|
||||||
data["refCount"] = data["refCount"] - 1;
|
data["refCount"] = data["refCount"] - 1;
|
||||||
if (data["refCount"] < 1) {
|
if (data["refCount"] < 1) {
|
||||||
deactiveProps = {
|
deactiveProps = {
|
||||||
gravity: data["gravity"],
|
gravity: data["gravity"],
|
||||||
collidesWith: data["collidesWith"],
|
// don't set collidesWith myAvatar back right away, because thrown things tend to bounce off the
|
||||||
|
// avatar's capsule.
|
||||||
|
collidesWith: removeMyAvatarFromCollidesWith(data["collidesWith"]),
|
||||||
collisionless: data["collisionless"],
|
collisionless: data["collisionless"],
|
||||||
dynamic: data["dynamic"],
|
dynamic: data["dynamic"],
|
||||||
parentID: data["parentID"],
|
parentID: data["parentID"],
|
||||||
parentJointIndex: data["parentJointIndex"]
|
parentJointIndex: data["parentJointIndex"]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
doDelayedDeactivate = (data["collidesWith"].indexOf("myAvatar") >= 0);
|
||||||
|
|
||||||
|
if (doDelayedDeactivate) {
|
||||||
|
var delayedCollidesWith = data["collidesWith"];
|
||||||
|
var delayedEntityID = entityID;
|
||||||
|
delayedDeactivateFunc = function () {
|
||||||
|
// set collidesWith back to original value a bit later than the rest
|
||||||
|
delayedDeactivateTimeout = null;
|
||||||
|
_this.delayedDeactivateEntity(delayedEntityID, delayedCollidesWith);
|
||||||
|
return delayedCollidesWith;
|
||||||
|
}
|
||||||
|
delayedDeactivateTimeout =
|
||||||
|
Script.setTimeout(delayedDeactivateFunc, COLLIDE_WITH_AV_AFTER_RELEASE_DELAY * MSECS_PER_SEC);
|
||||||
|
delayedDeactivateEntityID = entityID;
|
||||||
|
}
|
||||||
|
|
||||||
// things that are held by parenting and dropped with no velocity will end up as "static" in bullet. If
|
// things that are held by parenting and dropped with no velocity will end up as "static" in bullet. If
|
||||||
// it looks like the dropped thing should fall, give it a little velocity.
|
// it looks like the dropped thing should fall, give it a little velocity.
|
||||||
var props = Entities.getEntityProperties(entityID, ["parentID", "velocity", "dynamic", "shapeType"]);
|
var props = Entities.getEntityProperties(entityID, ["parentID", "velocity", "dynamic", "shapeType"]);
|
||||||
|
@ -2191,7 +2258,6 @@ function MyController(hand) {
|
||||||
// angularVelocity: this.currentAngularVelocity
|
// angularVelocity: this.currentAngularVelocity
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
data = null;
|
data = null;
|
||||||
} else if (this.shouldResetParentOnRelease) {
|
} else if (this.shouldResetParentOnRelease) {
|
||||||
// we parent-grabbed this from another parent grab. try to put it back where we found it.
|
// we parent-grabbed this from another parent grab. try to put it back where we found it.
|
||||||
|
@ -2210,7 +2276,9 @@ function MyController(hand) {
|
||||||
} else {
|
} else {
|
||||||
data = null;
|
data = null;
|
||||||
}
|
}
|
||||||
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
if (!doDelayedDeactivate) {
|
||||||
|
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getOtherHandController = function () {
|
this.getOtherHandController = function () {
|
||||||
|
|
Loading…
Reference in a new issue