// gravGun.js // // Created by Mark Brosche February 10, 2019 // Copyright 2019 Mark Brosche // // DISCLAIMER - This is a derivative work based off of the functionality of the Gravity Gun // as portrayed in the Half Life 2 series of games by Valve Software. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html (function(){ // Constant Variables var MAX_DISTANCE = 30; var MAX_ANGLE_FROM_RAY = 45; var DETECT_DISTANCE = 10; var MAX_WEIGHT = 60; // Mutable Variables var _this; var injector; var canGrabAvatars = false; var isEquipped = false; var children = []; var particles = []; var captureZone; var detectorInterval = false; var GravityGun = function(){ _this = this; }; GravityGun.prototype = { // ***** SUPPORT FUNCTIONS ***** playSound: function(sound, localOnly){ if (sound.downloaded) { if (injector) { injector.stop(); } injector = Audio.playSound(sound, { position: MyAvatar.position, volume: AUDIO_VOLUME, localOnly: localOnly }); } else { console.log("no sound downloaded"); } }, isEntityInsideZone: function(position, zoneProperties) { var localPosition = Vec3.multiplyQbyV(Quat.inverse(zoneProperties.rotation), Vec3.subtract(position, zoneProperties.position)); var halfDimensions = Vec3.multiply(zoneProperties.dimensions, HALF_MULTIPLIER); return -halfDimensions.x <= localPosition.x && halfDimensions.x >= localPosition.x && -halfDimensions.y <= localPosition.y && halfDimensions.y >= localPosition.y && -halfDimensions.z <= localPosition.z && halfDimensions.z >= localPosition.z; }, getEntityData: function() { // get any userData // get material entities // get animations // get sounds // get particles // get lights }, materialSwap: function(entityID1, entityID2) { // exchange the priority levels of entityID1 and entityID2 }, // ***** END SUPPORT FUNCTIONS ***** preload: function() { _this.getEntityData(); }, // ***** GUN METHODS ***** openClaws: function() { // vibrate controller a tiny bit // play opening sound }, closeClaws: function() { // vibrate controller a tiny bit // play closing sound }, detectObject: function() { // if no entity is being held // don't detect things through walls // if grabbable object is within detectable range/angle, open claws, get entity props // if grabble object moves out of detectable range/angle, close claws }, tractorBeam: function() { // don't detect things through walls // if no object in range, // claws stay closed, // play non-event sound // start soft glow from barrel end // else if // object is outside detect range but inside max range // start soft glow from barrel end // get entity props // edit entity acceleration to point to gun's position // else // get entity props // edit entity acceleration to point to gun's position // holdObject(); }, holdObject: function() { // don't detect things through walls // automatic when tractored objects are close enough // no need to hold a button to continue holding // set entity parent to gun // openClaws() if not already open // start lightning particles from claws to barrel end // play oscillating sound // vibrate controller a medium bit // recoil the gun // jiggle gauge needle and go from green to yellow // held object should retain orientation relative to player at moment of capture // colliding with other objects and surfaces may alter the object's orientation // but it will return to it's capture rotation if collisions stop }, puntObject: function(entity, weight) { // don't detect things through walls // if object is held // set acceleration to gun direction dependent on object weight // play punt sound // recoil the gun // large flash and lightning particles // jiggle the gauge needle // closeClaws() // pulse the controller heavily // else if object close but not held // if not aimed at object centroid, calculate torque // add thrust with gun direction dependent on object weight // play punt sound // recoil the gun // pulse the controller heavily // large particles // jiggle the gauge needle // else if object not puntable/nothing to punt // recoil the gun // jiggle the gauge needle }, dropObject: function() { // don't detect things through walls // set object acceleration to [0,-10,0] // play drop sound // stop lightning particles // stop soft glow particle }, setEnergyLevel: function(energy) { switch(energy) { case "NORMAL": // materialSwap canGrabAvatars = false; break; case "SUPERCHARGED": // materialSwap canGrabAvatars = true; // openClaws() is permanent // lightning particles sporadically appear // more lens flares around the claw arms // gun vibrates and hums with energy // entities punted will emit lightning and twitch for a few seconds break; } }, equipGun: function() { // set gun entity as child of avatar's right hand // set twist-grip as parent of avatar's left hand? isEquipped = true; // disable far grab // disable scaling with grip detectorInterval = Script.setInterval(function() { _this.detectObject(); }, interval); }, dropGun: function() { // set gun entity as having no parent, set acceleration to [0,-10,0] // clear intervals }, // ***** END GUN METHODS ***** // ***** VR CONTROLS **** onLeftBackTwist: function() { if (isEquipped && leftTriggerHeld) { _this.tractorBeam(); // ramp pulses increase to amount of twist // vibrate a lot if too much twist } }, onLeftFrontTwist: function() { if (isEquipped &&leftTriggerHeld) { _this.dropObject(); } }, onRightButtonOne: function() { if (isEquipped) { _this.puntObject(); } }, onRightButtonGrip: function() { if (isEquipped){ _this.dropGun(); } else { _this.equipGun(); } // pulse the controller }, // ***** END VR CONTROLS **** // ***** DESKTOP CONTROLS **** // ***** END DESKTOP CONTROLS **** unload: function() { // clear any intervals // remove any parented objects } } return new GravityGun; })