History

add some new tutorial JS files

Andrew Meadows committed 10 years ago

Commit 50117e21 parent 3a2cb3713 files · +1613 −0Browse files

Showing the changes to scripts/tutorials/entity_scripts (4 of 13 files). Show all

Unified · Split

4 files
  1. scripts/tutorials/entity_scripts/flashlight.js +268 −0
  2. scripts/tutorials/entity_scripts/golfClub.js +150 −0
  3. scripts/tutorials/entity_scripts/pingPongGun.js +177 −0
  4. scripts/tutorials/entity_scripts/soundMaker.js +28 −0
scripts/tutorials/entity_scripts/flashlight.js+268−0
@@ -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});
scripts/tutorials/entity_scripts/golfClub.js+150−0
@@ -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});
scripts/tutorials/entity_scripts/pingPongGun.js+177−0
@@ -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});
scripts/tutorials/entity_scripts/soundMaker.js+28−0
@@ -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})