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 | +}) | |