Showing the changes to tutorial/tutorial.js (1 of 1 file). Show all
Unified · Split
| @@ -58,11 +58,6 @@ function info() { · 57 unmodified lines | |||
| 58 | } | 58 | } |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | // Return a number between min (inclusive) and max (exclusive) | ||
| 62 | function randomInt(min, max) { | ||
| 63 | return min + Math.floor(Math.random() * (max - min)) | ||
| 64 | } | ||
| 65 | |||
| 66 | var NEAR_BOX_SPAWN_NAME = "tutorial/nearGrab/box_spawn"; | 61 | var NEAR_BOX_SPAWN_NAME = "tutorial/nearGrab/box_spawn"; |
| 67 | var FAR_BOX_SPAWN_NAME = "tutorial/farGrab/box_spawn"; | 62 | var FAR_BOX_SPAWN_NAME = "tutorial/farGrab/box_spawn"; |
| 68 | var GUN_SPAWN_NAME = "tutorial/gun_spawn"; | 63 | var GUN_SPAWN_NAME = "tutorial/gun_spawn"; |
| @@ -78,10 +73,6 @@ function setAwayEnabled(value) { · 9 unmodified lines | |||
| 78 | Messages.sendLocalMessage(CHANNEL_AWAY_ENABLE, message); | 73 | Messages.sendLocalMessage(CHANNEL_AWAY_ENABLE, message); |
| 79 | } | 74 | } |
| 80 | 75 | ||
| 81 | function beginsWithFilter(value, key) { | ||
| 82 | return value.indexOf(properties[key]) == 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | findEntity = function(properties, searchRadius, filterFn) { | 76 | findEntity = function(properties, searchRadius, filterFn) { |
| 86 | var entities = findEntities(properties, searchRadius, filterFn); | 77 | var entities = findEntities(properties, searchRadius, filterFn); |
| 87 | return entities.length > 0 ? entities[0] : null; | 78 | return entities.length > 0 ? entities[0] : null; |
| @@ -116,18 +107,29 @@ findEntities = function(properties, searchRadius, filterFn) { · 28 unmodified lines | |||
| 116 | return matchedEntities; | 107 | return matchedEntities; |
| 117 | } | 108 | } |
| 118 | 109 | ||
| 119 | function setControllerPartsVisible(parts) { | 110 | function findEntitiesWithTag(tag) { |
| 120 | Messages.sendLocalMessage('Controller-Display-Parts', JSON.stringify(parts)); | 111 | return findEntities({ userData: "" }, 10000, function(properties, key, value) { |
| 112 | data = parseJSON(value); | ||
| 113 | return data.tag === tag; | ||
| 114 | }); | ||
| 121 | } | 115 | } |
| 122 | 116 | ||
| 117 | /** | ||
| 118 | * A controller in made up of parts, and each part can have multiple "layers," | ||
| 119 | * which are really just different texures. For example, the "trigger" part | ||
| 120 | * has "normal" and "highlight" layers. | ||
| 121 | */ | ||
| 123 | function setControllerPartLayer(part, layer) { | 122 | function setControllerPartLayer(part, layer) { |
| 124 | data = {}; | 123 | data = {}; |
| 125 | data[part] = layer; | 124 | data[part] = layer; |
| 126 | Messages.sendLocalMessage('Controller-Set-Part-Layer', JSON.stringify(data)); | 125 | Messages.sendLocalMessage('Controller-Set-Part-Layer', JSON.stringify(data)); |
| 127 | } | 126 | } |
| 128 | 127 | ||
| 129 | function spawn(entityData, transform, modifyFn) { | 128 | /** |
| 130 | debug("Creating: ", entityData); | 129 | * @param {object[]} entityPropertiesList A list of properties to |
| 130 | */ | ||
| 131 | function spawn(entityPropertiesList, transform, modifyFn) { | ||
| 132 | debug("Creating: ", entityPropertiesList); | ||
| 131 | if (!transform) { | 133 | if (!transform) { |
| 132 | transform = { | 134 | transform = { |
| 133 | position: { x: 0, y: 0, z: 0 }, | 135 | position: { x: 0, y: 0, z: 0 }, |
| @@ -135,8 +137,8 @@ function spawn(entityData, transform, modifyFn) { · 1 unmodified line | |||
| 135 | } | 137 | } |
| 136 | } | 138 | } |
| 137 | var ids = []; | 139 | var ids = []; |
| 138 | for (var i = 0; i < entityData.length; ++i) { | 140 | for (var i = 0; i < entityPropertiesList.length; ++i) { |
| 139 | var data = entityData[i]; | 141 | var data = entityPropertiesList[i]; |
| 140 | debug("Creating: ", data.name); | 142 | debug("Creating: ", data.name); |
| 141 | data.position = Vec3.sum(transform.position, data.position); | 143 | data.position = Vec3.sum(transform.position, data.position); |
| 142 | data.rotation = Quat.multiply(data.rotation, transform.rotation); | 144 | data.rotation = Quat.multiply(data.rotation, transform.rotation); |
| @@ -150,6 +152,12 @@ function spawn(entityData, transform, modifyFn) { · 7 unmodified lines | |||
| 150 | return ids; | 152 | return ids; |
| 151 | } | 153 | } |
| 152 | 154 | ||
| 155 | /** | ||
| 156 | * @function parseJSON | ||
| 157 | * @param {string} jsonString The string to parse. | ||
| 158 | * @return {object} Return an empty if the string was not valid JSON, otherwise | ||
| 159 | * the parsed object is returned. | ||
| 160 | */ | ||
| 153 | function parseJSON(jsonString) { | 161 | function parseJSON(jsonString) { |
| 154 | var data; | 162 | var data; |
| 155 | try { | 163 | try { |
| @@ -160,6 +168,10 @@ function parseJSON(jsonString) { · 4 unmodified lines | |||
| 160 | return data; | 168 | return data; |
| 161 | } | 169 | } |
| 162 | 170 | ||
| 171 | /** | ||
| 172 | * Spawn entities with `tag` in the userData. | ||
| 173 | * @function spawnWithTag | ||
| 174 | */ | ||
| 163 | function spawnWithTag(entityData, transform, tag) { | 175 | function spawnWithTag(entityData, transform, tag) { |
| 164 | function modifyFn(data) { | 176 | function modifyFn(data) { |
| 165 | var userData = parseJSON(data.userData); | 177 | var userData = parseJSON(data.userData); |
| @@ -171,6 +183,10 @@ function spawnWithTag(entityData, transform, tag) { · 5 unmodified lines | |||
| 171 | return spawn(entityData, transform, modifyFn); | 183 | return spawn(entityData, transform, modifyFn); |
| 172 | } | 184 | } |
| 173 | 185 | ||
| 186 | /** | ||
| 187 | * Delete all entities with the tag `tag` in their userData. | ||
| 188 | * @function deleteEntitiesWithTag | ||
| 189 | */ | ||
| 174 | function deleteEntitiesWithTag(tag) { | 190 | function deleteEntitiesWithTag(tag) { |
| 175 | debug("searching for...:", tag); | 191 | debug("searching for...:", tag); |
| 176 | var entityIDs = findEntitiesWithTag(tag); | 192 | var entityIDs = findEntitiesWithTag(tag); |
| @@ -178,6 +194,7 @@ function deleteEntitiesWithTag(tag) { · 1 unmodified line | |||
| 178 | Entities.deleteEntity(entityIDs[i]); | 194 | Entities.deleteEntity(entityIDs[i]); |
| 179 | } | 195 | } |
| 180 | } | 196 | } |
| 197 | |||
| 181 | function editEntitiesWithTag(tag, propertiesOrFn) { | 198 | function editEntitiesWithTag(tag, propertiesOrFn) { |
| 182 | var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag]; | 199 | var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag]; |
| 183 | 200 | ||
| @@ -194,19 +211,117 @@ function editEntitiesWithTag(tag, propertiesOrFn) { · 10 unmodified lines | |||
| 194 | } | 211 | } |
| 195 | } | 212 | } |
| 196 | 213 | ||
| 197 | function findEntitiesWithTag(tag) { | ||
| 198 | return findEntities({ userData: "" }, 10000, function(properties, key, value) { | ||
| 199 | data = parseJSON(value); | ||
| 200 | return data.tag == tag; | ||
| 201 | }); | ||
| 202 | } | ||
| 203 | |||
| 204 | // From http://stackoverflow.com/questions/5999998/how-can-i-check-if-a-javascript-variable-is-function-type | 214 | // From http://stackoverflow.com/questions/5999998/how-can-i-check-if-a-javascript-variable-is-function-type |
| 205 | function isFunction(functionToCheck) { | 215 | function isFunction(functionToCheck) { |
| 206 | var getType = {}; | 216 | var getType = {}; |
| 207 | return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; | 217 | return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; |
| 208 | } | 218 | } |
| 209 | 219 | ||
| 220 | /** | ||
| 221 | * Return `true` if `entityID` can be found in the local entity tree, otherwise `false`. | ||
| 222 | */ | ||
| 223 | function isEntityInLocalTree(entityID) { | ||
| 224 | return Entities.getEntityProperties(entityID, 'visible').visible !== undefined; | ||
| 225 | } | ||
| 226 | |||
| 227 | /** | ||
| 228 | * | ||
| 229 | */ | ||
| 230 | function showEntitiesWithTag(tag) { | ||
| 231 | var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag]; | ||
| 232 | if (entities) { | ||
| 233 | for (entityID in entities) { | ||
| 234 | var data = entities[entityID]; | ||
| 235 | |||
| 236 | var collisionless = data.visible === false ? true : false; | ||
| 237 | if (data.collidable !== undefined) { | ||
| 238 | collisionless = data.collidable === true ? false : true; | ||
| 239 | } | ||
| 240 | if (data.soundKey) { | ||
| 241 | data.soundKey.playing = true; | ||
| 242 | } | ||
| 243 | var newProperties = { | ||
| 244 | visible: data.visible == false ? false : true, | ||
| 245 | collisionless: collisionless, | ||
| 246 | userData: JSON.stringify(data), | ||
| 247 | }; | ||
| 248 | debug("Showing: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID)); | ||
| 249 | Entities.editEntity(entityID, newProperties); | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | // Dynamic method, suppressed for now | ||
| 254 | return; | ||
| 255 | editEntitiesWithTag(tag, function(entityID) { | ||
| 256 | var userData = Entities.getEntityProperties(entityID, "userData").userData; | ||
| 257 | var data = parseJSON(userData); | ||
| 258 | var collisionless = data.visible === false ? true : false; | ||
| 259 | if (data.collidable !== undefined) { | ||
| 260 | collisionless = data.collidable === true ? false : true; | ||
| 261 | } | ||
| 262 | if (data.soundKey) { | ||
| 263 | data.soundKey.playing = true; | ||
| 264 | } | ||
| 265 | var newProperties = { | ||
| 266 | visible: data.visible == false ? false : true, | ||
| 267 | collisionless: collisionless, | ||
| 268 | userData: JSON.stringify(data), | ||
| 269 | }; | ||
| 270 | Entities.editEntity(entityID, newProperties); | ||
| 271 | }); | ||
| 272 | } | ||
| 273 | |||
| 274 | /** | ||
| 275 | * @function hideEntitiesWithTag | ||
| 276 | */ | ||
| 277 | function hideEntitiesWithTag(tag) { | ||
| 278 | var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag]; | ||
| 279 | if (entities) { | ||
| 280 | for (entityID in entities) { | ||
| 281 | var data = entities[entityID]; | ||
| 282 | |||
| 283 | if (data.soundKey) { | ||
| 284 | data.soundKey.playing = false; | ||
| 285 | } | ||
| 286 | var newProperties = { | ||
| 287 | visible: false, | ||
| 288 | collisionless: 1, | ||
| 289 | ignoreForCollisions: 1, | ||
| 290 | userData: JSON.stringify(data), | ||
| 291 | }; | ||
| 292 | |||
| 293 | debug("Hiding: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID)); | ||
| 294 | Entities.editEntity(entityID, newProperties); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | // Dynamic method, suppressed for now | ||
| 299 | return; | ||
| 300 | editEntitiesWithTag(tag, function(entityID) { | ||
| 301 | var userData = Entities.getEntityProperties(entityID, "userData").userData; | ||
| 302 | var data = parseJSON(userData); | ||
| 303 | if (data.soundKey) { | ||
| 304 | data.soundKey.playing = false; | ||
| 305 | } | ||
| 306 | var newProperties = { | ||
| 307 | visible: false, | ||
| 308 | collisionless: 1, | ||
| 309 | ignoreForCollisions: 1, | ||
| 310 | userData: JSON.stringify(data), | ||
| 311 | }; | ||
| 312 | Entities.editEntity(entityID, newProperties); | ||
| 313 | }); | ||
| 314 | } | ||
| 315 | |||
| 316 | // Return the entity properties for an entity with a given name if it is in our | ||
| 317 | // cached list of entities. Otherwise, return undefined. | ||
| 318 | function getEntityWithName(name) { | ||
| 319 | debug("Getting entity with name:", name); | ||
| 320 | var entityID = TUTORIAL_NAME_TO_ENTITY_PROPERTIES_MAP[name]; | ||
| 321 | debug("Entity id: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID)); | ||
| 322 | return entityID; | ||
| 323 | } | ||
| 324 | |||
| 210 | function playSuccessSound() { | 325 | function playSuccessSound() { |
| 211 | Audio.playSound(successSound, { | 326 | Audio.playSound(successSound, { |
| 212 | position: MyAvatar.position, | 327 | position: MyAvatar.position, |
| @@ -215,7 +330,6 @@ function playSuccessSound() { · 2 unmodified lines | |||
| 215 | }); | 330 | }); |
| 216 | } | 331 | } |
| 217 | 332 | ||
| 218 | |||
| 219 | function playFirecrackerSound(position) { | 333 | function playFirecrackerSound(position) { |
| 220 | Audio.playSound(firecrackerSound, { | 334 | Audio.playSound(firecrackerSound, { |
| 221 | position: position, | 335 | position: position, |
| @@ -400,7 +514,6 @@ stepNearGrab.prototype = { · 178 unmodified lines | |||
| 400 | 514 | ||
| 401 | setControllerPartLayer('tips', 'trigger'); | 515 | setControllerPartLayer('tips', 'trigger'); |
| 402 | setControllerPartLayer('trigger', 'highlight'); | 516 | setControllerPartLayer('trigger', 'highlight'); |
| 403 | var tag = this.tag; | ||
| 404 | 517 | ||
| 405 | // Spawn content set | 518 | // Spawn content set |
| 406 | showEntitiesWithTag(this.tag, { visible: true }); | 519 | showEntitiesWithTag(this.tag, { visible: true }); |
| @@ -871,101 +984,6 @@ stepCleanupFinish.prototype = { · 464 unmodified lines | |||
| 871 | 984 | ||
| 872 | 985 | ||
| 873 | 986 | ||
| 874 | function isEntityInLocalTree(entityID) { | ||
| 875 | return Entities.getEntityProperties(entityID, 'visible').visible !== undefined; | ||
| 876 | } | ||
| 877 | |||
| 878 | function showEntitiesWithTag(tag) { | ||
| 879 | var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag]; | ||
| 880 | if (entities) { | ||
| 881 | for (entityID in entities) { | ||
| 882 | var data = entities[entityID]; | ||
| 883 | |||
| 884 | var collisionless = data.visible === false ? true : false; | ||
| 885 | if (data.collidable !== undefined) { | ||
| 886 | collisionless = data.collidable === true ? false : true; | ||
| 887 | } | ||
| 888 | if (data.soundKey) { | ||
| 889 | data.soundKey.playing = true; | ||
| 890 | } | ||
| 891 | var newProperties = { | ||
| 892 | visible: data.visible == false ? false : true, | ||
| 893 | collisionless: collisionless, | ||
| 894 | userData: JSON.stringify(data), | ||
| 895 | }; | ||
| 896 | debug("Showing: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID)); | ||
| 897 | Entities.editEntity(entityID, newProperties); | ||
| 898 | } | ||
| 899 | } | ||
| 900 | |||
| 901 | // Dynamic method, suppressed for now | ||
| 902 | return; | ||
| 903 | editEntitiesWithTag(tag, function(entityID) { | ||
| 904 | var userData = Entities.getEntityProperties(entityID, "userData").userData; | ||
| 905 | var data = parseJSON(userData); | ||
| 906 | var collisionless = data.visible === false ? true : false; | ||
| 907 | if (data.collidable !== undefined) { | ||
| 908 | collisionless = data.collidable === true ? false : true; | ||
| 909 | } | ||
| 910 | if (data.soundKey) { | ||
| 911 | data.soundKey.playing = true; | ||
| 912 | } | ||
| 913 | var newProperties = { | ||
| 914 | visible: data.visible == false ? false : true, | ||
| 915 | collisionless: collisionless, | ||
| 916 | userData: JSON.stringify(data), | ||
| 917 | }; | ||
| 918 | Entities.editEntity(entityID, newProperties); | ||
| 919 | }); | ||
| 920 | } | ||
| 921 | |||
| 922 | function hideEntitiesWithTag(tag) { | ||
| 923 | var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag]; | ||
| 924 | if (entities) { | ||
| 925 | for (entityID in entities) { | ||
| 926 | var data = entities[entityID]; | ||
| 927 | |||
| 928 | if (data.soundKey) { | ||
| 929 | data.soundKey.playing = false; | ||
| 930 | } | ||
| 931 | var newProperties = { | ||
| 932 | visible: false, | ||
| 933 | collisionless: 1, | ||
| 934 | ignoreForCollisions: 1, | ||
| 935 | userData: JSON.stringify(data), | ||
| 936 | }; | ||
| 937 | |||
| 938 | debug("Hiding: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID)); | ||
| 939 | Entities.editEntity(entityID, newProperties); | ||
| 940 | } | ||
| 941 | } | ||
| 942 | |||
| 943 | // Dynamic method, suppressed for now | ||
| 944 | return; | ||
| 945 | editEntitiesWithTag(tag, function(entityID) { | ||
| 946 | var userData = Entities.getEntityProperties(entityID, "userData").userData; | ||
| 947 | var data = parseJSON(userData); | ||
| 948 | if (data.soundKey) { | ||
| 949 | data.soundKey.playing = false; | ||
| 950 | } | ||
| 951 | var newProperties = { | ||
| 952 | visible: false, | ||
| 953 | collisionless: 1, | ||
| 954 | ignoreForCollisions: 1, | ||
| 955 | userData: JSON.stringify(data), | ||
| 956 | }; | ||
| 957 | Entities.editEntity(entityID, newProperties); | ||
| 958 | }); | ||
| 959 | } | ||
| 960 | |||
| 961 | // Return the entity properties for an entity with a given name if it is in our | ||
| 962 | // cached list of entities. Otherwise, return undefined. | ||
| 963 | function getEntityWithName(name) { | ||
| 964 | debug("Getting entity with name:", name); | ||
| 965 | var entityID = TUTORIAL_NAME_TO_ENTITY_PROPERTIES_MAP[name]; | ||
| 966 | debug("Entity id: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID)); | ||
| 967 | return entityID; | ||
| 968 | } | ||
| 969 | 987 | ||
| 970 | 988 | ||
| 971 | TutorialManager = function() { | 989 | TutorialManager = function() { |
| @@ -1085,6 +1103,25 @@ TutorialManager = function() { · 113 unmodified lines | |||
| 1085 | 1103 | ||
| 1086 | // To run the tutorial: | 1104 | // To run the tutorial: |
| 1087 | // | 1105 | // |
| 1088 | // var tutorialManager = new TutorialManager(); | 1106 | var tutorialManager = new TutorialManager(); |
| 1089 | // tutorialManager.startTutorial(); | 1107 | tutorialManager.startTutorial(); |
| 1090 | // | 1108 | |
| 1109 | |||
| 1110 | var keyReleaseHandler = function(event) { | ||
| 1111 | if (event.isShifted && event.isAlt) { | ||
| 1112 | print('here', event.text); | ||
| 1113 | if (event.text == "F12") { | ||
| 1114 | if (!tutorialManager.startNextStep()) { | ||
| 1115 | tutorialManager.startTutorial(); | ||
| 1116 | } | ||
| 1117 | } else if (event.text == "F11") { | ||
| 1118 | tutorialManager.restartStep(); | ||
| 1119 | } else if (event.text == "F10") { | ||
| 1120 | MyAvatar.shouldRenderLocally = !MyAvatar.shouldRenderLocally; | ||
| 1121 | } else if (event.text == "r") { | ||
| 1122 | tutorialManager.stopTutorial(); | ||
| 1123 | tutorialManager.startTutorial(); | ||
| 1124 | } | ||
| 1125 | } | ||
| 1126 | }; | ||
| 1127 | Controller.keyReleaseEvent.connect(keyReleaseHandler); | ||