Showing the changes to scripts/tutorials/entity_scripts (4 of 13 files). Show all
Unified · Split
| @@ -0,0 +1,268 @@ | |||
| 1 | // | ||
| 2 | // flashlight.js | ||
| 3 | // | ||
| 4 | // Script Type: Entity | ||
| 5 | // | ||
| 6 | // Created by Sam Gateau on 9/9/15. | ||
| 7 | // Additions by James B. Pollack @imgntn on 9/21/2015 | ||
| 8 | // Copyright 2015 High Fidelity, Inc. | ||
| 9 | // | ||
| 10 | // This is a toy script that can be added to the Flashlight model entity: | ||
| 11 | // "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx" | ||
| 12 | // that creates a spotlight attached with the flashlight model while the entity is grabbed | ||
| 13 | // | ||
| 14 | // Distributed under the Apache License, Version 2.0. | ||
| 15 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 16 | // | ||
| 17 | |||
| 18 | (function() { | ||
| 19 | |||
| 20 | var ON_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_on.wav'; | ||
| 21 | var OFF_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_off.wav'; | ||
| 22 | |||
| 23 | //we are creating lights that we don't want to get stranded so lets make sure that we can get rid of them | ||
| 24 | //if you're going to be using this in a dungeon or something and holding it for a long time, increase this lifetime value. | ||
| 25 | var LIFETIME = 100; | ||
| 26 | |||
| 27 | |||
| 28 | // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember | ||
| 29 | // 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) | ||
| 30 | function Flashlight() { | ||
| 31 | return; | ||
| 32 | } | ||
| 33 | |||
| 34 | //if the trigger value goes below this while held, the flashlight will turn off. if it goes above, it will | ||
| 35 | var DISABLE_LIGHT_THRESHOLD = 0.7; | ||
| 36 | |||
| 37 | // These constants define the Spotlight position and orientation relative to the model | ||
| 38 | var MODEL_LIGHT_POSITION = { | ||
| 39 | x: 0, | ||
| 40 | y: -0.3, | ||
| 41 | z: 0 | ||
| 42 | }; | ||
| 43 | var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { | ||
| 44 | x: 1, | ||
| 45 | y: 0, | ||
| 46 | z: 0 | ||
| 47 | }); | ||
| 48 | |||
| 49 | //there's another small point light we put at the end of the flashlight to make the end glow | ||
| 50 | |||
| 51 | var GLOW_LIGHT_POSITION = { | ||
| 52 | x: 0, | ||
| 53 | y: -0.1, | ||
| 54 | z: 0 | ||
| 55 | }; | ||
| 56 | |||
| 57 | // Evaluate the world light entity positions and orientations from the model ones | ||
| 58 | function evalLightWorldTransform(modelPosition, modelRotation) { | ||
| 59 | |||
| 60 | return { | ||
| 61 | p: Vec3.sum(modelPosition, Vec3.multiplyQbyV(modelRotation, MODEL_LIGHT_POSITION)), | ||
| 62 | q: Quat.multiply(modelRotation, MODEL_LIGHT_ROTATION) | ||
| 63 | }; | ||
| 64 | } | ||
| 65 | |||
| 66 | function glowLightWorldTransform(modelPosition, modelRotation) { | ||
| 67 | return { | ||
| 68 | p: Vec3.sum(modelPosition, Vec3.multiplyQbyV(modelRotation, GLOW_LIGHT_POSITION)), | ||
| 69 | q: Quat.multiply(modelRotation, MODEL_LIGHT_ROTATION) | ||
| 70 | }; | ||
| 71 | } | ||
| 72 | |||
| 73 | Flashlight.prototype = { | ||
| 74 | lightOn: false, | ||
| 75 | hand: null, | ||
| 76 | whichHand: null, | ||
| 77 | hasSpotlight: false, | ||
| 78 | spotlight: null, | ||
| 79 | |||
| 80 | startNearGrab: function(entityID, args) { | ||
| 81 | //this first second parameter in this method contains arguments from the grab script, the first of which is the 'hand' that was used to start the grab | ||
| 82 | this.hand = args[0]; | ||
| 83 | if (!this.hasSpotlight) { | ||
| 84 | |||
| 85 | var modelProperties = Entities.getEntityProperties(this.entityID, ['position', 'rotation']); | ||
| 86 | var lightTransform = evalLightWorldTransform(modelProperties.position, modelProperties.rotation); | ||
| 87 | var glowLightTransform = glowLightWorldTransform(modelProperties.position, modelProperties.rotation); | ||
| 88 | |||
| 89 | |||
| 90 | //this light casts the beam | ||
| 91 | this.spotlight = Entities.addEntity({ | ||
| 92 | type: "Light", | ||
| 93 | isSpotlight: true, | ||
| 94 | dimensions: { | ||
| 95 | x: 2, | ||
| 96 | y: 2, | ||
| 97 | z: 20 | ||
| 98 | }, | ||
| 99 | parentID: this.entityID, | ||
| 100 | color: { | ||
| 101 | red: 255, | ||
| 102 | green: 255, | ||
| 103 | blue: 255 | ||
| 104 | }, | ||
| 105 | intensity: 1, | ||
| 106 | falloffRadius:0.9, | ||
| 107 | exponent: 0.5, | ||
| 108 | cutoff: 20, | ||
| 109 | lifetime: LIFETIME, | ||
| 110 | position: lightTransform.p, | ||
| 111 | rotation: lightTransform.q, | ||
| 112 | }); | ||
| 113 | |||
| 114 | //this light creates the effect of a bulb at the end of the flashlight | ||
| 115 | this.glowLight = Entities.addEntity({ | ||
| 116 | type: "Light", | ||
| 117 | dimensions: { | ||
| 118 | x: 0.25, | ||
| 119 | y: 0.25, | ||
| 120 | z: 0.25 | ||
| 121 | }, | ||
| 122 | parentID: this.entityID, | ||
| 123 | isSpotlight: false, | ||
| 124 | color: { | ||
| 125 | red: 255, | ||
| 126 | green: 255, | ||
| 127 | blue: 255 | ||
| 128 | }, | ||
| 129 | exponent: 0, | ||
| 130 | intensity:1.0, | ||
| 131 | falloffRadius:0.3, | ||
| 132 | lifetime: LIFETIME, | ||
| 133 | cutoff: 90, // in degrees | ||
| 134 | position: glowLightTransform.p, | ||
| 135 | rotation: glowLightTransform.q, | ||
| 136 | |||
| 137 | }); | ||
| 138 | |||
| 139 | this.hasSpotlight = true; | ||
| 140 | |||
| 141 | } | ||
| 142 | |||
| 143 | }, | ||
| 144 | startEquip: function(id, params) { | ||
| 145 | this.startNearGrab(id, params); | ||
| 146 | }, | ||
| 147 | |||
| 148 | setWhichHand: function() { | ||
| 149 | this.whichHand = this.hand; | ||
| 150 | }, | ||
| 151 | |||
| 152 | continueNearGrab: function() { | ||
| 153 | if (this.whichHand === null) { | ||
| 154 | //only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten | ||
| 155 | this.setWhichHand(); | ||
| 156 | } else { | ||
| 157 | this.changeLightWithTriggerPressure(this.whichHand); | ||
| 158 | } | ||
| 159 | }, | ||
| 160 | continueEquip: function(entityID, args) { | ||
| 161 | this.continueNearGrab(entityID, args); | ||
| 162 | }, | ||
| 163 | |||
| 164 | releaseGrab: function(entityID, args) { | ||
| 165 | //delete the lights and reset state | ||
| 166 | if (this.hasSpotlight) { | ||
| 167 | Entities.deleteEntity(this.spotlight); | ||
| 168 | Entities.deleteEntity(this.glowLight); | ||
| 169 | this.hasSpotlight = false; | ||
| 170 | this.glowLight = null; | ||
| 171 | this.spotlight = null; | ||
| 172 | this.whichHand = null; | ||
| 173 | this.lightOn = false; | ||
| 174 | } | ||
| 175 | }, | ||
| 176 | |||
| 177 | releaseEquip: function(entityID, args) { | ||
| 178 | this.releaseGrab(entityID, args); | ||
| 179 | }, | ||
| 180 | |||
| 181 | changeLightWithTriggerPressure: function(flashLightHand) { | ||
| 182 | //read the value of the controller trigger and use it to turn the light on / off when the value reaches certain thresholds | ||
| 183 | if (flashLightHand === 'LEFT') { | ||
| 184 | this.triggerValue = Controller.getValue(Controller.Standard.LT); | ||
| 185 | } | ||
| 186 | if (flashLightHand === 'RIGHT') { | ||
| 187 | this.triggerValue = Controller.getValue(Controller.Standard.RT); | ||
| 188 | |||
| 189 | } | ||
| 190 | |||
| 191 | if (this.triggerValue < DISABLE_LIGHT_THRESHOLD && this.lightOn === true) { | ||
| 192 | this.turnLightOff(); | ||
| 193 | } else if (this.triggerValue >= DISABLE_LIGHT_THRESHOLD && this.lightOn === false) { | ||
| 194 | this.turnLightOn(); | ||
| 195 | } | ||
| 196 | return; | ||
| 197 | }, | ||
| 198 | |||
| 199 | turnLightOff: function() { | ||
| 200 | this.playSoundAtCurrentPosition(false); | ||
| 201 | Entities.editEntity(this.spotlight, { | ||
| 202 | intensity: 0 | ||
| 203 | }); | ||
| 204 | Entities.editEntity(this.glowLight, { | ||
| 205 | intensity: 0 | ||
| 206 | }); | ||
| 207 | this.lightOn = false; | ||
| 208 | }, | ||
| 209 | |||
| 210 | turnLightOn: function() { | ||
| 211 | this.playSoundAtCurrentPosition(true); | ||
| 212 | |||
| 213 | Entities.editEntity(this.glowLight, { | ||
| 214 | intensity: 2 | ||
| 215 | }); | ||
| 216 | Entities.editEntity(this.spotlight, { | ||
| 217 | intensity: 2 | ||
| 218 | }); | ||
| 219 | this.lightOn = true; | ||
| 220 | }, | ||
| 221 | |||
| 222 | playSoundAtCurrentPosition: function(playOnSound) { | ||
| 223 | //when someone grabs, play a clicking noise for turning the flashlight on/off | ||
| 224 | var position = Entities.getEntityProperties(this.entityID, "position").position; | ||
| 225 | |||
| 226 | var audioProperties = { | ||
| 227 | volume: 0.25, | ||
| 228 | position: position | ||
| 229 | }; | ||
| 230 | |||
| 231 | if (playOnSound) { | ||
| 232 | Audio.playSound(this.ON_SOUND, audioProperties); | ||
| 233 | } else { | ||
| 234 | Audio.playSound(this.OFF_SOUND, audioProperties); | ||
| 235 | } | ||
| 236 | }, | ||
| 237 | |||
| 238 | preload: function(entityID) { | ||
| 239 | // preload() will be called when the entity has become visible (or known) to the interface | ||
| 240 | // it gives us a chance to set our local JavaScript object up. In this case it means: | ||
| 241 | // * remembering our entityID, so we can access it in cases where we're called without an entityID | ||
| 242 | // * preloading sounds | ||
| 243 | this.entityID = entityID; | ||
| 244 | this.ON_SOUND = SoundCache.getSound(ON_SOUND_URL); | ||
| 245 | this.OFF_SOUND = SoundCache.getSound(OFF_SOUND_URL); | ||
| 246 | |||
| 247 | }, | ||
| 248 | |||
| 249 | unload: function() { | ||
| 250 | // unload() will be called when our entity is no longer available. It may be because we were deleted, | ||
| 251 | // or because we've left the domain or quit the application. | ||
| 252 | if (this.hasSpotlight) { | ||
| 253 | Entities.deleteEntity(this.spotlight); | ||
| 254 | Entities.deleteEntity(this.glowLight); | ||
| 255 | this.hasSpotlight = false; | ||
| 256 | this.glowLight = null; | ||
| 257 | this.spotlight = null; | ||
| 258 | this.whichHand = null; | ||
| 259 | this.lightOn = false; | ||
| 260 | } | ||
| 261 | |||
| 262 | }, | ||
| 263 | |||
| 264 | }; | ||
| 265 | |||
| 266 | // entity should return a newly constructed object of our type | ||
| 267 | return new Flashlight(); | ||
| 268 | }); | ||
| @@ -0,0 +1,150 @@ | |||
| 1 | // | ||
| 2 | // golfClub.js | ||
| 3 | // | ||
| 4 | // Created by Philip Rosedale on April 11, 2016. | ||
| 5 | // Copyright 2016 High Fidelity, Inc. | ||
| 6 | // | ||
| 7 | // | ||
| 8 | // Distributed under the Apache License, Version 2.0. | ||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 10 | // | ||
| 11 | // A simple golf club. If you have equipped it, and pull trigger, it will either make | ||
| 12 | // you a new golf ball, or take you to your ball if one is not made. | ||
| 13 | |||
| 14 | (function() { | ||
| 15 | var ball = null; | ||
| 16 | var collisionSoundURL = "http://hifi-production.s3.amazonaws.com/tutorials/golfClub/collision1.wav"; | ||
| 17 | var triggerState = false; | ||
| 18 | var BALL_GRAVITY = -9.8; | ||
| 19 | var BALL_START_VELOCITY = 0.1; | ||
| 20 | var BALL_MAX_RANGE = 10; | ||
| 21 | var BALL_DROP_DISTANCE = 0.6; | ||
| 22 | var BALL_DIAMETER = 0.07; | ||
| 23 | var BALL_LIFETIME = 3600; | ||
| 24 | var MAX_BRAKING_SPEED = 0.2; | ||
| 25 | var BALL_BRAKING_RATE = 0.5; | ||
| 26 | |||
| 27 | var TRIGGER_CONTROLS = [ | ||
| 28 | Controller.Standard.LT, | ||
| 29 | Controller.Standard.RT, | ||
| 30 | ]; | ||
| 31 | |||
| 32 | function triggerPulled(hand) { | ||
| 33 | // Return true if the trigger has just been pulled | ||
| 34 | var triggerValue = Controller.getValue(TRIGGER_CONTROLS[hand]); | ||
| 35 | var oldTriggerState = triggerState; | ||
| 36 | var TRIGGER_PULL_THRESHOLD = 0.5; | ||
| 37 | var TRIGGER_RELEASE_THRESHOLD = 0.4; | ||
| 38 | if (triggerValue > TRIGGER_PULL_THRESHOLD) { | ||
| 39 | triggerState = true; | ||
| 40 | } else if (triggerValue < TRIGGER_RELEASE_THRESHOLD) { | ||
| 41 | triggerState = false; | ||
| 42 | } | ||
| 43 | return (triggerState && (oldTriggerState != triggerState)); | ||
| 44 | } | ||
| 45 | |||
| 46 | function ballPosition(ball) { | ||
| 47 | // return the position of this entity | ||
| 48 | var properties = Entities.getEntityProperties(ball, ['position']); | ||
| 49 | if (!properties) { | ||
| 50 | return null; | ||
| 51 | } else { | ||
| 52 | return properties.position; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | function gotoPointOnGround(position, away) { | ||
| 57 | // Position yourself facing in the direction you were originally facing, but with a | ||
| 58 | // point on the ground *away* meters from *position* and in front of you. | ||
| 59 | |||
| 60 | var offset = Quat.getFront(MyAvatar.orientation); | ||
| 61 | offset.y = 0.0; | ||
| 62 | offset = Vec3.multiply(-away, Vec3.normalize(offset)); | ||
| 63 | var newAvatarPosition = Vec3.sum(position, offset); | ||
| 64 | |||
| 65 | // Assuming position is on ground, put me distance from eyes to hips higher, plus a 50% adjust for longer legs. | ||
| 66 | // TODO: Need avatar callback for exact foot-to-hips height. | ||
| 67 | |||
| 68 | var halfHeight = avatarHalfHeight(); | ||
| 69 | print("Height = " + halfHeight); | ||
| 70 | newAvatarPosition.y += (halfHeight * 1.5); | ||
| 71 | MyAvatar.position = newAvatarPosition; | ||
| 72 | } | ||
| 73 | |||
| 74 | function inFrontOfMe() { | ||
| 75 | return Vec3.sum(MyAvatar.position, Vec3.multiply(BALL_DROP_DISTANCE, Quat.getFront(MyAvatar.orientation))); | ||
| 76 | } | ||
| 77 | |||
| 78 | function avatarHalfHeight() { | ||
| 79 | return MyAvatar.getDefaultEyePosition().y - MyAvatar.position.y; | ||
| 80 | } | ||
| 81 | |||
| 82 | function brakeBall(ball) { | ||
| 83 | // Check the ball's velocity and slow it down if beyond a threshold | ||
| 84 | var properties = Entities.getEntityProperties(ball, ['velocity']); | ||
| 85 | if (properties) { | ||
| 86 | var velocity = Vec3.length(properties.velocity); | ||
| 87 | if ((velocity > 0) && (velocity < MAX_BRAKING_SPEED)) { | ||
| 88 | Entities.editEntity(ball, { | ||
| 89 | velocity: Vec3.multiply(BALL_BRAKING_RATE, properties.velocity) | ||
| 90 | }); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | function makeBall(position) { | ||
| 96 | // Create a new sphere entity | ||
| 97 | ball = Entities.addEntity({ | ||
| 98 | type: "Sphere", | ||
| 99 | position: position, | ||
| 100 | color: { | ||
| 101 | red: 255, | ||
| 102 | green: 255, | ||
| 103 | blue: 255 | ||
| 104 | }, | ||
| 105 | dimensions: { | ||
| 106 | x: BALL_DIAMETER, | ||
| 107 | y: BALL_DIAMETER, | ||
| 108 | z: BALL_DIAMETER | ||
| 109 | }, | ||
| 110 | gravity: { | ||
| 111 | x: 0, | ||
| 112 | y: BALL_GRAVITY, | ||
| 113 | z: 0 | ||
| 114 | }, | ||
| 115 | velocity: { | ||
| 116 | x: 0, | ||
| 117 | y: BALL_START_VELOCITY, | ||
| 118 | z: 0 | ||
| 119 | }, | ||
| 120 | friction: 0.5, | ||
| 121 | restitution: 0.5, | ||
| 122 | shapeType: "sphere", | ||
| 123 | dynamic: true, | ||
| 124 | lifetime: BALL_LIFETIME, | ||
| 125 | collisionSoundURL: collisionSoundURL | ||
| 126 | }); | ||
| 127 | } | ||
| 128 | |||
| 129 | function checkClub(params) { | ||
| 130 | var hand = params[0] == "left" ? 0 : 1; | ||
| 131 | var makeNewBall = false; | ||
| 132 | if (triggerPulled(hand)) { | ||
| 133 | // If trigger just pulled, either drop new ball or go to existing one | ||
| 134 | var position = ballPosition(ball); | ||
| 135 | if (position && (Vec3.distance(MyAvatar.position, position) < BALL_MAX_RANGE)) { | ||
| 136 | gotoPointOnGround(position, BALL_DROP_DISTANCE); | ||
| 137 | } else { | ||
| 138 | Entities.deleteEntity(ball); | ||
| 139 | makeBall(inFrontOfMe()); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | brakeBall(ball); | ||
| 143 | } | ||
| 144 | |||
| 145 | this.continueEquip = function(id, params) { | ||
| 146 | // While holding the club, continuously check for trigger pull and brake ball if moving. | ||
| 147 | checkClub(params); | ||
| 148 | } | ||
| 149 | |||
| 150 | }); | ||
| @@ -0,0 +1,177 @@ | |||
| 1 | // pingPongGun.js | ||
| 2 | // | ||
| 3 | // Script Type: Entity | ||
| 4 | // Created by James B. Pollack @imgntn on 9/21/2015 | ||
| 5 | // Copyright 2015 High Fidelity, Inc. | ||
| 6 | // | ||
| 7 | // This script shoots a ping pong ball. | ||
| 8 | // Distributed under the Apache License, Version 2.0. | ||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 10 | // | ||
| 11 | |||
| 12 | (function() { | ||
| 13 | var _this = this; | ||
| 14 | |||
| 15 | var SHOOTING_SOUND_URL = 'http://hifi-production.s3.amazonaws.com/tutorials/pingPongGun/pong_sound.wav'; | ||
| 16 | |||
| 17 | function PingPongGun() { | ||
| 18 | return; | ||
| 19 | } | ||
| 20 | |||
| 21 | //if the trigger value goes below this value, reload the gun. | ||
| 22 | var RELOAD_THRESHOLD = 0.95; | ||
| 23 | var GUN_TIP_FWD_OFFSET = -0.6; | ||
| 24 | var GUN_TIP_UP_OFFSET = 0.12; | ||
| 25 | var GUN_FORCE = 9; | ||
| 26 | var BALL_RESTITUTION = 0.6; | ||
| 27 | var BALL_LINEAR_DAMPING = 0.4; | ||
| 28 | var BALL_GRAVITY = { | ||
| 29 | x: 0, | ||
| 30 | y: -4.8, | ||
| 31 | z: 0 | ||
| 32 | }; | ||
| 33 | |||
| 34 | var PING_PONG_GUN_GRAVITY = { | ||
| 35 | x: 0, | ||
| 36 | y: -10, | ||
| 37 | z: 0 | ||
| 38 | }; | ||
| 39 | |||
| 40 | var BALL_DIMENSIONS = { | ||
| 41 | x: 0.04, | ||
| 42 | y: 0.04, | ||
| 43 | z: 0.04 | ||
| 44 | }; | ||
| 45 | |||
| 46 | |||
| 47 | var BALL_COLOR = { | ||
| 48 | red: 255, | ||
| 49 | green: 255, | ||
| 50 | blue: 255 | ||
| 51 | }; | ||
| 52 | |||
| 53 | var TRIGGER_CONTROLS = [ | ||
| 54 | Controller.Standard.LT, | ||
| 55 | Controller.Standard.RT, | ||
| 56 | ]; | ||
| 57 | |||
| 58 | |||
| 59 | PingPongGun.prototype = { | ||
| 60 | hand: null, | ||
| 61 | gunTipPosition: null, | ||
| 62 | canShoot: false, | ||
| 63 | canShootTimeout: null, | ||
| 64 | |||
| 65 | startEquip: function(entityID, args) { | ||
| 66 | this.hand = args[0] == "left" ? 0 : 1; | ||
| 67 | }, | ||
| 68 | |||
| 69 | continueEquip: function(entityID, args) { | ||
| 70 | if (this.canShootTimeout !== null) { | ||
| 71 | Script.clearTimeout(this.canShootTimeout); | ||
| 72 | } | ||
| 73 | this.checkTriggerPressure(this.hand); | ||
| 74 | }, | ||
| 75 | |||
| 76 | releaseEquip: function(entityID, args) { | ||
| 77 | var _this = this; | ||
| 78 | this.canShootTimeout = Script.setTimeout(function() { | ||
| 79 | _this.canShoot = false; | ||
| 80 | }, 250); | ||
| 81 | }, | ||
| 82 | |||
| 83 | checkTriggerPressure: function(gunHand) { | ||
| 84 | this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[gunHand]); | ||
| 85 | if (this.triggerValue < RELOAD_THRESHOLD) { | ||
| 86 | this.canShoot = true; | ||
| 87 | } else if (this.triggerValue >= RELOAD_THRESHOLD && this.canShoot === true) { | ||
| 88 | var gunProperties = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); | ||
| 89 | this.shootBall(gunProperties); | ||
| 90 | this.canShoot = false; | ||
| 91 | } | ||
| 92 | |||
| 93 | return; | ||
| 94 | }, | ||
| 95 | |||
| 96 | shootBall: function(gunProperties) { | ||
| 97 | var forwardVec = Quat.getFront(Quat.multiply(gunProperties.rotation, Quat.fromPitchYawRollDegrees(0, 180, 0))); | ||
| 98 | forwardVec = Vec3.normalize(forwardVec); | ||
| 99 | forwardVec = Vec3.multiply(forwardVec, GUN_FORCE); | ||
| 100 | |||
| 101 | var properties = { | ||
| 102 | name: 'Tutorial Ping Pong Ball', | ||
| 103 | shapeType: 'sphere', | ||
| 104 | type: 'Sphere', | ||
| 105 | color: BALL_COLOR, | ||
| 106 | dimensions: BALL_DIMENSIONS, | ||
| 107 | damping: BALL_LINEAR_DAMPING, | ||
| 108 | gravity: BALL_GRAVITY, | ||
| 109 | restitution: BALL_RESTITUTION, | ||
| 110 | dynamic: true, | ||
| 111 | rotation: gunProperties.rotation, | ||
| 112 | position: this.getGunTipPosition(gunProperties), | ||
| 113 | gravity: PING_PONG_GUN_GRAVITY, | ||
| 114 | velocity: forwardVec, | ||
| 115 | lifetime: 10 | ||
| 116 | }; | ||
| 117 | |||
| 118 | Entities.addEntity(properties); | ||
| 119 | |||
| 120 | this.playSoundAtCurrentPosition(gunProperties.position); | ||
| 121 | }, | ||
| 122 | |||
| 123 | playSoundAtCurrentPosition: function(position) { | ||
| 124 | var audioProperties = { | ||
| 125 | volume: 0.2, | ||
| 126 | position: position | ||
| 127 | }; | ||
| 128 | |||
| 129 | Audio.playSound(this.SHOOTING_SOUND, audioProperties); | ||
| 130 | }, | ||
| 131 | |||
| 132 | getGunTipPosition: function(properties) { | ||
| 133 | //the tip of the gun is going to be in a different place than the center, so we move in space relative to the model to find that position | ||
| 134 | var frontVector = Quat.getFront(properties.rotation); | ||
| 135 | var frontOffset = Vec3.multiply(frontVector, GUN_TIP_FWD_OFFSET); | ||
| 136 | var upVector = Quat.getUp(properties.rotation); | ||
| 137 | var upOffset = Vec3.multiply(upVector, GUN_TIP_UP_OFFSET); | ||
| 138 | |||
| 139 | var gunTipPosition = Vec3.sum(properties.position, frontOffset); | ||
| 140 | gunTipPosition = Vec3.sum(gunTipPosition, upOffset); | ||
| 141 | |||
| 142 | return gunTipPosition; | ||
| 143 | }, | ||
| 144 | |||
| 145 | preload: function(entityID) { | ||
| 146 | this.entityID = entityID; | ||
| 147 | this.SHOOTING_SOUND = SoundCache.getSound(SHOOTING_SOUND_URL); | ||
| 148 | // this.createTipEntity(entityID); | ||
| 149 | }, | ||
| 150 | createTipEntity: function(entityID) { | ||
| 151 | //for debugging where its going to shoot from | ||
| 152 | var gunProperties = Entities.getEntityProperties(entityID, ["position", "rotation"]); | ||
| 153 | |||
| 154 | var tipProps = { | ||
| 155 | name: 'Ping pong tip test', | ||
| 156 | dimensions: { | ||
| 157 | x: 0.1, | ||
| 158 | y: 0.1, | ||
| 159 | z: 0.1 | ||
| 160 | }, | ||
| 161 | color: { | ||
| 162 | red: 0, | ||
| 163 | green: 255, | ||
| 164 | blue: 0 | ||
| 165 | }, | ||
| 166 | type: 'Box', | ||
| 167 | parentID: entityID, | ||
| 168 | position: this.getGunTipPosition(gunProperties) | ||
| 169 | }; | ||
| 170 | var tip = Entities.addEntity(tipProps); | ||
| 171 | } | ||
| 172 | |||
| 173 | }; | ||
| 174 | |||
| 175 | // entity scripts should return a newly constructed object of our type | ||
| 176 | return new PingPongGun(); | ||
| 177 | }); | ||
| @@ -0,0 +1,28 @@ | |||
| 1 | // | ||
| 2 | // Copyright 2016 High Fidelity, Inc. | ||
| 3 | // | ||
| 4 | // | ||
| 5 | // Distributed under the Apache License, Version 2.0. | ||
| 6 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 7 | // | ||
| 8 | |||
| 9 | (function(){ | ||
| 10 | |||
| 11 | var soundURL ='http://hifi-production.s3.amazonaws.com/tutorials/soundMaker/bell.wav'; | ||
| 12 | var ringSound; | ||
| 13 | |||
| 14 | this.preload = function(entityID) { | ||
| 15 | print("preload("+entityID+")"); | ||
| 16 | ringSound = SoundCache.getSound(soundURL); | ||
| 17 | }; | ||
| 18 | |||
| 19 | this.clickDownOnEntity = function(entityID, mouseEvent) { | ||
| 20 | var bellPosition = Entities.getEntityProperties(entityID).position; | ||
| 21 | print("clickDownOnEntity()..."); | ||
| 22 | Audio.playSound(ringSound, { | ||
| 23 | position: bellPosition, | ||
| 24 | volume: 0.5 | ||
| 25 | }); | ||
| 26 | }; | ||
| 27 | |||
| 28 | }) | ||