// // bow.js // // This script attaches to a bow that you can pick up with a hand controller. Load an arrow and then shoot it. // Created by James B. Pollack @imgntn on 10/19/2015 // 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 // (function() { Script.include("../../libraries/utils.js"); var NOTCH_ARROW_SOUND_URL = 'http://hifi-content.s3.amazonaws.com/james/bow_and_arrow/sounds/notch.wav?123'; var SHOOT_ARROW_SOUND_URL = 'http://hifi-content.s3.amazonaws.com/james/bow_and_arrow/sounds/String_release2.L.wav'; var STRING_PULL_SOUND_URL = 'http://hifi-content.s3.amazonaws.com/james/bow_and_arrow/sounds/Bow_draw.1.L.wav'; var ARROW_WHIZZ_SOUND_URL = 'http://hifi-content.s3.amazonaws.com/james/bow_and_arrow/sounds/whizz.wav'; //todo : multiple impact sounds var ARROW_HIT_SOUND_URL = 'http://hifi-content.s3.amazonaws.com/james/bow_and_arrow/sounds/Arrow_impact1.L.wav' var ARROW_DIMENSIONS = { x: 0.02, y: 0.02, z: 0.64 }; var ZERO_VEC = { x: 0, y: 0, z: 0 }; var LINE_ENTITY_DIMENSIONS = { x: 1000, y: 1000, z: 1000 }; var ARROW_OFFSET = -0.36; var ARROW_TIP_OFFSET = 0.32; var ARROW_GRAVITY = { x: 0, y: -4.8, z: 0 }; var ARROW_MODEL_URL = "http://hifi-content.s3.amazonaws.com/james/bow_and_arrow/models/newarrow_textured.fbx"; var ARROW_COLLISION_HULL_URL = "http://hifi-content.s3.amazonaws.com/james/bow_and_arrow/models/newarrow_collision_hull.obj"; var ARROW_DIMENSIONS = { x: 0.02, y: 0.02, z: 0.64 }; var TOP_NOTCH_OFFSET = 0.6; var BOTTOM_NOTCH_OFFSET = 0.6; var LINE_DIMENSIONS = { x: 5, y: 5, z: 5 }; var DRAW_STRING_THRESHOLD = 0.80; var TARGET_LINE_LENGTH = 1; var LEFT_TIP = 1; var RIGHT_TIP = 3; var NOTCH_DETECTOR_OFFSET_FORWARD = 0.08; var NOTCH_DETECTOR_OFFSET_UP = 0.035; var NOTCH_DETECTOR_DIMENSIONS = { x: 0.05, y: 0.05, z: 0.05 }; var NOTCH_DETECTOR_DISTANCE = 0.1; var SHOT_SCALE = { min1: 0, max1: 0.6, min2: 1, max2: 10 } var BOW_SPATIAL_KEY = { relativePosition: { x: 0, y: 0.06, z: 0.11 }, relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 90) } var arrowTrackers = []; var _this; function Bow() { _this = this; return; } Bow.prototype = { isGrabbed: false, stringDrawn: false, aiming: false, arrowTipPosition: null, preNotchString: null, hasArrowNotched: false, notchDetector: null, arrow: null, arrowIsBurning: false, prePickupString: null, stringData: { currentColor: { red: 255, green: 255, blue: 255 } }, preload: function(entityID) { print('preload bow') this.entityID = entityID; this.bowID = entityID; this.stringPullSound = SoundCache.getSound(STRING_PULL_SOUND_URL); this.shootArrowSound = SoundCache.getSound(SHOOT_ARROW_SOUND_URL); this.arrowHitSound = SoundCache.getSound(ARROW_HIT_SOUND_URL); this.arrowNotchSound = SoundCache.getSound(NOTCH_ARROW_SOUND_URL); this.arrowWhizzSound = SoundCache.getSound(ARROW_WHIZZ_SOUND_URL); this.createPreNotchString(); Script.update.connect(this.drawStringsBeforePickup); }, unload: function() { // Script.update.disconnect(this.updateArrowTrackers); // while (arrowTrackers.length > 0) { // var tracker = arrowTrackers.pop(); // tracker.childEntities.forEach(function(child) { // Entities.deleteEntity(child); // }) // tracker.childParticleSystems.forEach(function(child) { // Entities.deleteEntity(child); // }) // Entities.deleteEntity(tracker.arrowID); // } this.deleteStrings(); Entities.deleteEntity(this.notchDetector); Entities.deleteEntity(this.preNotchString); Entities.deleteEntity(this.arrow); Script.update.disconnect(this.drawStringsBeforePickup); }, setLeftHand: function() { if (this.isGrabbed === true) { return false; } this.hand = 'left'; }, setRightHand: function() { if (this.isGrabbed === true) { return false; } this.hand = 'right'; }, startNearGrab: function() { if (this.isGrabbed === true) { return false; } this.isGrabbed = true; this.initialHand = this.hand; setEntityCustomData('grabbableKey', this.entityID, { turnOffOtherHand: true, invertSolidWhileHeld: true, spatialKey: BOW_SPATIAL_KEY }); }, continueNearGrab: function() { // print('collidable bow' + Entities.getEntityProperties(this.entityID, "collisionsWillMove").collisionsWillMove) // print('collidable arrow' + Entities.getEntityProperties(this.arrow, "collisionsWillMove").collisionsWillMove) // print('collidable notch' + Entities.getEntityProperties(this.notchDetector, "collisionsWillMove").collisionsWillMove) // print('collidable topstring' + Entities.getEntityProperties(this.topString, "collisionsWillMove").collisionsWillMove) // print('collidable bottomstring' + Entities.getEntityProperties(this.bottomString, "collisionsWillMove").collisionsWillMove) // print('collidable prenotchstring' + Entities.getEntityProperties(this.preNotchString, "collisionsWillMove").collisionsWillMove) this.bowProperties = Entities.getEntityProperties(this.entityID, ["position", "rotation", "userData"]); this.updateNotchDetectorPosition(); // if (this.hasArrowNotched === false) { // this.hasArrowNotched = true // this.arrowIsBurning = false // setEntityCustomData('grabbableKey', this.entityID, { // turnOffOtherHand: true, // invertSolidWhileHeld: true, // spatialKey: BOW_SPATIAL_KEY // }); // } //create a string across the bow when we pick it up // if (this.preNotchString === null) { // this.createPreNotchString(); // } if (this.preNotchString !== null && this.aiming === false) { // print('DRAW PRE NOTCH STRING') // this.drawPreNotchStrings(); // this.updateArrowAttachedToBow(); } // create the notch detector that arrows will look for if (this.notchDetector === null) { this.createNotchDetector(); } //if we have an arrow notched, then draw some new strings // if (this.hasArrowNotched === true) { if (this.aiming === true) { Entities.editEntity(this.preNotchString, { visible: false }) } else { Entities.editEntity(this.preNotchString, { visible: true }) } //only test for strings now that an arrow is notched this.checkStringHand(); // } else { // // print('DONT DO ANYTHING') // //otherwise, don't do much of anything. // } }, releaseGrab: function() { print('RELEASE GRAB EVENT') if (this.isGrabbed === true && this.hand === this.initialHand) { this.isGrabbed = false; this.stringDrawn = false; this.deleteStrings(); setEntityCustomData('grabbableKey', this.entityID, { turnOffOtherHand: false, invertSolidWhileHeld: true, spatialKey: BOW_SPATIAL_KEY }); Entities.deleteEntity(this.notchDetector); // Entities.deleteEntity(this.preNotchString); Entities.deleteEntity(this.arrow); this.aiming = false; this.notchDetector = null; this.hasArrowNotched = false; // this.preNotchString = null; } }, createArrow: function() { this.playArrowNotchSound(); var arrow = Entities.addEntity({ name: 'Hifi-Arrow', type: 'Model', modelURL: ARROW_MODEL_URL, shapeType: 'compound', compoundShapeURL: ARROW_COLLISION_HULL_URL, dimensions: ARROW_DIMENSIONS, position: this.bowProperties.position, collisionsWillMove: false, ignoreForCollisions: true, collisionSoundURL: ARROW_HIT_SOUND_URL, gravity: ARROW_GRAVITY, damping: 0.01, userData: JSON.stringify({ grabbableKey: { invertSolidWhileHeld: true, grabbable: false } }) }); var arrowProps = Entities.getEntityProperties(arrow) Script.addEventHandler(arrow, "collisionWithEntity", function(entityA, entityB, collision) { //have to reverse lookup the tracker by the arrow id to get access to the children print('ARROW COLLIDED WITH::' + entityB); print('NAME OF ENTITY:::' + Entities.getEntityProperties(entityB, "name").name) }); return arrow }, createStrings: function() { this.createTopString(); this.createBottomString(); }, createTopString: function() { var stringProperties = { name: 'Hifi-Bow-Top-String', type: 'Line', position: Vec3.sum(this.bowProperties.position, TOP_NOTCH_OFFSET), dimensions: LINE_DIMENSIONS, collisionsWillMove: false, ignoreForCollisions: true, userData: JSON.stringify({ grabbableKey: { grabbable: false } }) }; this.topString = Entities.addEntity(stringProperties); }, createBottomString: function() { var stringProperties = { name: 'Hifi-Bow-Bottom-String', type: 'Line', position: Vec3.sum(this.bowProperties.position, BOTTOM_NOTCH_OFFSET), dimensions: LINE_DIMENSIONS, collisionsWillMove: false, ignoreForCollisions: true, userData: JSON.stringify({ grabbableKey: { grabbable: false } }) }; this.bottomString = Entities.addEntity(stringProperties); }, deleteStrings: function() { Entities.deleteEntity(this.topString); Entities.deleteEntity(this.bottomString); }, updateStringPositions: function() { // print('update string positions!!!') var upVector = Quat.getUp(this.bowProperties.rotation); var upOffset = Vec3.multiply(upVector, TOP_NOTCH_OFFSET); var downVector = Vec3.multiply(-1, Quat.getUp(this.bowProperties.rotation)); var downOffset = Vec3.multiply(downVector, BOTTOM_NOTCH_OFFSET); var backOffset = Vec3.multiply(-0.1, Quat.getFront(this.bowProperties.rotation)); var topStringPosition = Vec3.sum(this.bowProperties.position, upOffset); this.topStringPosition = Vec3.sum(topStringPosition, backOffset); var bottomStringPosition = Vec3.sum(this.bowProperties.position, downOffset); this.bottomStringPosition = Vec3.sum(bottomStringPosition, backOffset); Entities.editEntity(this.preNotchString, { position: this.topStringPosition }); Entities.editEntity(this.topString, { position: this.topStringPosition }); Entities.editEntity(this.bottomString, { position: this.bottomStringPosition }); }, drawStrings: function() { this.updateStringPositions(); var lineVectors = this.getLocalLineVectors(); Entities.editEntity(this.topString, { linePoints: [{ x: 0, y: 0, z: 0 }, lineVectors[0]], lineWidth: 5, color: this.stringData.currentColor }); Entities.editEntity(this.bottomString, { linePoints: [{ x: 0, y: 0, z: 0 }, lineVectors[1]], lineWidth: 5, color: this.stringData.currentColor }); }, getLocalLineVectors: function() { var topVector = Vec3.subtract(this.arrowRearPosition, this.topStringPosition); var bottomVector = Vec3.subtract(this.arrowRearPosition, this.bottomStringPosition); return [topVector, bottomVector]; }, drawStringsBeforePickup: function() { _this.drawPreNotchStrings(); }, createPreNotchString: function() { this.bowProperties = Entities.getEntityProperties(_this.entityID, ["position", "rotation", "userData"]); var stringProperties = { type: 'Line', position: Vec3.sum(this.bowProperties.position, TOP_NOTCH_OFFSET), dimensions: LINE_DIMENSIONS, visible: true, ignoreForCollisions: true, collisionsWillMove: false, userData: JSON.stringify({ grabbableKey: { grabbable: false } }) }; this.preNotchString = Entities.addEntity(stringProperties); }, drawPreNotchStrings: function() { this.bowProperties = Entities.getEntityProperties(_this.entityID, ["position", "rotation", "userData"]); this.updateStringPositions(); var downVector = Vec3.multiply(-1, Quat.getUp(this.bowProperties.rotation)); var downOffset = Vec3.multiply(downVector, BOTTOM_NOTCH_OFFSET * 2); Entities.editEntity(this.preNotchString, { name: 'Hifi-Pre-Notch-String', linePoints: [{ x: 0, y: 0, z: 0 }, Vec3.sum({ x: 0, y: 0, z: 0 }, downOffset)], lineWidth: 5, color: this.stringData.currentColor, }); }, checkStringHand: function() { //invert the hands because our string will be held with the opposite hand of the first one we pick up the bow with if (this.initialHand === 'left') { this.getStringHandPosition = MyAvatar.getRightPalmPosition; this.getStringHandRotation = MyAvatar.getRightPalmRotation; this.getGrabHandPosition = MyAvatar.getLeftPalmPosition; this.getGrabHandRotation = MyAvatar.getLeftPalmRotation; this.stringTriggerAction = Controller.findAction("RIGHT_HAND_CLICK"); } else if (this.initialHand === 'right') { this.getStringHandPosition = MyAvatar.getLeftPalmPosition; this.getStringHandRotation = MyAvatar.getLeftPalmRotation; this.getGrabHandPosition = MyAvatar.getRightPalmPosition; this.getGrabHandRotation = MyAvatar.getRightPalmRotation; this.stringTriggerAction = Controller.findAction("LEFT_HAND_CLICK"); } this.triggerValue = Controller.getActionValue(this.stringTriggerAction); // print('TRIGGER VALUE:::' + this.triggerValue) if (this.triggerValue < DRAW_STRING_THRESHOLD && this.stringDrawn === true) { // firing the arrow print('HIT RELEASE LOOP IN CHECK') this.hasArrowNotched = false; this.aiming = false; this.stringDrawn = false; this.releaseArrow(); } else if (this.triggerValue >= DRAW_STRING_THRESHOLD && this.stringDrawn === true) { // print('HIT CONTINUE LOOP IN CHECK') this.aiming = true; //continuing to aim the arrow this.stringData.handPosition = this.getStringHandPosition(); this.stringData.handRotation = this.getStringHandRotation(); this.stringData.grabHandPosition = this.getGrabHandPosition(); this.stringData.grabHandRotation = this.getGrabHandRotation(); this.drawStrings(); this.updateArrowPositionInNotch(); } else if (this.triggerValue >= DRAW_STRING_THRESHOLD && this.stringDrawn === false) { this.arrow = this.createArrow(); print('CREATE ARROW' + this.arrow); // print('HIT START LOOP IN CHECK') this.playStringPullSound(); //the first time aiming the arrow this.stringDrawn = true; this.createStrings(); // var arrowTracker = this.createArrowTracker(this.arrow); // arrowTrackers.push(arrowTracker) this.stringData.handPosition = this.getStringHandPosition(); this.stringData.handRotation = this.getStringHandRotation(); this.stringData.grabHandPosition = this.getGrabHandPosition(); this.stringData.grabHandRotation = this.getGrabHandRotation(); this.drawStrings(); this.updateArrowPositionInNotch(); } }, setArrowTipPosition: function(arrowPosition, arrowRotation) { var frontVector = Quat.getFront(arrowRotation); var frontOffset = Vec3.multiply(frontVector, ARROW_TIP_OFFSET); var arrowTipPosition = Vec3.sum(arrowPosition, frontOffset); this.arrowTipPosition = arrowTipPosition; return arrowTipPosition; }, setArrowRearPosition: function(arrowPosition, arrowRotation) { var frontVector = Quat.getFront(arrowRotation); var frontOffset = Vec3.multiply(frontVector, -ARROW_TIP_OFFSET); var arrowTipPosition = Vec3.sum(arrowPosition, frontOffset); this.arrowRearPosition = arrowTipPosition; return arrowTipPosition; }, getArrowPosition: function() { var arrowVector = Vec3.subtract(this.stringData.handPosition, this.stringData.grabHandPosition); arrowVector = Vec3.normalize(arrowVector); arrowVector = Vec3.multiply(arrowVector, ARROW_OFFSET); var arrowPosition = Vec3.sum(this.stringData.grabHandPosition, arrowVector); return arrowPosition; }, updateArrowAttachedToBow: function() { Entities.editEntity(this.arrow, { position: this.notchDetectorPosition, rotation: this.bowProperties.rotation }) }, updateArrowPositionInNotch: function() { //move it backwards var handToNotch = Vec3.subtract(this.notchDetectorPosition, this.stringData.handPosition); var pullBackDistance = Vec3.length(handToNotch); if (pullBackDistance >= 0.6) { pullBackDistance = 0.6; } var pullBackOffset = Vec3.multiply(handToNotch, -pullBackDistance); var arrowPosition = Vec3.sum(this.notchDetectorPosition, pullBackOffset); this.changeStringPullSoundVolume(pullBackDistance); //move it forward a bit var pushForwardOffset = Vec3.multiply(handToNotch, -ARROW_OFFSET); var finalArrowPosition = Vec3.sum(arrowPosition, pushForwardOffset); var arrowRotation = Quat.rotationBetween(Vec3.FRONT, handToNotch); this.setArrowTipPosition(finalArrowPosition, arrowRotation); this.setArrowRearPosition(finalArrowPosition, arrowRotation); Entities.editEntity(this.arrow, { position: finalArrowPosition, rotation: arrowRotation }) }, releaseArrow: function() { print('RELEASE ARROW!!!') var handToNotch = Vec3.subtract(this.notchDetectorPosition, this.stringData.handPosition); var pullBackDistance = Vec3.length(handToNotch); // if (pullBackDistance >= 0.6) { // pullBackDistance = 0.6; // } var arrowRotation = Quat.rotationBetween(Vec3.FRONT, handToNotch); print('HAND DISTANCE:: ' + pullBackDistance); var arrowForce = this.scaleArrowShotStrength(pullBackDistance); print('ARROW FORCE::' + arrowForce); // handToNotch = Vec3.normalize(handToNotch) //var forwardVec = handToNotch; var forwardVec = Vec3.multiply(handToNotch, arrowForce); //var forwardVec = Vec3.multiply(handToNotch, handToNotch); var arrowProperties = { // rotation: arrowRotation, ignoreForCollisions: false, collisionsWillMove: true, velocity: forwardVec, lifetime: 10 }; this.playShootArrowSound(); Entities.editEntity(this.arrow, arrowProperties); var arrowStore = this.arrow; this.arrow = null; Entities.editEntity(this.preNotchString, { visible: true }); this.deleteStrings(); }, scaleArrowShotStrength: function(value) { var min1 = SHOT_SCALE.min1; var max1 = SHOT_SCALE.max1; var min2 = SHOT_SCALE.min2; var max2 = SHOT_SCALE.max2; return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); }, createNotchDetector: function() { print('CREATE NOTCH DETECTOR') var detectorPosition; var frontVector = Quat.getFront(this.bowProperties.rotation); var notchVectorForward = Vec3.multiply(frontVector, NOTCH_DETECTOR_OFFSET_FORWARD); var upVector = Quat.getUp(this.bowProperties.rotation); var notchVectorUp = Vec3.multiply(upVector, NOTCH_DETECTOR_OFFSET_UP); detectorPosition = Vec3.sum(this.bowProperties.position, notchVectorForward); detectorPosition = Vec3.sum(detectorPosition, notchVectorUp); var detectorProperties = { name: 'Hifi-NotchDetector', type: 'Box', visible: false, collisionsWillMove: false, ignoreForCollisions: true, dimensions: NOTCH_DETECTOR_DIMENSIONS, position: detectorPosition, color: { red: 0, green: 255, blue: 0 } }; this.notchDetector = Entities.addEntity(detectorProperties); }, updateNotchDetectorPosition: function() { var detectorPosition; var frontVector = Quat.getFront(this.bowProperties.rotation); var notchVectorForward = Vec3.multiply(frontVector, NOTCH_DETECTOR_OFFSET_FORWARD); var upVector = Quat.getUp(this.bowProperties.rotation); var notchVectorUp = Vec3.multiply(upVector, NOTCH_DETECTOR_OFFSET_UP); detectorPosition = Vec3.sum(this.bowProperties.position, notchVectorForward); detectorPosition = Vec3.sum(detectorPosition, notchVectorUp); this.notchDetectorPosition = detectorPosition; Entities.editEntity(this.notchDetector, { position: this.notchDetectorPosition, rotation: this.bowProperties.rotation }); }, createFireParticleSystem: function() { print('MAKING A FIRE') //will probably need to dynamically update the orientation to match the arrow??? var myOrientation = Quat.fromPitchYawRollDegrees(-90, 0, 0.0); var animationSettings = JSON.stringify({ fps: 30, running: true, loop: true, firstFrame: 1, lastFrame: 10000 }); var fire = Entities.addEntity({ type: "ParticleEffect", name: "Hifi-Arrow-Fire", animationSettings: animationSettings, textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", emitRate: 100, position: MyAvatar.position, colorStart: { red: 70, green: 70, blue: 137 }, color: { red: 200, green: 99, blue: 42 }, colorFinish: { red: 255, green: 99, blue: 32 }, radiusSpread: 0.01, radiusStart: 0.02, radiusEnd: 0.001, particleRadius: 0.15, radiusFinish: 0.0, emitOrientation: myOrientation, emitSpeed: 0.3, speedSpread: 0.1, alphaStart: 0.05, alpha: 0.1, alphaFinish: 0.05, emitDimensions: { x: 0.5, y: 0.5, z: 0.1 }, polarFinish: 0.1, emitAcceleration: { x: 0.0, y: 0.0, z: 0.0 }, accelerationSpread: { x: 0.1, y: 0.01, z: 0.1 }, lifespan: 0.5, ignoreForCollisions: true, collisionsWillMove: false, }); return fire; }, createArrowTracker: function(arrow, isBurning) { print('in create arrow tracker:::' + arrow) var _t = this; // var isBurning = this.arrowIsBurning; //delete this line below once debugging is done var isBurning = isBurning || true; var arrowTracker = { arrowID: arrow, // whizzingSound: _t.playWhizzSound(), //fireSound: _t.createFireSound(), hasPlayedCollisionSound: false, glowBox: _t.createGlowBoxAsModel(), fireParticleSystem: _t.createFireParticleSystem(), childEntities: [], childSounds: [], childParticleSystems: [], init: function() { print('init arrow tracker') this.setChildren(); }, setCollisionCallback: function() { print('set arrow tracker callback' + this.arrowID) Script.addEventHandler(this.arrowID, "collisionWithEntity", function(entityA, entityB, collision) { //have to reverse lookup the tracker by the arrow id to get access to the children var tracker = getArrowTrackerByArrowID(entityA); Entities.deleteEntity(tracker.glowBox); }); }, setChildren: function() { print('set arrow tracker children') // this.childSounds.push(this.whizzingSound); // this.childSounds.push(this.fireSound); this.childEntities.push(this.glowBox); this.childParticleSystems.push(this.fireParticleSystem); }, updateChildEntities: function(arrowID) { var arrowProperties = Entities.getEntityProperties(this.arrowID, ["position", "rotation"]); _t.setArrowTipPosition(arrowProperties.position, arrowProperties.rotation); _t.setArrowRearPosition(arrowProperties.position, arrowProperties.rotation); //update the positions // this.soundEntities.forEach(function(injector) { // var audioProperties = { // volume: 0.25, // position: arrowProperties.position // }; // injector.options = audioProperties; // }) this.childEntities.forEach(function(child) { Entities.editEntity(child, { position: arrowProperties.position, rotation: arrowProperties.rotation }) }) this.childParticleSystems.forEach(function(child) { Entities.editEntity(child, { position: _t.arrowTipPosition }) }) } }; arrowTracker.init(); arrowTracker.setCollisionCallback(); return arrowTracker }, createFireBurningSound: function() { var audioProperties = { volume: 0.25, position: this.bowProperties.position, loop: true }; var injector = Audio.playSound(this.fireBurningSound, audioProperties); return injector }, createGlowBoxAsModel: function() { var GLOW_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/bow_and_arrow/models/glow.fbx'; var properties = { name: 'Hifi-Arrow-Glow-Model', type: 'Model', modelURL: GLOW_MODEL_URL, dimensions: ARROW_DIMENSIONS, collisionsWillMove: false, ignoreForCollisions: true, userData: JSON.stringify({ grabbableKey: { grabbable: false } }) } var glowBox = Entities.addEntity(properties); return glowBox }, createGlowBox: function() { print('creating glow box') var shaderUrl = Script.resolvePath('../../shaders/exampleV2.fs'); var properties = { name: 'Hifi-Arrow-Glow', type: 'Box', dimensions: ARROW_DIMENSIONS, collisionsWillMove: false, ignoreForCollisions: true, color: { red: 255, green: 0, blue: 255 }, //i want to use shader but for some reason its white... need to fix; // userData: JSON.stringify({ // "grabbableKey": { // grabbable: false // }, // "ProceduralEntity": { // "shaderUrl": shaderUrl, // // V2 and onwards, shaders must include a version identifier, or they will default // // to V1 behavior // "version": 2, // // Any values specified here will be passed on to uniforms with matching names in // // the shader. Only numbers and arrays of length 1-4 of numbers are supported. // // // // The size of the data must match the size of the uniform: // // a number or 1 value array = 'uniform float' // // 2 value array = 'uniform vec2' // // 3 value array = 'uniform vec3' // // 4 value array = 'uniform vec4' // // // // Uniforms should always be declared in the shader with a default value // // or failure to specify the value here will result in undefined behavior. // "uniforms": { // // uniform float iSpeed = 1.0; // "iSpeed": 2.0, // // uniform vec3 iSize = vec3(1.0); // "iSize": [1.0, 2.0, 4.0] // } // } // }) } var glowBox = Entities.addEntity(properties); return glowBox }, updateArrowTrackers: function() { // print('updating arrow trackers:::' + arrowTrackers.length); arrowTrackers.forEach(function(tracker) { var arrowID = tracker.arrowID; tracker.updateChildEntities(arrowID); }) }, playStringPullSound: function() { var audioProperties = { volume: 0.25, position: this.bowProperties.position }; this.stringPullInjector = Audio.playSound(this.stringPullSound, audioProperties); }, playShootArrowSound: function(sound) { var audioProperties = { volume: 0.25, position: this.bowProperties.position }; Audio.playSound(this.shootArrowSound, audioProperties); }, playArrowHitSound: function(position) { var audioProperties = { volume: 0.25, position: position }; Audio.playSound(this.arrowHitSound, audioProperties); }, playArrowNotchSound: function() { print('play arrow notch sound') var audioProperties = { volume: 0.25, position: this.bowProperties.position }; Audio.playSound(this.arrowNotchSound, audioProperties); }, playArrowWhizzSound: function() { var audioProperties = { volume: 0.0, position: this.bowProperties.position }; var injector = Audio.playSound(this.arrowWhizzSound, audioProperties); return injector }, changeStringPullSoundVolume: function(pullBackDistance) { var audioProperties = { volume: 0.25, position: this.bowProperties.position } this.stringPullInjector.options = audioProperties } }; getArrowTrackerByArrowID = function(arrowID) { var result = arrowTrackers.filter(function(tracker) { return tracker.arrowID === arrowID; }); var tracker = result[0] return tracker } return new Bow(); });