overte/examples/toys/flashlight/flashlight.js
2015-09-18 15:26:34 -07:00

206 lines
No EOL
8 KiB
JavaScript

//
// flashlight.js
//
// Script Type: Entity
//
// Created by Sam Gateau on 9/9/15.
// Copyright 2015 High Fidelity, Inc.
//
// This is a toy script that can be added to the Flashlight model entity:
// "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx"
// that creates a spotlight attached with the flashlight model while the entity is grabbed
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// TODO: update to use new grab signals, which will include handedness.
// BONUS: dim the light with pressure instead of binary on/off
(function() {
function debugPrint(message) {
//print(message);
}
Script.include("../../libraries/utils.js");
var _this;
// this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember
// our this object, so we can access it in cases where we're called without a this (like in the case of various global signals)
Flashlight = function() {
_this = this;
_this._hasSpotlight = false;
_this._spotlight = null;
};
var DISABLE_LIGHT_THRESHOLD = 0.5;
// These constants define the Spotlight position and orientation relative to the model
var MODEL_LIGHT_POSITION = {
x: 0,
y: 0,
z: 0
};
var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, {
x: 1,
y: 0,
z: 0
});
// Evaluate the world light entity position and orientation from the model ones
function evalLightWorldTransform(modelPos, modelRot) {
return {
p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)),
q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION)
};
};
Flashlight.prototype = {
lightOn: false,
// update() will be called regulary, because we've hooked the update signal in our preload() function
// we will check out userData for the grabData. In the case of the hydraGrab script, it will tell us
// if we're currently being grabbed and if the person grabbing us is the current interfaces avatar.
// we will watch this for state changes and print out if we're being grabbed or released when it changes.
update: function() {
var GRAB_USER_DATA_KEY = "grabKey";
// because the update() signal doesn't have a valid this, we need to use our memorized _this to access our entityID
var entityID = _this.entityID;
// we want to assume that if there is no grab data, then we are not being grabbed
var defaultGrabData = {
activated: false,
avatarId: null
};
// this handy function getEntityCustomData() is available in utils.js and it will return just the specific section
// of user data we asked for. If it's not available it returns our default data.
var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, defaultGrabData);
// if the grabData says we're being grabbed, and the owner ID is our session, then we are being grabbed by this interface
if (grabData.activated && grabData.avatarId == MyAvatar.sessionUUID) {
// remember we're being grabbed so we can detect being released
_this.beingGrabbed = true;
var modelProperties = Entities.getEntityProperties(entityID);
var lightTransform = evalLightWorldTransform(modelProperties.position, modelProperties.rotation);
// Create the spot light driven by this model if we don;t have one yet
// Or make sure to keep it's position in sync
if (!_this._hasSpotlight) {
_this._spotlight = Entities.addEntity({
type: "Light",
position: lightTransform.p,
rotation: lightTransform.q,
isSpotlight: true,
dimensions: {
x: 2,
y: 2,
z: 20
},
color: {
red: 255,
green: 255,
blue: 255
},
intensity: 2,
exponent: 0.3,
cutoff: 20
});
_this._hasSpotlight = true;
debugPrint("Flashlight:: creating a spotlight");
} else {
// Updating the spotlight
Entities.editEntity(_this._spotlight, {
position: lightTransform.p,
rotation: lightTransform.q
});
_this.changeLightWithTriggerPressure();
debugPrint("Flashlight:: updating the spotlight");
}
debugPrint("I'm being grabbed...");
} else if (_this.beingGrabbed) {
if (_this._hasSpotlight) {
Entities.deleteEntity(_this._spotlight);
debugPrint("Destroying flashlight spotlight...");
}
_this._hasSpotlight = false;
_this._spotlight = null;
// if we are not being grabbed, and we previously were, then we were just released, remember that
// and print out a message
_this.beingGrabbed = false;
debugPrint("I'm was released...");
}
},
changeLightWithTriggerPressure: function(flashLightHand) {
var handClickString = flashLightHand + "_HAND_CLICK";
var handClick = Controller.findAction(handClickString);
this.triggerValue = Controller.getActionValue(handClick);
if (this.triggerValue < DISABLE_LIGHT_THRESHOLD && this.lightOn === true) {
this.turnLightOff();
} else if (this.triggerValue >= DISABLE_LIGHT_THRESHOLD && this.lightOn === false) {
this.turnLightOn();
}
return triggerValue
},
turnLightOff: function() {
Entities.editEntity(_this._spotlight, {
intensity: 0
});
this.lightOn = false
},
turnLightOn: function() {
Entities.editEntity(_this._spotlight, {
intensity: 2
});
this.lightOn = true
},
// preload() will be called when the entity has become visible (or known) to the interface
// it gives us a chance to set our local JavaScript object up. In this case it means:
// * remembering our entityID, so we can access it in cases where we're called without an entityID
// * connecting to the update signal so we can check our grabbed state
preload: function(entityID) {
_this.entityID = entityID;
var modelProperties = Entities.getEntityProperties(entityID);
Script.update.connect(this.update);
},
// unload() will be called when our entity is no longer available. It may be because we were deleted,
// or because we've left the domain or quit the application. In all cases we want to unhook our connection
// to the update signal
unload: function(entityID) {
if (_this._hasSpotlight) {
Entities.deleteEntity(_this._spotlight);
}
_this._hasSpotlight = false;
_this._spotlight = null;
Script.update.disconnect(this.update);
},
};
// entity scripts always need to return a newly constructed object of our type
return new Flashlight();
})