// springAway.js // // If you attach this entity script to an object, the object will spring away from // your avatar's hands. Useful for making a beachball or basketball, because you // can bounce it on your hands. // // You can change the force applied by the script by setting userData to contain // a value 'strength', which will otherwise default to DEFAULT_STRENGTH // // Note that the use of dimensions.x as the size of the entity means that it // needs to be spherical for this to look correct. // // Copyright 2016 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 // (function(){ var UPDATE_INTERVAL_MSECS = 1000/45; // Update the spring/object at 45Hz var SETTINGS_INTERVAL_MSECS = 1000; // Periodically check user data for updates var TOO_FAR = 5.0; // If the object var DEFAULT_STRENGTH = 3.0; // How strong/stiff is the spring? var entity; var props; var checkTimer = false; var settingsTimer = false; var strength = DEFAULT_STRENGTH; var _this; var WANT_DEBUG = false; function debugPrint(string) { if (WANT_DEBUG) { print(string); } } function howFarAway(position) { return Vec3.distance(MyAvatar.position, position); } function springForce(position, center, radius) { // // Return a vector corresponding to a normalized spring force ranging from 1 at // exact center to zero at distance radius from center. // var distance = Vec3.distance(position, center); return Vec3.multiply(1.0 - distance / radius, Vec3.normalize(Vec3.subtract(center, position))); } function fingerPosition(which) { // // Get the worldspace position of either the tip of the index finger (jointName "RightHandIndex3", etc), or // fall back to the controller position if that doesn't exist. // var joint = MyAvatar.getJointPosition(which === "RIGHT" ? "RightHandIndex3" : "LeftHandIndex3"); if (Vec3.length(joint) > 0) { return joint; } else { return Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getPoseValue(which === "RIGHT" ? Controller.Standard.RightHand : Controller.Standard.LeftHand).translation)); } } this.preload = function(entityID) { // Load the sound and range from the entity userData fields, and note the position of the entity. debugPrint("springAway preload"); entity = entityID; _this = this; checkTimer = Script.setInterval(this.maybePush, UPDATE_INTERVAL_MSECS); settingsTimer = Script.setInterval(this.checkSettings, SETTINGS_INTERVAL_MSECS); }; this.maybePush = function() { props = Entities.getEntityProperties(entity, [ "position", "dimensions", "velocity" ]); // First, check if the entity is far enough away to not need to do anything with it if (howFarAway(props.position) - props.dimensions.x / 2 > TOO_FAR) { return; } var rightFingerPosition = fingerPosition("RIGHT"); var leftFingerPosition = fingerPosition("LEFT"); var addVelocity = { x: 0, y: 0, z: 0 }; if (Vec3.distance(leftFingerPosition, props.position) < props.dimensions.x / 2) { addVelocity = Vec3.sum(addVelocity, Vec3.multiply(springForce(leftFingerPosition, props.position, props.dimensions.x), strength)); } if (Vec3.distance(rightFingerPosition, props.position) < props.dimensions.x / 2) { addVelocity = Vec3.sum(addVelocity, Vec3.multiply(springForce(rightFingerPosition, props.position, props.dimensions.x), strength)); } if (Vec3.length(addVelocity) > 0) { Entities.editEntity(entity, { velocity: Vec3.sum(props.velocity, addVelocity) }); } } this.checkSettings = function() { var dataProps = Entities.getEntityProperties(entity, [ "userData" ]); if (dataProps.userData) { var data = JSON.parse(dataProps.userData); if (data.strength) { if (!(strength === data.strength)) { debugPrint("Read new spring strength: " + data.strength); } strength = data.strength; } } } this.unload = function(entityID) { debugPrint("springAway unload"); if (checkTimer) { Script.clearInterval(checkTimer); } if (settingsTimer) { Script.clearInterval(settingsTimer); } }; })