mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 19:29:47 +02:00
Merge pull request #5088 from sethalves/actions
spring action with rotation and position target, rework grab script to use it
This commit is contained in:
commit
a3c5ea1b58
22 changed files with 840 additions and 126 deletions
|
@ -4,7 +4,7 @@
|
||||||
// Created by Eric Levin on May 1, 2015
|
// Created by Eric Levin on May 1, 2015
|
||||||
// Copyright 2015 High Fidelity, Inc.
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
// Grab's physically moveable entities with the mouse, by applying a spring force.
|
// Grab's physically moveable entities with the mouse, by applying a spring force.
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
@ -20,7 +20,7 @@ var ANGULAR_DAMPING_RATE = 0.40;
|
||||||
// NOTE: to improve readability global variable names start with 'g'
|
// NOTE: to improve readability global variable names start with 'g'
|
||||||
var gIsGrabbing = false;
|
var gIsGrabbing = false;
|
||||||
var gGrabbedEntity = null;
|
var gGrabbedEntity = null;
|
||||||
var gPrevMouse = {x: 0, y: 0};
|
var gActionID = null;
|
||||||
var gEntityProperties;
|
var gEntityProperties;
|
||||||
var gStartPosition;
|
var gStartPosition;
|
||||||
var gStartRotation;
|
var gStartRotation;
|
||||||
|
@ -31,20 +31,20 @@ var gPlaneNormal = ZERO_VEC3;
|
||||||
// gMaxGrabDistance is a function of the size of the object.
|
// gMaxGrabDistance is a function of the size of the object.
|
||||||
var gMaxGrabDistance;
|
var gMaxGrabDistance;
|
||||||
|
|
||||||
// gGrabMode defines the degrees of freedom of the grab target positions
|
// gGrabMode defines the degrees of freedom of the grab target positions
|
||||||
// relative to gGrabStartPosition options include:
|
// relative to gGrabStartPosition options include:
|
||||||
// xzPlane (default)
|
// xzPlane (default)
|
||||||
// verticalCylinder (SHIFT)
|
// verticalCylinder (SHIFT)
|
||||||
// rotate (CONTROL)
|
// rotate (CONTROL)
|
||||||
// Modes to eventually support?:
|
// Modes to eventually support?:
|
||||||
// xyPlane
|
// xyPlane
|
||||||
// yzPlane
|
// yzPlane
|
||||||
// polar
|
// polar
|
||||||
// elevationAzimuth
|
// elevationAzimuth
|
||||||
var gGrabMode = "xzplane";
|
var gGrabMode = "xzplane";
|
||||||
|
|
||||||
// gGrabOffset allows the user to grab an object off-center. It points from ray's intersection
|
// gGrabOffset allows the user to grab an object off-center. It points from ray's intersection
|
||||||
// with the move-plane to object center (at the moment the grab is initiated). Future target positions
|
// with the move-plane to object center (at the moment the grab is initiated). Future target positions
|
||||||
// are relative to the ray's intersection by the same offset.
|
// are relative to the ray's intersection by the same offset.
|
||||||
var gGrabOffset = { x: 0, y: 0, z: 0 };
|
var gGrabOffset = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
|
@ -53,13 +53,14 @@ var gTargetRotation;
|
||||||
var gLiftKey = false; // SHIFT
|
var gLiftKey = false; // SHIFT
|
||||||
var gRotateKey = false; // CONTROL
|
var gRotateKey = false; // CONTROL
|
||||||
|
|
||||||
|
var gInitialMouse = { x: 0, y: 0 };
|
||||||
var gPreviousMouse = { x: 0, y: 0 };
|
var gPreviousMouse = { x: 0, y: 0 };
|
||||||
var gMouseCursorLocation = { x: 0, y: 0 };
|
var gMouseCursorLocation = { x: 0, y: 0 };
|
||||||
var gMouseAtRotateStart = { x: 0, y: 0 };
|
var gMouseAtRotateStart = { x: 0, y: 0 };
|
||||||
|
|
||||||
var gBeaconHeight = 0.10;
|
var gBeaconHeight = 0.10;
|
||||||
|
|
||||||
var gAngularVelocity = ZERO_VEC3;
|
// var gAngularVelocity = ZERO_VEC3;
|
||||||
|
|
||||||
// TODO: play sounds again when we aren't leaking AudioInjector threads
|
// TODO: play sounds again when we aren't leaking AudioInjector threads
|
||||||
// var grabSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/CloseClamp.wav");
|
// var grabSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/CloseClamp.wav");
|
||||||
|
@ -166,7 +167,7 @@ function computeNewGrabPlane() {
|
||||||
var xzOffset = Vec3.subtract(gPointOnPlane, Camera.getPosition());
|
var xzOffset = Vec3.subtract(gPointOnPlane, Camera.getPosition());
|
||||||
xzOffset.y = 0;
|
xzOffset.y = 0;
|
||||||
gXzDistanceToGrab = Vec3.length(xzOffset);
|
gXzDistanceToGrab = Vec3.length(xzOffset);
|
||||||
|
|
||||||
if (gGrabMode !== "rotate" && maybeResetMousePosition) {
|
if (gGrabMode !== "rotate" && maybeResetMousePosition) {
|
||||||
// we reset the mouse position whenever we stop rotating
|
// we reset the mouse position whenever we stop rotating
|
||||||
Window.setCursorPosition(gMouseAtRotateStart.x, gMouseAtRotateStart.y);
|
Window.setCursorPosition(gMouseAtRotateStart.x, gMouseAtRotateStart.y);
|
||||||
|
@ -177,6 +178,7 @@ function mousePressEvent(event) {
|
||||||
if (!event.isLeftButton) {
|
if (!event.isLeftButton) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
gInitialMouse = {x: event.x, y: event.y };
|
||||||
gPreviousMouse = {x: event.x, y: event.y };
|
gPreviousMouse = {x: event.x, y: event.y };
|
||||||
|
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
@ -193,12 +195,13 @@ function mousePressEvent(event) {
|
||||||
|
|
||||||
var clickedEntity = pickResults.entityID;
|
var clickedEntity = pickResults.entityID;
|
||||||
var entityProperties = Entities.getEntityProperties(clickedEntity)
|
var entityProperties = Entities.getEntityProperties(clickedEntity)
|
||||||
var objectPosition = entityProperties.position;
|
gStartPosition = entityProperties.position;
|
||||||
|
gStartRotation = entityProperties.rotation;
|
||||||
var cameraPosition = Camera.getPosition();
|
var cameraPosition = Camera.getPosition();
|
||||||
|
|
||||||
gBeaconHeight = Vec3.length(entityProperties.dimensions);
|
gBeaconHeight = Vec3.length(entityProperties.dimensions);
|
||||||
gMaxGrabDistance = gBeaconHeight / MAX_SOLID_ANGLE;
|
gMaxGrabDistance = gBeaconHeight / MAX_SOLID_ANGLE;
|
||||||
if (Vec3.distance(objectPosition, cameraPosition) > gMaxGrabDistance) {
|
if (Vec3.distance(gStartPosition, cameraPosition) > gMaxGrabDistance) {
|
||||||
// don't allow grabs of things far away
|
// don't allow grabs of things far away
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -209,20 +212,20 @@ function mousePressEvent(event) {
|
||||||
gGrabbedEntity = clickedEntity;
|
gGrabbedEntity = clickedEntity;
|
||||||
gCurrentPosition = entityProperties.position;
|
gCurrentPosition = entityProperties.position;
|
||||||
gOriginalGravity = entityProperties.gravity;
|
gOriginalGravity = entityProperties.gravity;
|
||||||
gTargetPosition = objectPosition;
|
gTargetPosition = gStartPosition;
|
||||||
|
|
||||||
// compute the grab point
|
// compute the grab point
|
||||||
var nearestPoint = Vec3.subtract(objectPosition, cameraPosition);
|
var nearestPoint = Vec3.subtract(gStartPosition, cameraPosition);
|
||||||
var distanceToGrab = Vec3.dot(nearestPoint, pickRay.direction);
|
var distanceToGrab = Vec3.dot(nearestPoint, pickRay.direction);
|
||||||
nearestPoint = Vec3.multiply(distanceToGrab, pickRay.direction);
|
nearestPoint = Vec3.multiply(distanceToGrab, pickRay.direction);
|
||||||
gPointOnPlane = Vec3.sum(cameraPosition, nearestPoint);
|
gPointOnPlane = Vec3.sum(cameraPosition, nearestPoint);
|
||||||
|
|
||||||
// compute the grab offset
|
// compute the grab offset
|
||||||
gGrabOffset = Vec3.subtract(objectPosition, gPointOnPlane);
|
gGrabOffset = Vec3.subtract(gStartPosition, gPointOnPlane);
|
||||||
|
|
||||||
computeNewGrabPlane();
|
computeNewGrabPlane();
|
||||||
|
|
||||||
updateDropLine(objectPosition);
|
updateDropLine(gStartPosition);
|
||||||
|
|
||||||
// TODO: play sounds again when we aren't leaking AudioInjector threads
|
// TODO: play sounds again when we aren't leaking AudioInjector threads
|
||||||
//Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME });
|
//Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME });
|
||||||
|
@ -235,6 +238,8 @@ function mouseReleaseEvent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
gIsGrabbing = false
|
gIsGrabbing = false
|
||||||
|
Entities.deleteAction(gGrabbedEntity, gActionID);
|
||||||
|
gActionID = null;
|
||||||
|
|
||||||
Overlays.editOverlay(gBeacon, { visible: false });
|
Overlays.editOverlay(gBeacon, { visible: false });
|
||||||
|
|
||||||
|
@ -254,18 +259,24 @@ function mouseMoveEvent(event) {
|
||||||
gOriginalGravity = entityProperties.gravity;
|
gOriginalGravity = entityProperties.gravity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var actionArgs = {};
|
||||||
|
|
||||||
if (gGrabMode === "rotate") {
|
if (gGrabMode === "rotate") {
|
||||||
var deltaMouse = { x: 0, y: 0 };
|
var deltaMouse = { x: 0, y: 0 };
|
||||||
var dx = event.x - gPreviousMouse.x;
|
var dx = event.x - gInitialMouse.x;
|
||||||
var dy = event.y - gPreviousMouse.y;
|
var dy = event.y - gInitialMouse.y;
|
||||||
|
|
||||||
var orientation = Camera.getOrientation();
|
var orientation = Camera.getOrientation();
|
||||||
var dragOffset = Vec3.multiply(dx, Quat.getRight(orientation));
|
var dragOffset = Vec3.multiply(dx, Quat.getRight(orientation));
|
||||||
dragOffset = Vec3.sum(dragOffset, Vec3.multiply(-dy, Quat.getUp(orientation)));
|
dragOffset = Vec3.sum(dragOffset, Vec3.multiply(-dy, Quat.getUp(orientation)));
|
||||||
var axis = Vec3.cross(dragOffset, Quat.getFront(orientation));
|
var axis = Vec3.cross(dragOffset, Quat.getFront(orientation));
|
||||||
var axis = Vec3.normalize(axis);
|
axis = Vec3.normalize(axis);
|
||||||
var ROTATE_STRENGTH = 8.0; // magic number tuned by hand
|
var ROTATE_STRENGTH = 0.4; // magic number tuned by hand
|
||||||
gAngularVelocity = Vec3.multiply(ROTATE_STRENGTH, axis);
|
var angle = ROTATE_STRENGTH * Math.sqrt((dx * dx) + (dy * dy));
|
||||||
|
var deltaQ = Quat.angleAxis(angle, axis);
|
||||||
|
// var qZero = entityProperties.rotation;
|
||||||
|
var qZero = gStartRotation;
|
||||||
|
var qOne = Quat.multiply(deltaQ, qZero);
|
||||||
|
actionArgs = {targetRotation: qOne, angularTimeScale: 0.1};
|
||||||
} else {
|
} else {
|
||||||
var newTargetPosition;
|
var newTargetPosition;
|
||||||
if (gGrabMode === "verticalCylinder") {
|
if (gGrabMode === "verticalCylinder") {
|
||||||
|
@ -288,9 +299,18 @@ function mouseMoveEvent(event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gTargetPosition = Vec3.sum(newTargetPosition, gGrabOffset);
|
gTargetPosition = Vec3.sum(newTargetPosition, gGrabOffset);
|
||||||
|
actionArgs = {targetPosition: gTargetPosition, linearTimeScale: 0.1};
|
||||||
}
|
}
|
||||||
gPreviousMouse = { x: event.x, y: event.y };
|
gPreviousMouse = { x: event.x, y: event.y };
|
||||||
gMouseCursorLocation = { x: Window.getCursorPositionX(), y: Window.getCursorPositionY() };
|
gMouseCursorLocation = { x: Window.getCursorPositionX(), y: Window.getCursorPositionY() };
|
||||||
|
|
||||||
|
if (!gActionID) {
|
||||||
|
gActionID = Entities.addAction("spring", gGrabbedEntity, actionArgs);
|
||||||
|
} else {
|
||||||
|
Entities.updateAction(gGrabbedEntity, gActionID, actionArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDropLine(gTargetPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
function keyReleaseEvent(event) {
|
function keyReleaseEvent(event) {
|
||||||
|
@ -313,38 +333,8 @@ function keyPressEvent(event) {
|
||||||
computeNewGrabPlane();
|
computeNewGrabPlane();
|
||||||
}
|
}
|
||||||
|
|
||||||
function update(deltaTime) {
|
|
||||||
if (!gIsGrabbing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var entityProperties = Entities.getEntityProperties(gGrabbedEntity);
|
|
||||||
gCurrentPosition = entityProperties.position;
|
|
||||||
if (gGrabMode === "rotate") {
|
|
||||||
gAngularVelocity = Vec3.subtract(gAngularVelocity, Vec3.multiply(gAngularVelocity, ANGULAR_DAMPING_RATE));
|
|
||||||
Entities.editEntity(gGrabbedEntity, { angularVelocity: gAngularVelocity, });
|
|
||||||
}
|
|
||||||
|
|
||||||
// always push toward linear grab position, even when rotating
|
|
||||||
var newVelocity = ZERO_VEC3;
|
|
||||||
var dPosition = Vec3.subtract(gTargetPosition, gCurrentPosition);
|
|
||||||
var delta = Vec3.length(dPosition);
|
|
||||||
if (delta > CLOSE_ENOUGH) {
|
|
||||||
var MAX_POSITION_DELTA = 4.0;
|
|
||||||
if (delta > MAX_POSITION_DELTA) {
|
|
||||||
dPosition = Vec3.multiply(dPosition, MAX_POSITION_DELTA / delta);
|
|
||||||
}
|
|
||||||
// desired speed is proportional to displacement by the inverse of timescale
|
|
||||||
// (for critically damped motion)
|
|
||||||
newVelocity = Vec3.multiply(dPosition, INV_MOVE_TIMESCALE);
|
|
||||||
}
|
|
||||||
Entities.editEntity(gGrabbedEntity, { velocity: newVelocity, });
|
|
||||||
updateDropLine(gTargetPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||||
Controller.mousePressEvent.connect(mousePressEvent);
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||||
Controller.keyPressEvent.connect(keyPressEvent);
|
Controller.keyPressEvent.connect(keyPressEvent);
|
||||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||||
Script.update.connect(update);
|
|
||||||
|
|
92
examples/stick.js
Normal file
92
examples/stick.js
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
// stick.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2015-6-10
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Allow avatar to hold a stick
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var hand = "left";
|
||||||
|
var nullActionID = "00000000-0000-0000-0000-000000000000";
|
||||||
|
var controllerID;
|
||||||
|
var controllerActive;
|
||||||
|
var stickID = null;
|
||||||
|
var actionID = nullActionID;
|
||||||
|
// sometimes if this is run immediately the stick doesn't get created? use a timer.
|
||||||
|
Script.setTimeout(function() {
|
||||||
|
stickID = Entities.addEntity({
|
||||||
|
type: "Model",
|
||||||
|
modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx",
|
||||||
|
compoundShapeURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.obj",
|
||||||
|
dimensions: {x: .11, y: .11, z: .59},
|
||||||
|
position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close
|
||||||
|
rotation: MyAvatar.orientation,
|
||||||
|
damping: .1,
|
||||||
|
collisionsWillMove: true
|
||||||
|
});
|
||||||
|
actionID = Entities.addAction("hold", stickID, {relativePosition: {x: 0.0, y: 0.0, z: -0.9},
|
||||||
|
hand: hand,
|
||||||
|
timeScale: 0.15});
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
|
||||||
|
function cleanUp() {
|
||||||
|
Entities.deleteEntity(stickID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function positionStick(stickOrientation) {
|
||||||
|
var baseOffset = {x: 0.0, y: 0.0, z: -0.9};
|
||||||
|
var offset = Vec3.multiplyQbyV(stickOrientation, baseOffset);
|
||||||
|
Entities.updateAction(stickID, actionID, {relativePosition: offset,
|
||||||
|
relativeRotation: stickOrientation});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function mouseMoveEvent(event) {
|
||||||
|
if (!stickID || actionID == nullActionID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var windowCenterX = Window.innerWidth / 2;
|
||||||
|
var windowCenterY = Window.innerHeight / 2;
|
||||||
|
var mouseXCenterOffset = event.x - windowCenterX;
|
||||||
|
var mouseYCenterOffset = event.y - windowCenterY;
|
||||||
|
var mouseXRatio = mouseXCenterOffset / windowCenterX;
|
||||||
|
var mouseYRatio = mouseYCenterOffset / windowCenterY;
|
||||||
|
|
||||||
|
var stickOrientation = Quat.fromPitchYawRollDegrees(mouseYRatio * -90, mouseXRatio * -90, 0);
|
||||||
|
positionStick(stickOrientation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function initControls(){
|
||||||
|
if (hand == "right") {
|
||||||
|
controllerID = 3; // right handed
|
||||||
|
} else {
|
||||||
|
controllerID = 4; // left handed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function update(deltaTime){
|
||||||
|
var palmPosition = Controller.getSpatialControlPosition(controllerID);
|
||||||
|
controllerActive = (Vec3.length(palmPosition) > 0);
|
||||||
|
if(!controllerActive){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stickOrientation = Controller.getSpatialControlRawRotation(controllerID);
|
||||||
|
var adjustment = Quat.fromPitchYawRollDegrees(180, 0, 0);
|
||||||
|
stickOrientation = Quat.multiply(stickOrientation, adjustment);
|
||||||
|
|
||||||
|
positionStick(stickOrientation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(cleanUp);
|
||||||
|
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||||
|
Script.update.connect(update);
|
|
@ -100,6 +100,7 @@
|
||||||
#include "ModelPackager.h"
|
#include "ModelPackager.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "InterfaceLogging.h"
|
#include "InterfaceLogging.h"
|
||||||
|
#include "InterfaceActionFactory.h"
|
||||||
|
|
||||||
#include "avatar/AvatarManager.h"
|
#include "avatar/AvatarManager.h"
|
||||||
|
|
||||||
|
@ -257,6 +258,7 @@ bool setupEssentials(int& argc, char** argv) {
|
||||||
|
|
||||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||||
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
|
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
|
||||||
|
DependencyManager::registerInheritance<EntityActionFactoryInterface, InterfaceActionFactory>();
|
||||||
|
|
||||||
Setting::init();
|
Setting::init();
|
||||||
|
|
||||||
|
@ -293,7 +295,8 @@ bool setupEssentials(int& argc, char** argv) {
|
||||||
auto discoverabilityManager = DependencyManager::set<DiscoverabilityManager>();
|
auto discoverabilityManager = DependencyManager::set<DiscoverabilityManager>();
|
||||||
auto sceneScriptingInterface = DependencyManager::set<SceneScriptingInterface>();
|
auto sceneScriptingInterface = DependencyManager::set<SceneScriptingInterface>();
|
||||||
auto offscreenUi = DependencyManager::set<OffscreenUi>();
|
auto offscreenUi = DependencyManager::set<OffscreenUi>();
|
||||||
auto pathUtils = DependencyManager::set<PathUtils>();
|
auto pathUtils = DependencyManager::set<PathUtils>();
|
||||||
|
auto actionFactory = DependencyManager::set<InterfaceActionFactory>();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
49
interface/src/InterfaceActionFactory.cpp
Normal file
49
interface/src/InterfaceActionFactory.cpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
//
|
||||||
|
// InterfaceActionFactory.cpp
|
||||||
|
// libraries/entities/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2015-6-2
|
||||||
|
// 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 <avatar/AvatarActionHold.h>
|
||||||
|
#include <ObjectActionPullToPoint.h>
|
||||||
|
#include <ObjectActionSpring.h>
|
||||||
|
|
||||||
|
#include "InterfaceActionFactory.h"
|
||||||
|
|
||||||
|
|
||||||
|
EntityActionPointer InterfaceActionFactory::factory(EntitySimulation* simulation,
|
||||||
|
EntityActionType type,
|
||||||
|
QUuid id,
|
||||||
|
EntityItemPointer ownerEntity,
|
||||||
|
QVariantMap arguments) {
|
||||||
|
EntityActionPointer action = nullptr;
|
||||||
|
switch (type) {
|
||||||
|
case ACTION_TYPE_NONE:
|
||||||
|
return nullptr;
|
||||||
|
case ACTION_TYPE_PULL_TO_POINT:
|
||||||
|
action = (EntityActionPointer) new ObjectActionPullToPoint(id, ownerEntity);
|
||||||
|
break;
|
||||||
|
case ACTION_TYPE_SPRING:
|
||||||
|
action = (EntityActionPointer) new ObjectActionSpring(id, ownerEntity);
|
||||||
|
break;
|
||||||
|
case ACTION_TYPE_HOLD:
|
||||||
|
action = (EntityActionPointer) new AvatarActionHold(id, ownerEntity);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = action->updateArguments(arguments);
|
||||||
|
if (ok) {
|
||||||
|
ownerEntity->addAction(simulation, action);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
action = nullptr;
|
||||||
|
return action;
|
||||||
|
}
|
28
interface/src/InterfaceActionFactory.h
Normal file
28
interface/src/InterfaceActionFactory.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// InterfaceActionFactory.cpp
|
||||||
|
// interface/src/
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2015-6-10
|
||||||
|
// 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_InterfaceActionFactory_h
|
||||||
|
#define hifi_InterfaceActionFactory_h
|
||||||
|
|
||||||
|
#include "EntityActionFactoryInterface.h"
|
||||||
|
|
||||||
|
class InterfaceActionFactory : public EntityActionFactoryInterface {
|
||||||
|
public:
|
||||||
|
InterfaceActionFactory() : EntityActionFactoryInterface() { }
|
||||||
|
virtual ~InterfaceActionFactory() { }
|
||||||
|
virtual EntityActionPointer factory(EntitySimulation* simulation,
|
||||||
|
EntityActionType type,
|
||||||
|
QUuid id,
|
||||||
|
EntityItemPointer ownerEntity,
|
||||||
|
QVariantMap arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_InterfaceActionFactory_h
|
108
interface/src/avatar/AvatarActionHold.cpp
Normal file
108
interface/src/avatar/AvatarActionHold.cpp
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
//
|
||||||
|
// AvatarActionHold.cpp
|
||||||
|
// interface/src/avatar/
|
||||||
|
//
|
||||||
|
// Created by Seth Alves 2015-6-9
|
||||||
|
// 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 "avatar/MyAvatar.h"
|
||||||
|
#include "avatar/AvatarManager.h"
|
||||||
|
|
||||||
|
#include "AvatarActionHold.h"
|
||||||
|
|
||||||
|
AvatarActionHold::AvatarActionHold(QUuid id, EntityItemPointer ownerEntity) :
|
||||||
|
ObjectActionSpring(id, ownerEntity) {
|
||||||
|
#if WANT_DEBUG
|
||||||
|
qDebug() << "AvatarActionHold::AvatarActionHold";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
AvatarActionHold::~AvatarActionHold() {
|
||||||
|
#if WANT_DEBUG
|
||||||
|
qDebug() << "AvatarActionHold::~AvatarActionHold";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
|
||||||
|
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
|
glm::vec3 palmPosition;
|
||||||
|
if (_hand == "right") {
|
||||||
|
palmPosition = myAvatar->getRightPalmPosition();
|
||||||
|
} else {
|
||||||
|
palmPosition = myAvatar->getLeftPalmPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rotation = myAvatar->getWorldAlignedOrientation();
|
||||||
|
auto offset = rotation * _relativePosition;
|
||||||
|
auto position = palmPosition + offset;
|
||||||
|
rotation *= _relativeRotation;
|
||||||
|
|
||||||
|
lockForWrite();
|
||||||
|
_positionalTarget = position;
|
||||||
|
_rotationalTarget = rotation;
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
ObjectActionSpring::updateActionWorker(deltaTimeStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
||||||
|
bool rPOk = true;
|
||||||
|
glm::vec3 relativePosition =
|
||||||
|
EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", rPOk, false);
|
||||||
|
bool rROk = true;
|
||||||
|
glm::quat relativeRotation =
|
||||||
|
EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", rROk, false);
|
||||||
|
bool tSOk = true;
|
||||||
|
float timeScale =
|
||||||
|
EntityActionInterface::extractFloatArgument("hold", arguments, "timeScale", tSOk, false);
|
||||||
|
bool hOk = true;
|
||||||
|
QString hand =
|
||||||
|
EntityActionInterface::extractStringArgument("hold", arguments, "hand", hOk, false);
|
||||||
|
|
||||||
|
lockForWrite();
|
||||||
|
if (rPOk) {
|
||||||
|
_relativePosition = relativePosition;
|
||||||
|
} else if (!_parametersSet) {
|
||||||
|
_relativePosition = glm::vec3(0.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rROk) {
|
||||||
|
_relativeRotation = relativeRotation;
|
||||||
|
} else if (!_parametersSet) {
|
||||||
|
_relativeRotation = glm::quat(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tSOk) {
|
||||||
|
_linearTimeScale = timeScale;
|
||||||
|
_angularTimeScale = timeScale;
|
||||||
|
} else if (!_parametersSet) {
|
||||||
|
_linearTimeScale = 0.2;
|
||||||
|
_angularTimeScale = 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hOk) {
|
||||||
|
hand = hand.toLower();
|
||||||
|
if (hand == "left") {
|
||||||
|
_hand = "left";
|
||||||
|
} else if (hand == "right") {
|
||||||
|
_hand = "right";
|
||||||
|
} else {
|
||||||
|
qDebug() << "hold action -- invalid hand argument:" << hand;
|
||||||
|
_hand = "right";
|
||||||
|
}
|
||||||
|
} else if (!_parametersSet) {
|
||||||
|
_hand = "right";
|
||||||
|
}
|
||||||
|
|
||||||
|
_parametersSet = true;
|
||||||
|
_positionalTargetSet = true;
|
||||||
|
_rotationalTargetSet = true;
|
||||||
|
_active = true;
|
||||||
|
unlock();
|
||||||
|
return true;
|
||||||
|
}
|
35
interface/src/avatar/AvatarActionHold.h
Normal file
35
interface/src/avatar/AvatarActionHold.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
//
|
||||||
|
// AvatarActionHold.h
|
||||||
|
// interface/src/avatar/
|
||||||
|
//
|
||||||
|
// Created by Seth Alves 2015-6-9
|
||||||
|
// 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_AvatarActionHold_h
|
||||||
|
#define hifi_AvatarActionHold_h
|
||||||
|
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
|
#include <EntityItem.h>
|
||||||
|
#include <ObjectActionSpring.h>
|
||||||
|
|
||||||
|
class AvatarActionHold : public ObjectActionSpring {
|
||||||
|
public:
|
||||||
|
AvatarActionHold(QUuid id, EntityItemPointer ownerEntity);
|
||||||
|
virtual ~AvatarActionHold();
|
||||||
|
|
||||||
|
virtual bool updateArguments(QVariantMap arguments);
|
||||||
|
virtual void updateActionWorker(float deltaTimeStep);
|
||||||
|
|
||||||
|
private:
|
||||||
|
glm::vec3 _relativePosition;
|
||||||
|
glm::quat _relativeRotation;
|
||||||
|
QString _hand;
|
||||||
|
bool _parametersSet = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AvatarActionHold_h
|
|
@ -1012,7 +1012,9 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
||||||
void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
|
void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
|
||||||
checkAndCallPreload(entityID);
|
checkAndCallPreload(entityID);
|
||||||
auto entity = static_cast<EntityTree*>(_tree)->findEntityByID(entityID);
|
auto entity = static_cast<EntityTree*>(_tree)->findEntityByID(entityID);
|
||||||
addEntityToScene(entity);
|
if (entity) {
|
||||||
|
addEntityToScene(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) {
|
void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) {
|
||||||
|
|
33
libraries/entities/src/EntityActionFactoryInterface.h
Normal file
33
libraries/entities/src/EntityActionFactoryInterface.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
//
|
||||||
|
// EntityActionFactoryInterface.cpp
|
||||||
|
// libraries/entities/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2015-6-2
|
||||||
|
// 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_EntityActionFactoryInterface_h
|
||||||
|
#define hifi_EntityActionFactoryInterface_h
|
||||||
|
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
|
||||||
|
#include "EntityActionInterface.h"
|
||||||
|
|
||||||
|
class EntityActionFactoryInterface : public QObject, public Dependency {
|
||||||
|
Q_OBJECT
|
||||||
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
|
public:
|
||||||
|
EntityActionFactoryInterface() { }
|
||||||
|
virtual ~EntityActionFactoryInterface() { }
|
||||||
|
virtual EntityActionPointer factory(EntitySimulation* simulation,
|
||||||
|
EntityActionType type,
|
||||||
|
QUuid id,
|
||||||
|
EntityItemPointer ownerEntity,
|
||||||
|
QVariantMap arguments) { assert(false); return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_EntityActionFactoryInterface_h
|
|
@ -22,6 +22,12 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS
|
||||||
if (normalizedActionTypeString == "pulltopoint") {
|
if (normalizedActionTypeString == "pulltopoint") {
|
||||||
return ACTION_TYPE_PULL_TO_POINT;
|
return ACTION_TYPE_PULL_TO_POINT;
|
||||||
}
|
}
|
||||||
|
if (normalizedActionTypeString == "spring") {
|
||||||
|
return ACTION_TYPE_SPRING;
|
||||||
|
}
|
||||||
|
if (normalizedActionTypeString == "hold") {
|
||||||
|
return ACTION_TYPE_HOLD;
|
||||||
|
}
|
||||||
|
|
||||||
qDebug() << "Warning -- EntityActionInterface::actionTypeFromString got unknown action-type name" << actionTypeString;
|
qDebug() << "Warning -- EntityActionInterface::actionTypeFromString got unknown action-type name" << actionTypeString;
|
||||||
return ACTION_TYPE_NONE;
|
return ACTION_TYPE_NONE;
|
||||||
|
@ -33,31 +39,37 @@ QString EntityActionInterface::actionTypeToString(EntityActionType actionType) {
|
||||||
return "none";
|
return "none";
|
||||||
case ACTION_TYPE_PULL_TO_POINT:
|
case ACTION_TYPE_PULL_TO_POINT:
|
||||||
return "pullToPoint";
|
return "pullToPoint";
|
||||||
|
case ACTION_TYPE_SPRING:
|
||||||
|
return "spring";
|
||||||
|
case ACTION_TYPE_HOLD:
|
||||||
|
return "hold";
|
||||||
}
|
}
|
||||||
assert(false);
|
assert(false);
|
||||||
return "none";
|
return "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 EntityActionInterface::extractVec3Argument(QString objectName, QVariantMap arguments,
|
glm::vec3 EntityActionInterface::extractVec3Argument(QString objectName, QVariantMap arguments,
|
||||||
QString argumentName, bool& ok) {
|
QString argumentName, bool& ok, bool required) {
|
||||||
if (!arguments.contains(argumentName)) {
|
if (!arguments.contains(argumentName)) {
|
||||||
qDebug() << objectName << "requires argument:" << argumentName;
|
if (required) {
|
||||||
|
qDebug() << objectName << "requires argument:" << argumentName;
|
||||||
|
}
|
||||||
ok = false;
|
ok = false;
|
||||||
return vec3();
|
return glm::vec3();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant resultV = arguments[argumentName];
|
QVariant resultV = arguments[argumentName];
|
||||||
if (resultV.type() != (QVariant::Type) QMetaType::QVariantMap) {
|
if (resultV.type() != (QVariant::Type) QMetaType::QVariantMap) {
|
||||||
qDebug() << objectName << "argument" << argumentName << "must be a map";
|
qDebug() << objectName << "argument" << argumentName << "must be a map";
|
||||||
ok = false;
|
ok = false;
|
||||||
return vec3();
|
return glm::vec3();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap resultVM = resultV.toMap();
|
QVariantMap resultVM = resultV.toMap();
|
||||||
if (!resultVM.contains("x") || !resultVM.contains("y") || !resultVM.contains("z")) {
|
if (!resultVM.contains("x") || !resultVM.contains("y") || !resultVM.contains("z")) {
|
||||||
qDebug() << objectName << "argument" << argumentName << "must be a map with keys of x, y, z";
|
qDebug() << objectName << "argument" << argumentName << "must be a map with keys of x, y, z";
|
||||||
ok = false;
|
ok = false;
|
||||||
return vec3();
|
return glm::vec3();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant xV = resultVM["x"];
|
QVariant xV = resultVM["x"];
|
||||||
|
@ -73,17 +85,65 @@ glm::vec3 EntityActionInterface::extractVec3Argument(QString objectName, QVarian
|
||||||
if (!xOk || !yOk || !zOk) {
|
if (!xOk || !yOk || !zOk) {
|
||||||
qDebug() << objectName << "argument" << argumentName << "must be a map with keys of x, y, z and values of type float.";
|
qDebug() << objectName << "argument" << argumentName << "must be a map with keys of x, y, z and values of type float.";
|
||||||
ok = false;
|
ok = false;
|
||||||
return vec3();
|
return glm::vec3();
|
||||||
}
|
}
|
||||||
|
|
||||||
return vec3(x, y, z);
|
return glm::vec3(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::quat EntityActionInterface::extractQuatArgument(QString objectName, QVariantMap arguments,
|
||||||
|
QString argumentName, bool& ok, bool required) {
|
||||||
|
if (!arguments.contains(argumentName)) {
|
||||||
|
if (required) {
|
||||||
|
qDebug() << objectName << "requires argument:" << argumentName;
|
||||||
|
}
|
||||||
|
ok = false;
|
||||||
|
return glm::quat();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant resultV = arguments[argumentName];
|
||||||
|
if (resultV.type() != (QVariant::Type) QMetaType::QVariantMap) {
|
||||||
|
qDebug() << objectName << "argument" << argumentName << "must be a map, not" << resultV.typeName();
|
||||||
|
ok = false;
|
||||||
|
return glm::quat();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap resultVM = resultV.toMap();
|
||||||
|
if (!resultVM.contains("x") || !resultVM.contains("y") || !resultVM.contains("z")) {
|
||||||
|
qDebug() << objectName << "argument" << argumentName << "must be a map with keys of x, y, z";
|
||||||
|
ok = false;
|
||||||
|
return glm::quat();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant xV = resultVM["x"];
|
||||||
|
QVariant yV = resultVM["y"];
|
||||||
|
QVariant zV = resultVM["z"];
|
||||||
|
QVariant wV = resultVM["w"];
|
||||||
|
|
||||||
|
bool xOk = true;
|
||||||
|
bool yOk = true;
|
||||||
|
bool zOk = true;
|
||||||
|
bool wOk = true;
|
||||||
|
float x = xV.toFloat(&xOk);
|
||||||
|
float y = yV.toFloat(&yOk);
|
||||||
|
float z = zV.toFloat(&zOk);
|
||||||
|
float w = wV.toFloat(&wOk);
|
||||||
|
if (!xOk || !yOk || !zOk || !wOk) {
|
||||||
|
qDebug() << objectName << "argument" << argumentName
|
||||||
|
<< "must be a map with keys of x, y, z, w and values of type float.";
|
||||||
|
ok = false;
|
||||||
|
return glm::quat();
|
||||||
|
}
|
||||||
|
|
||||||
|
return glm::quat(w, x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMap arguments,
|
float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMap arguments,
|
||||||
QString argumentName, bool& ok) {
|
QString argumentName, bool& ok, bool required) {
|
||||||
if (!arguments.contains(argumentName)) {
|
if (!arguments.contains(argumentName)) {
|
||||||
qDebug() << objectName << "requires argument:" << argumentName;
|
if (required) {
|
||||||
|
qDebug() << objectName << "requires argument:" << argumentName;
|
||||||
|
}
|
||||||
ok = false;
|
ok = false;
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
@ -99,3 +159,18 @@ float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMa
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString EntityActionInterface::extractStringArgument(QString objectName, QVariantMap arguments,
|
||||||
|
QString argumentName, bool& ok, bool required) {
|
||||||
|
if (!arguments.contains(argumentName)) {
|
||||||
|
if (required) {
|
||||||
|
qDebug() << objectName << "requires argument:" << argumentName;
|
||||||
|
}
|
||||||
|
ok = false;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant vV = arguments[argumentName];
|
||||||
|
QString v = vV.toString();
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
|
@ -14,12 +14,16 @@
|
||||||
|
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
|
#include "EntityItem.h"
|
||||||
|
|
||||||
class EntitySimulation;
|
class EntitySimulation;
|
||||||
|
|
||||||
enum EntityActionType {
|
enum EntityActionType {
|
||||||
// keep these synchronized with actionTypeFromString and actionTypeToString
|
// keep these synchronized with actionTypeFromString and actionTypeToString
|
||||||
ACTION_TYPE_NONE,
|
ACTION_TYPE_NONE,
|
||||||
ACTION_TYPE_PULL_TO_POINT
|
ACTION_TYPE_PULL_TO_POINT,
|
||||||
|
ACTION_TYPE_SPRING,
|
||||||
|
ACTION_TYPE_HOLD
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,18 +36,35 @@ public:
|
||||||
virtual const EntityItemPointer& getOwnerEntity() const = 0;
|
virtual const EntityItemPointer& getOwnerEntity() const = 0;
|
||||||
virtual void setOwnerEntity(const EntityItemPointer ownerEntity) = 0;
|
virtual void setOwnerEntity(const EntityItemPointer ownerEntity) = 0;
|
||||||
virtual bool updateArguments(QVariantMap arguments) = 0;
|
virtual bool updateArguments(QVariantMap arguments) = 0;
|
||||||
// virtual QByteArray serialize() = 0;
|
|
||||||
// static EntityActionPointer deserialize(EntityItemPointer ownerEntity, QByteArray data);
|
|
||||||
|
|
||||||
static EntityActionType actionTypeFromString(QString actionTypeString);
|
static EntityActionType actionTypeFromString(QString actionTypeString);
|
||||||
static QString actionTypeToString(EntityActionType actionType);
|
static QString actionTypeToString(EntityActionType actionType);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual glm::vec3 getPosition() = 0;
|
||||||
|
virtual void setPosition(glm::vec3 position) = 0;
|
||||||
|
virtual glm::quat getRotation() = 0;
|
||||||
|
virtual void setRotation(glm::quat rotation) = 0;
|
||||||
|
virtual glm::vec3 getLinearVelocity() = 0;
|
||||||
|
virtual void setLinearVelocity(glm::vec3 linearVelocity) = 0;
|
||||||
|
virtual glm::vec3 getAngularVelocity() = 0;
|
||||||
|
virtual void setAngularVelocity(glm::vec3 angularVelocity) = 0;
|
||||||
|
|
||||||
|
// these look in the arguments map for a named argument. if it's not found or isn't well formed,
|
||||||
|
// ok will be set to false (note that it's never set to true -- set it to true before calling these).
|
||||||
|
// if required is true, failure to extract an argument will cause a warning to be printed.
|
||||||
|
static glm::vec3 extractVec3Argument (QString objectName, QVariantMap arguments,
|
||||||
|
QString argumentName, bool& ok, bool required = true);
|
||||||
|
static glm::quat extractQuatArgument (QString objectName, QVariantMap arguments,
|
||||||
|
QString argumentName, bool& ok, bool required = true);
|
||||||
|
static float extractFloatArgument(QString objectName, QVariantMap arguments,
|
||||||
|
QString argumentName, bool& ok, bool required = true);
|
||||||
|
static QString extractStringArgument(QString objectName, QVariantMap arguments,
|
||||||
|
QString argumentName, bool& ok, bool required = true);
|
||||||
|
|
||||||
static glm::vec3 extractVec3Argument(QString objectName, QVariantMap arguments, QString argumentName, bool& ok);
|
|
||||||
static float extractFloatArgument(QString objectName, QVariantMap arguments, QString argumentName, bool& ok);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef std::shared_ptr<EntityActionInterface> EntityActionPointer;
|
typedef std::shared_ptr<EntityActionInterface> EntityActionPointer;
|
||||||
|
|
||||||
#endif // hifi_EntityActionInterface_h
|
#endif // hifi_EntityActionInterface_h
|
||||||
|
|
|
@ -28,13 +28,16 @@
|
||||||
#include "EntityItemID.h"
|
#include "EntityItemID.h"
|
||||||
#include "EntityItemProperties.h"
|
#include "EntityItemProperties.h"
|
||||||
#include "EntityItemPropertiesDefaults.h"
|
#include "EntityItemPropertiesDefaults.h"
|
||||||
#include "EntityActionInterface.h"
|
|
||||||
#include "EntityTypes.h"
|
#include "EntityTypes.h"
|
||||||
|
|
||||||
class EntitySimulation;
|
class EntitySimulation;
|
||||||
class EntityTreeElement;
|
class EntityTreeElement;
|
||||||
class EntityTreeElementExtraEncodeData;
|
class EntityTreeElementExtraEncodeData;
|
||||||
|
|
||||||
|
class EntityActionInterface;
|
||||||
|
typedef std::shared_ptr<EntityActionInterface> EntityActionPointer;
|
||||||
|
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
class Scene;
|
class Scene;
|
||||||
class PendingChanges;
|
class PendingChanges;
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#include "ZoneEntityItem.h"
|
#include "ZoneEntityItem.h"
|
||||||
#include "EntitiesLogging.h"
|
#include "EntitiesLogging.h"
|
||||||
#include "EntitySimulation.h"
|
#include "EntitySimulation.h"
|
||||||
|
#include "EntityActionInterface.h"
|
||||||
|
#include "EntityActionFactoryInterface.h"
|
||||||
|
|
||||||
#include "EntityScriptingInterface.h"
|
#include "EntityScriptingInterface.h"
|
||||||
|
|
||||||
|
@ -491,12 +493,19 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
|
||||||
const QUuid& entityID,
|
const QUuid& entityID,
|
||||||
const QVariantMap& arguments) {
|
const QVariantMap& arguments) {
|
||||||
QUuid actionID = QUuid::createUuid();
|
QUuid actionID = QUuid::createUuid();
|
||||||
|
auto actionFactory = DependencyManager::get<EntityActionFactoryInterface>();
|
||||||
bool success = actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) {
|
bool success = actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) {
|
||||||
|
// create this action even if the entity doesn't have physics info. it will often be the
|
||||||
|
// case that a script adds an action immediately after an object is created, and the physicsInfo
|
||||||
|
// is computed asynchronously.
|
||||||
|
// if (!entity->getPhysicsInfo()) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
EntityActionType actionType = EntityActionInterface::actionTypeFromString(actionTypeString);
|
EntityActionType actionType = EntityActionInterface::actionTypeFromString(actionTypeString);
|
||||||
if (actionType == ACTION_TYPE_NONE) {
|
if (actionType == ACTION_TYPE_NONE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (simulation->actionFactory(actionType, actionID, entity, arguments)) {
|
if (actionFactory->factory(simulation, actionType, actionID, entity, arguments)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
|
||||||
|
#include "EntityActionInterface.h"
|
||||||
#include "EntityItem.h"
|
#include "EntityItem.h"
|
||||||
#include "EntityTree.h"
|
#include "EntityTree.h"
|
||||||
|
|
||||||
|
@ -56,10 +57,6 @@ public:
|
||||||
|
|
||||||
friend class EntityTree;
|
friend class EntityTree;
|
||||||
|
|
||||||
virtual EntityActionPointer actionFactory(EntityActionType type,
|
|
||||||
QUuid id,
|
|
||||||
EntityItemPointer ownerEntity,
|
|
||||||
QVariantMap arguments) { return nullptr; }
|
|
||||||
virtual void addAction(EntityActionPointer action) { _actionsToAdd += action; }
|
virtual void addAction(EntityActionPointer action) { _actionsToAdd += action; }
|
||||||
virtual void removeAction(const QUuid actionID) { _actionsToRemove += actionID; }
|
virtual void removeAction(const QUuid actionID) { _actionsToRemove += actionID; }
|
||||||
virtual void removeActions(QList<QUuid> actionIDsToRemove) { _actionsToRemove += actionIDsToRemove; }
|
virtual void removeActions(QList<QUuid> actionIDsToRemove) { _actionsToRemove += actionIDsToRemove; }
|
||||||
|
|
|
@ -24,7 +24,14 @@ ObjectAction::~ObjectAction() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) {
|
void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) {
|
||||||
qDebug() << "ObjectAction::updateAction called";
|
if (!_active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_ownerEntity) {
|
||||||
|
qDebug() << "ObjectActionPullToPoint::updateAction no owner entity";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateActionWorker(deltaTimeStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectAction::debugDraw(btIDebugDraw* debugDrawer) {
|
void ObjectAction::debugDraw(btIDebugDraw* debugDrawer) {
|
||||||
|
@ -33,3 +40,87 @@ void ObjectAction::debugDraw(btIDebugDraw* debugDrawer) {
|
||||||
void ObjectAction::removeFromSimulation(EntitySimulation* simulation) const {
|
void ObjectAction::removeFromSimulation(EntitySimulation* simulation) const {
|
||||||
simulation->removeAction(_id);
|
simulation->removeAction(_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
btRigidBody* ObjectAction::getRigidBody() {
|
||||||
|
if (!_ownerEntity) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void* physicsInfo = _ownerEntity->getPhysicsInfo();
|
||||||
|
if (!physicsInfo) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
|
||||||
|
return motionState->getRigidBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 ObjectAction::getPosition() {
|
||||||
|
auto rigidBody = getRigidBody();
|
||||||
|
if (!rigidBody) {
|
||||||
|
return glm::vec3(0.0f);
|
||||||
|
}
|
||||||
|
return bulletToGLM(rigidBody->getCenterOfMassPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectAction::setPosition(glm::vec3 position) {
|
||||||
|
auto rigidBody = getRigidBody();
|
||||||
|
if (!rigidBody) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// XXX
|
||||||
|
// void setWorldTransform (const btTransform &worldTrans)
|
||||||
|
assert(false);
|
||||||
|
rigidBody->activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat ObjectAction::getRotation() {
|
||||||
|
auto rigidBody = getRigidBody();
|
||||||
|
if (!rigidBody) {
|
||||||
|
return glm::quat(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
return bulletToGLM(rigidBody->getOrientation());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectAction::setRotation(glm::quat rotation) {
|
||||||
|
auto rigidBody = getRigidBody();
|
||||||
|
if (!rigidBody) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// XXX
|
||||||
|
// void setWorldTransform (const btTransform &worldTrans)
|
||||||
|
assert(false);
|
||||||
|
rigidBody->activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 ObjectAction::getLinearVelocity() {
|
||||||
|
auto rigidBody = getRigidBody();
|
||||||
|
if (!rigidBody) {
|
||||||
|
return glm::vec3(0.0f);
|
||||||
|
}
|
||||||
|
return bulletToGLM(rigidBody->getLinearVelocity());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectAction::setLinearVelocity(glm::vec3 linearVelocity) {
|
||||||
|
auto rigidBody = getRigidBody();
|
||||||
|
if (!rigidBody) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rigidBody->setLinearVelocity(glmToBullet(glm::vec3(0.0f)));
|
||||||
|
rigidBody->activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 ObjectAction::getAngularVelocity() {
|
||||||
|
auto rigidBody = getRigidBody();
|
||||||
|
if (!rigidBody) {
|
||||||
|
return glm::vec3(0.0f);
|
||||||
|
}
|
||||||
|
return bulletToGLM(rigidBody->getAngularVelocity());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectAction::setAngularVelocity(glm::vec3 angularVelocity) {
|
||||||
|
auto rigidBody = getRigidBody();
|
||||||
|
if (!rigidBody) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rigidBody->setAngularVelocity(glmToBullet(angularVelocity));
|
||||||
|
rigidBody->activate();
|
||||||
|
}
|
||||||
|
|
|
@ -13,12 +13,17 @@
|
||||||
#ifndef hifi_ObjectAction_h
|
#ifndef hifi_ObjectAction_h
|
||||||
#define hifi_ObjectAction_h
|
#define hifi_ObjectAction_h
|
||||||
|
|
||||||
#include <btBulletDynamicsCommon.h>
|
|
||||||
|
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
|
#include <btBulletDynamicsCommon.h>
|
||||||
|
|
||||||
#include <EntityItem.h>
|
#include <EntityItem.h>
|
||||||
|
|
||||||
|
#include "ObjectMotionState.h"
|
||||||
|
#include "BulletUtil.h"
|
||||||
|
#include "EntityActionInterface.h"
|
||||||
|
|
||||||
|
|
||||||
class ObjectAction : public btActionInterface, public EntityActionInterface {
|
class ObjectAction : public btActionInterface, public EntityActionInterface {
|
||||||
public:
|
public:
|
||||||
ObjectAction(QUuid id, EntityItemPointer ownerEntity);
|
ObjectAction(QUuid id, EntityItemPointer ownerEntity);
|
||||||
|
@ -30,6 +35,9 @@ public:
|
||||||
virtual void setOwnerEntity(const EntityItemPointer ownerEntity) { _ownerEntity = ownerEntity; }
|
virtual void setOwnerEntity(const EntityItemPointer ownerEntity) { _ownerEntity = ownerEntity; }
|
||||||
virtual bool updateArguments(QVariantMap arguments) { return false; }
|
virtual bool updateArguments(QVariantMap arguments) { return false; }
|
||||||
|
|
||||||
|
// this is called from updateAction and should be overridden by subclasses
|
||||||
|
virtual void updateActionWorker(float deltaTimeStep) {}
|
||||||
|
|
||||||
// these are from btActionInterface
|
// these are from btActionInterface
|
||||||
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep);
|
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep);
|
||||||
virtual void debugDraw(btIDebugDraw* debugDrawer);
|
virtual void debugDraw(btIDebugDraw* debugDrawer);
|
||||||
|
@ -39,6 +47,16 @@ private:
|
||||||
QReadWriteLock _lock;
|
QReadWriteLock _lock;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual btRigidBody* getRigidBody();
|
||||||
|
virtual glm::vec3 getPosition();
|
||||||
|
virtual void setPosition(glm::vec3 position);
|
||||||
|
virtual glm::quat getRotation();
|
||||||
|
virtual void setRotation(glm::quat rotation);
|
||||||
|
virtual glm::vec3 getLinearVelocity();
|
||||||
|
virtual void setLinearVelocity(glm::vec3 linearVelocity);
|
||||||
|
virtual glm::vec3 getAngularVelocity();
|
||||||
|
virtual void setAngularVelocity(glm::vec3 angularVelocity);
|
||||||
|
|
||||||
bool tryLockForRead() { return _lock.tryLockForRead(); }
|
bool tryLockForRead() { return _lock.tryLockForRead(); }
|
||||||
void lockForWrite() { _lock.lockForWrite(); }
|
void lockForWrite() { _lock.lockForWrite(); }
|
||||||
void unlock() { _lock.unlock(); }
|
void unlock() { _lock.unlock(); }
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "ObjectMotionState.h"
|
|
||||||
#include "BulletUtil.h"
|
|
||||||
|
|
||||||
#include "ObjectActionPullToPoint.h"
|
#include "ObjectActionPullToPoint.h"
|
||||||
|
|
||||||
ObjectActionPullToPoint::ObjectActionPullToPoint(QUuid id, EntityItemPointer ownerEntity) :
|
ObjectActionPullToPoint::ObjectActionPullToPoint(QUuid id, EntityItemPointer ownerEntity) :
|
||||||
|
@ -27,28 +24,34 @@ ObjectActionPullToPoint::~ObjectActionPullToPoint() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectActionPullToPoint::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) {
|
void ObjectActionPullToPoint::updateActionWorker(btScalar deltaTimeStep) {
|
||||||
if (!tryLockForRead()) {
|
if (!tryLockForRead()) {
|
||||||
// don't risk hanging the thread running the physics simulation
|
// don't risk hanging the thread running the physics simulation
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void* physicsInfo = _ownerEntity->getPhysicsInfo();
|
|
||||||
|
|
||||||
if (_active && physicsInfo) {
|
void* physicsInfo = _ownerEntity->getPhysicsInfo();
|
||||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
|
if (!physicsInfo) {
|
||||||
btRigidBody* rigidBody = motionState->getRigidBody();
|
unlock();
|
||||||
if (rigidBody) {
|
return;
|
||||||
glm::vec3 offset = _target - bulletToGLM(rigidBody->getCenterOfMassPosition());
|
|
||||||
float offsetLength = glm::length(offset);
|
|
||||||
if (offsetLength > IGNORE_POSITION_DELTA) {
|
|
||||||
glm::vec3 newVelocity = glm::normalize(offset) * _speed;
|
|
||||||
rigidBody->setLinearVelocity(glmToBullet(newVelocity));
|
|
||||||
rigidBody->activate();
|
|
||||||
} else {
|
|
||||||
rigidBody->setLinearVelocity(glmToBullet(glm::vec3()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
|
||||||
|
btRigidBody* rigidBody = motionState->getRigidBody();
|
||||||
|
if (!rigidBody) {
|
||||||
|
unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 offset = _target - bulletToGLM(rigidBody->getCenterOfMassPosition());
|
||||||
|
float offsetLength = glm::length(offset);
|
||||||
|
if (offsetLength > IGNORE_POSITION_DELTA) {
|
||||||
|
glm::vec3 newVelocity = glm::normalize(offset) * _speed;
|
||||||
|
rigidBody->setLinearVelocity(glmToBullet(newVelocity));
|
||||||
|
rigidBody->activate();
|
||||||
|
} else {
|
||||||
|
rigidBody->setLinearVelocity(glmToBullet(glm::vec3()));
|
||||||
|
}
|
||||||
|
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ public:
|
||||||
virtual ~ObjectActionPullToPoint();
|
virtual ~ObjectActionPullToPoint();
|
||||||
|
|
||||||
virtual bool updateArguments(QVariantMap arguments);
|
virtual bool updateArguments(QVariantMap arguments);
|
||||||
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep);
|
virtual void updateActionWorker(float deltaTimeStep);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
144
libraries/physics/src/ObjectActionSpring.cpp
Normal file
144
libraries/physics/src/ObjectActionSpring.cpp
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
//
|
||||||
|
// ObjectActionSpring.cpp
|
||||||
|
// libraries/physics/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves 2015-6-5
|
||||||
|
// 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 "ObjectActionSpring.h"
|
||||||
|
|
||||||
|
ObjectActionSpring::ObjectActionSpring(QUuid id, EntityItemPointer ownerEntity) :
|
||||||
|
ObjectAction(id, ownerEntity) {
|
||||||
|
#if WANT_DEBUG
|
||||||
|
qDebug() << "ObjectActionSpring::ObjectActionSpring";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectActionSpring::~ObjectActionSpring() {
|
||||||
|
#if WANT_DEBUG
|
||||||
|
qDebug() << "ObjectActionSpring::~ObjectActionSpring";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
|
||||||
|
if (!tryLockForRead()) {
|
||||||
|
// don't risk hanging the thread running the physics simulation
|
||||||
|
qDebug() << "ObjectActionSpring::updateActionWorker lock failed";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* physicsInfo = _ownerEntity->getPhysicsInfo();
|
||||||
|
if (!physicsInfo) {
|
||||||
|
unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
|
||||||
|
btRigidBody* rigidBody = motionState->getRigidBody();
|
||||||
|
if (!rigidBody) {
|
||||||
|
unlock();
|
||||||
|
qDebug() << "ObjectActionSpring::updateActionWorker no rigidBody";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle the linear part
|
||||||
|
if (_positionalTargetSet) {
|
||||||
|
glm::vec3 offset = _positionalTarget - bulletToGLM(rigidBody->getCenterOfMassPosition());
|
||||||
|
float offsetLength = glm::length(offset);
|
||||||
|
float speed = offsetLength / _linearTimeScale;
|
||||||
|
|
||||||
|
if (offsetLength > IGNORE_POSITION_DELTA) {
|
||||||
|
glm::vec3 newVelocity = glm::normalize(offset) * speed;
|
||||||
|
rigidBody->setLinearVelocity(glmToBullet(newVelocity));
|
||||||
|
rigidBody->activate();
|
||||||
|
} else {
|
||||||
|
rigidBody->setLinearVelocity(glmToBullet(glm::vec3(0.0f)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle rotation
|
||||||
|
if (_rotationalTargetSet) {
|
||||||
|
glm::quat bodyRotation = bulletToGLM(rigidBody->getOrientation());
|
||||||
|
// if qZero and qOne are too close to each other, we can get NaN for angle.
|
||||||
|
auto alignmentDot = glm::dot(bodyRotation, _rotationalTarget);
|
||||||
|
const float almostOne = 0.99999f;
|
||||||
|
if (glm::abs(alignmentDot) < almostOne) {
|
||||||
|
glm::quat target = _rotationalTarget;
|
||||||
|
if (alignmentDot < 0) {
|
||||||
|
target = -target;
|
||||||
|
}
|
||||||
|
glm::quat qZeroInverse = glm::inverse(bodyRotation);
|
||||||
|
glm::quat deltaQ = target * qZeroInverse;
|
||||||
|
glm::vec3 axis = glm::axis(deltaQ);
|
||||||
|
float angle = glm::angle(deltaQ);
|
||||||
|
assert(!isNaN(angle));
|
||||||
|
glm::vec3 newAngularVelocity = (angle / _angularTimeScale) * glm::normalize(axis);
|
||||||
|
rigidBody->setAngularVelocity(glmToBullet(newAngularVelocity));
|
||||||
|
rigidBody->activate();
|
||||||
|
} else {
|
||||||
|
rigidBody->setAngularVelocity(glmToBullet(glm::vec3(0.0f)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
|
||||||
|
// targets are required, spring-constants are optional
|
||||||
|
bool ptOk = true;
|
||||||
|
glm::vec3 positionalTarget =
|
||||||
|
EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ptOk, false);
|
||||||
|
bool pscOk = true;
|
||||||
|
float linearTimeScale =
|
||||||
|
EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", pscOk, false);
|
||||||
|
if (ptOk && pscOk && linearTimeScale <= 0.0f) {
|
||||||
|
qDebug() << "spring action -- linearTimeScale must be greater than zero.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rtOk = true;
|
||||||
|
glm::quat rotationalTarget =
|
||||||
|
EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", rtOk, false);
|
||||||
|
bool rscOk = true;
|
||||||
|
float angularTimeScale =
|
||||||
|
EntityActionInterface::extractFloatArgument("spring action", arguments, "angularTimeScale", rscOk, false);
|
||||||
|
|
||||||
|
if (!ptOk && !rtOk) {
|
||||||
|
qDebug() << "spring action requires either targetPosition or targetRotation argument";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lockForWrite();
|
||||||
|
|
||||||
|
_positionalTargetSet = _rotationalTargetSet = false;
|
||||||
|
|
||||||
|
if (ptOk) {
|
||||||
|
_positionalTarget = positionalTarget;
|
||||||
|
_positionalTargetSet = true;
|
||||||
|
|
||||||
|
if (pscOk) {
|
||||||
|
_linearTimeScale = linearTimeScale;
|
||||||
|
} else {
|
||||||
|
_linearTimeScale = 0.1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtOk) {
|
||||||
|
_rotationalTarget = rotationalTarget;
|
||||||
|
_rotationalTargetSet = true;
|
||||||
|
|
||||||
|
if (rscOk) {
|
||||||
|
_angularTimeScale = angularTimeScale;
|
||||||
|
} else {
|
||||||
|
_angularTimeScale = 0.1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_active = true;
|
||||||
|
unlock();
|
||||||
|
return true;
|
||||||
|
}
|
39
libraries/physics/src/ObjectActionSpring.h
Normal file
39
libraries/physics/src/ObjectActionSpring.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
//
|
||||||
|
// ObjectActionSpring.h
|
||||||
|
// libraries/physics/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves 2015-6-5
|
||||||
|
// 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_ObjectActionSpring_h
|
||||||
|
#define hifi_ObjectActionSpring_h
|
||||||
|
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
|
#include <EntityItem.h>
|
||||||
|
#include "ObjectAction.h"
|
||||||
|
|
||||||
|
class ObjectActionSpring : public ObjectAction {
|
||||||
|
public:
|
||||||
|
ObjectActionSpring(QUuid id, EntityItemPointer ownerEntity);
|
||||||
|
virtual ~ObjectActionSpring();
|
||||||
|
|
||||||
|
virtual bool updateArguments(QVariantMap arguments);
|
||||||
|
virtual void updateActionWorker(float deltaTimeStep);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
glm::vec3 _positionalTarget;
|
||||||
|
float _linearTimeScale;
|
||||||
|
bool _positionalTargetSet;
|
||||||
|
|
||||||
|
glm::quat _rotationalTarget;
|
||||||
|
float _angularTimeScale;
|
||||||
|
bool _rotationalTargetSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_ObjectActionSpring_h
|
|
@ -9,10 +9,11 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "PhysicsHelpers.h"
|
#include "PhysicsHelpers.h"
|
||||||
#include "PhysicsLogging.h"
|
#include "PhysicsLogging.h"
|
||||||
#include "ShapeManager.h"
|
#include "ShapeManager.h"
|
||||||
#include "ObjectActionPullToPoint.h"
|
|
||||||
|
|
||||||
#include "PhysicalEntitySimulation.h"
|
#include "PhysicalEntitySimulation.h"
|
||||||
|
|
||||||
|
@ -234,29 +235,6 @@ void PhysicalEntitySimulation::handleCollisionEvents(CollisionEvents& collisionE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityActionPointer PhysicalEntitySimulation::actionFactory(EntityActionType type,
|
|
||||||
QUuid id,
|
|
||||||
EntityItemPointer ownerEntity,
|
|
||||||
QVariantMap arguments) {
|
|
||||||
EntityActionPointer action = nullptr;
|
|
||||||
switch (type) {
|
|
||||||
case ACTION_TYPE_NONE:
|
|
||||||
return nullptr;
|
|
||||||
case ACTION_TYPE_PULL_TO_POINT:
|
|
||||||
action = (EntityActionPointer) new ObjectActionPullToPoint(id, ownerEntity);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok = action->updateArguments(arguments);
|
|
||||||
if (ok) {
|
|
||||||
ownerEntity->addAction(this, action);
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
action = nullptr;
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicalEntitySimulation::applyActionChanges() {
|
void PhysicalEntitySimulation::applyActionChanges() {
|
||||||
if (_physicsEngine) {
|
if (_physicsEngine) {
|
||||||
foreach (EntityActionPointer actionToAdd, _actionsToAdd) {
|
foreach (EntityActionPointer actionToAdd, _actionsToAdd) {
|
||||||
|
|
|
@ -32,10 +32,6 @@ public:
|
||||||
|
|
||||||
void init(EntityTree* tree, PhysicsEngine* engine, EntityEditPacketSender* packetSender);
|
void init(EntityTree* tree, PhysicsEngine* engine, EntityEditPacketSender* packetSender);
|
||||||
|
|
||||||
virtual EntityActionPointer actionFactory(EntityActionType type,
|
|
||||||
QUuid id,
|
|
||||||
EntityItemPointer ownerEntity,
|
|
||||||
QVariantMap arguments);
|
|
||||||
virtual void applyActionChanges();
|
virtual void applyActionChanges();
|
||||||
|
|
||||||
protected: // only called by EntitySimulation
|
protected: // only called by EntitySimulation
|
||||||
|
|
Loading…
Reference in a new issue