content/hifi-content/zfox/laser/laser.js
2022-02-14 02:04:11 +01:00

350 lines
13 KiB
JavaScript

//
// laser.js
//
// Adapted from gun.js by David Back
// by Rebecca Stankus on 01/05/18
// Copyright 2018 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
/* globals RayPick */
(function() {
var _this;
var TRIGGER_CONTROLS = [Controller.Standard.LT, Controller.Standard.RT];
var BEAM_LOCAL_OFFSET = {x: 0, y: -0.0055, z: -0.045};
var BEAM_LOCAL_DIRECTION = {x: 0, y: 0, z: -1000};
var BEAM_MIN_SIZE = 0.04;
var TRIGGER_TOGGLE_VALUE = 0.97;
var ORIGIN_SIZE_RATIO = 0.6;
var BEAM_OFFSET_RATIO = 0.5;
var MIN_FOCUS_SIZE = 0.02;
var BEAM_WIDTH = 0.01;
var HALF = 0.5;
var LASER_ON_SOUND = SoundCache.getSound(Script.resolvePath("sounds/on.wav"));
var FLASHLIGHT_ON_SOUND = SoundCache.getSound(Script.resolvePath("sounds/flashlight.wav"));
var OFF_SOUND = SoundCache.getSound(Script.resolvePath("sounds/off.wav"));
var AUDIO_VOLUME_LEVEL = 1;
var equipped = false;
var currentHand = null;
var doNotRayPick = [];
var triggerReleased = true;
var injector;
var Laser = function() {
_this = this;
};
Laser.prototype = {
on: false,
flashlight: null,
flashlightBeam: null,
position: null,
diameter: null,
beamOffset: null,
origin: null,
beam: null,
focus: null,
preload: function(entityID) {
_this.entityID = entityID;
var dimensions = Entities.getEntityProperties(_this.entityID, 'dimensions').dimensions;
_this.diameter = dimensions.x;
_this.beamOffset = {
x: 0,
y: 0,
z: -(BEAM_OFFSET_RATIO * dimensions.z)
};
},
startEquip: function(id, params) {
equipped = true;
currentHand = params[0] === "left" ? 0 : 1;
},
continueEquip: function(id, params) {
if (!equipped) {
var parentJointIndex = Entities.getEntityProperties(_this.entityID, 'parentJointIndex').parentJointIndex;
currentHand = (parentJointIndex === MyAvatar.getJointIndex("LeftHand")) ? 0 : 1;
equipped = true;
} else {
_this.toggleWithTriggerPressure();
}
},
toggleWithTriggerPressure: function() {
var triggerValue = Controller.getValue(TRIGGER_CONTROLS[currentHand]);
if (_this.on) {
if (_this.flashlight) {
if (triggerValue >= TRIGGER_TOGGLE_VALUE && triggerReleased) {
_this.turnOff();
triggerReleased = false;
} else if (triggerValue < TRIGGER_TOGGLE_VALUE && !triggerReleased) {
triggerReleased = true;
}
} else {
if (triggerValue >= TRIGGER_TOGGLE_VALUE && triggerReleased) {
_this.flashlightMode();
triggerReleased = false;
} else if (triggerValue < TRIGGER_TOGGLE_VALUE && !triggerReleased) {
triggerReleased = true;
} else {
_this.turnOn();
}
}
} else {
if (triggerValue >= TRIGGER_TOGGLE_VALUE && triggerReleased) {
_this.turnOn();
triggerReleased = false;
} else if (triggerValue < TRIGGER_TOGGLE_VALUE && !triggerReleased) {
triggerReleased = true;
}
}
},
releaseEquip: function(id, params) {
currentHand = null;
equipped = false;
_this.turnOff();
},
getBeamPosition: function() {
var properties = Entities.getEntityProperties(_this.entityID, ['position', 'rotation']);
var beamLocalPosition = Vec3.multiplyQbyV(properties.rotation, BEAM_LOCAL_OFFSET);
var beamWorldPosition = Vec3.sum(properties.position, beamLocalPosition);
return beamWorldPosition;
},
getBeamDirection: function() {
var rotation = Entities.getEntityProperties(_this.entityID, ['rotation']).rotation;
var beamAdjustedDirection = Vec3.multiplyQbyV(rotation, BEAM_LOCAL_DIRECTION);
return beamAdjustedDirection;
},
playSound: function(sound) {
if (sound.downloaded) {
if (injector) {
injector.stop();
}
injector = Audio.playSound(sound, {
position: Entities.getEntityProperties(_this.entityID, ['position']).position,
volume: AUDIO_VOLUME_LEVEL
});
}
},
addFocus: function(size, position) {
_this.focus = Entities.addEntity({
type: 'Model',
modelURL: Script.resolvePath("models/Glow-ball-red.fbx"),
dimensions: {x: size, y: size, z: size},
name: "Laser Focus",
color: {red: 255, green: 0, blue: 0},
position: position,
collisionless: true,
userData: "{\"grabbableKey\":{\"grabbable\":false}}"
}, true);
doNotRayPick.push(_this.focus);
},
turnOn: function() {
var beamStart = _this.getBeamPosition();
var beamDirection = _this.getBeamDirection();
var beamDirectionLength = Vec3.length(beamDirection);
var beamDirectionNormalized = Vec3.normalize(beamDirection);
var beamPickRay = ({
origin: beamStart,
direction: beamDirectionNormalized
});
var entityIntersection = Entities.findRayIntersection(beamPickRay, true, [], doNotRayPick);
var entityIntersectionDistance = entityIntersection.intersects ? entityIntersection.distance : 100;
var avatarIntersection = AvatarList.findRayIntersection(beamPickRay);
var avatarIntersectionDistance = avatarIntersection.intersects ? avatarIntersection.distance : 100;
var intersection = null;
var intersectEntityID = null;
if (entityIntersection.intersects && entityIntersectionDistance <= avatarIntersectionDistance) {
intersectEntityID = entityIntersection.entityID;
intersection = entityIntersection;
} else if (avatarIntersection.intersects && avatarIntersectionDistance < entityIntersectionDistance) {
intersectEntityID = avatarIntersection.avatarID;
intersection = avatarIntersection;
}
var intersectionPosition = false;
var beamPointDistance = false;
var beamSize = false;
if (intersectEntityID) {
intersectionPosition = intersection.intersection;
beamPointDistance = Vec3.distance(intersectionPosition, beamStart);
} else {
beamPointDistance = Math.min(entityIntersectionDistance, avatarIntersectionDistance);
}
beamSize = MIN_FOCUS_SIZE * beamPointDistance;
if (beamSize < BEAM_MIN_SIZE) {
beamSize = BEAM_MIN_SIZE;
}
console.log("ZRF HERE " + beamSize);
if (!_this.on) {
_this.playSound(LASER_ON_SOUND);
if (intersectionPosition) {
_this.addFocus(beamSize, intersectionPosition);
}
var originDiameter = ORIGIN_SIZE_RATIO * _this.diameter;
_this.origin = Entities.addEntity({
type: 'Model',
modelURL: Script.resolvePath("models/Glow-ball-red.fbx"),
name: "Laser Origin",
parentID: _this.entityID,
localPosition: _this.beamOffset,
dimensions: {x: originDiameter, y: originDiameter, z: originDiameter},
collisionless: true,
userData: "{\"grabbableKey\":{\"grabbable\":false}}",
description: "CC_BY Alan Zimmerman"
}, true);
doNotRayPick.push(_this.origin);
_this.beam = Entities.addEntity({
type: 'Model',
modelURL: Script.resolvePath("models/laser-beam-red.fbx"),
name: "Laser Beam",
parentID: _this.origin,
registrationPoint: {x: 0.5, y: 0.5, z: 1.0},
localPosition: {x: 0, y: 0, z: 0},
localRotation: Quat.normalize({}),
dimensions: {x: BEAM_WIDTH, y: BEAM_WIDTH, z: beamPointDistance},
userData: "{\"grabbableKey\":{\"grabbable\":false}}",
description: "CC_BY Alan Zimmerman"
}, true);
doNotRayPick.push(_this.beam);
} else {
if (intersectionPosition) {
if (_this.focus) {
Entities.editEntity(_this.focus, {
dimensions: {x: beamSize, y: beamSize, z: beamSize},
position: intersectionPosition
});
} else {
_this.addFocus(beamSize, intersectionPosition);
}
} else {
if (_this.focus) {
Entities.deleteEntity(_this.focus);
_this.focus = false;
}
}
Entities.editEntity(_this.beam, {
localRotation: Quat.normalize({}),
dimensions: {x: BEAM_WIDTH, y: BEAM_WIDTH, z: beamPointDistance}
});
}
_this.on = true;
},
flashlightMode: function() {
_this.laserOff();
_this.playSound(FLASHLIGHT_ON_SOUND);
_this.flashlight = Entities.addEntity({
type: "Light",
color: {
blue: 22,
green: 88,
red: 255
},
cutoff: 18,
dimensions: {
x: 3.652251958847046,
y: 3.652251958847046,
z: 11.81893539428711
},
exponent: 120,
falloffRadius: 5,
intensity: 5,
isSpotlight: true,
name: "Laser Flashlight",
parentID: _this.entityID,
localRotation: {
w: 0.999969482421875,
x: -0.007339596748352051,
y: 0.0000152587890625,
z: -0.0000457763671875
},
localPosition: {
x: -0.011594533920288086,
y: -0.0043926239013671875,
z: -0.04103599488735199
},
userData: "{\"grabbableKey\":{\"grabbable\":false}}"
}, true);
_this.flashlightBeam = Entities.addEntity({
type: 'Model',
modelURL: Script.resolvePath("models/light-beam.fbx"),
name: "Laser Beam",
parentID: _this.entityID,
localPosition: {
x: -0.0007977485656738281,
y: -0.0014594662934541702,
z: -0.1237635612487793
},
localRotation: {
x: 0,
y: 0,
z: 0,
w: 1
},
dimensions: {
x: 0.0589,
y: 0.0589,
z: 0.1641
},
userData: "{\"grabbableKey\":{\"grabbable\":false}}",
description: "CC_BY Alan Zimmerman"
}, true);
},
laserOff: function() {
Entities.deleteEntity(_this.focus);
Entities.deleteEntity(_this.beam);
Entities.deleteEntity(_this.origin);
_this.focus = null;
_this.beam = null;
_this.origin = null;
},
lightOff: function() {
Entities.deleteEntity(_this.flashlightBeam);
Entities.deleteEntity(_this.flashlight);
_this.flashlight = null;
_this.flashlightBeam = null;
},
turnOff: function() {
_this.playSound(OFF_SOUND);
if (_this.flashlight) {
this.lightOff();
} else {
_this.laserOff();
}
_this.on = false;
},
unload: function() {
_this.turnOff();
}
};
return new Laser();
});