mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-17 00:06:47 +02:00
Merge pull request #10713 from huffman/feat/remove-tutorial
Remove /tutorial in favor of new repo
This commit is contained in:
commit
87a6b16d16
17 changed files with 0 additions and 3251 deletions
|
@ -1,308 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
/*jslint nomen: true, plusplus: true, vars: true*/
|
||||
/*global AvatarList, Entities, EntityViewer, Script, SoundCache, Audio, print, randFloat*/
|
||||
//
|
||||
// ACAudioSearchAndInject.js
|
||||
// audio
|
||||
//
|
||||
// Created by Eric Levin and Howard Stearns 2/1/2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Keeps track of all sounds within QUERY_RADIUS of an avatar, where a "sound" is specified in entity userData.
|
||||
// Inject as many as practical into the audio mixer.
|
||||
// See acAudioSearchAndCompatibilityEntitySpawner.js.
|
||||
//
|
||||
// This implementation takes some precautions to scale well:
|
||||
// - It doesn't hastle the entity server because it issues at most one octree query every UPDATE_TIME period, regardless of the number of avatars.
|
||||
// - It does not load itself because it only gathers entities once every UPDATE_TIME period, and only
|
||||
// checks entity properties for those small number of entities that are currently playing (plus a RECHECK_TIME period examination of all entities).
|
||||
// This implementation tries to use all the available injectors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
var MSEC_PER_SEC = 1000;
|
||||
var SOUND_DATA_KEY = "io.highfidelity.soundKey"; // Sound data is specified in userData under this key.
|
||||
var old_sound_data_key = "soundKey"; // For backwards compatibility.
|
||||
var QUERY_RADIUS = 50; // meters
|
||||
var UPDATE_TIME = 100; // ms. We'll update just one thing on this period.
|
||||
var EXPIRATION_TIME = 5 * MSEC_PER_SEC; // ms. Remove sounds that have been out of range for this time.
|
||||
var RECHECK_TIME = 10 * MSEC_PER_SEC; // ms. Check for new userData properties this often when not currently playing.
|
||||
// (By not checking most of the time when not playing, we can efficiently go through all entities without getEntityProperties.)
|
||||
var UPDATES_PER_STATS_LOG = RECHECK_TIME / UPDATE_TIME; // (It's nice to smooth out the results by straddling a recheck.)
|
||||
|
||||
var DEFAULT_SOUND_DATA = {
|
||||
volume: 0.5, // userData cannot specify zero volume with our current method of defaulting.
|
||||
loop: false, // Default must be false with our current method of defaulting, else there's no way to get a false value.
|
||||
playbackGap: MSEC_PER_SEC, // in ms
|
||||
playbackGapRange: 0 // in ms
|
||||
};
|
||||
|
||||
//var AGENT_AVATAR_POSITION = { x: -1.5327, y: 0.672515, z: 5.91573 };
|
||||
var AGENT_AVATAR_POSITION = { x: -2.83785, y: 1.45243, z: -13.6042 };
|
||||
|
||||
//var isACScript = this.EntityViewer !== undefined;
|
||||
var isACScript = true;
|
||||
|
||||
if (isACScript) {
|
||||
Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList.
|
||||
Avatar.skeletonModelURL = "http://hifi-content.s3.amazonaws.com/ozan/dev/avatars/invisible_avatar/invisible_avatar.fst";
|
||||
Avatar.position = AGENT_AVATAR_POSITION;
|
||||
Agent.isListeningToAudioStream = true;
|
||||
}
|
||||
function ignore() {}
|
||||
function debug() { // Display the arguments not just [Object object].
|
||||
//print.apply(null, [].map.call(arguments, JSON.stringify));
|
||||
}
|
||||
|
||||
function randFloat(low, high) {
|
||||
return low + Math.random() * (high - low);
|
||||
}
|
||||
|
||||
if (isACScript) {
|
||||
EntityViewer.setCenterRadius(QUERY_RADIUS);
|
||||
}
|
||||
|
||||
// ENTITY DATA CACHE
|
||||
//
|
||||
var entityCache = {}; // A dictionary of unexpired EntityData objects.
|
||||
var entityInvalidUserDataCache = {}; // A cache containing the entity IDs that have
|
||||
// previously been identified as containing non-JSON userData.
|
||||
// We use a dictionary here so id lookups are constant time.
|
||||
var examinationCount = 0;
|
||||
function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about.
|
||||
// This data is only use for our sound injection. There is no need to store such info in the replicated entity on everyone's computer.
|
||||
var that = this;
|
||||
that.lastUserDataUpdate = 0; // new entity is in need of rechecking user data
|
||||
// State Transitions:
|
||||
// no data => no data | sound data | expired
|
||||
// expired => stop => remove
|
||||
// sound data => downloading
|
||||
// downloading => downloading | waiting
|
||||
// waiting => playing | waiting (if too many already playing)
|
||||
// playing => update position etc | no data
|
||||
that.stop = function stop() {
|
||||
if (!that.sound) {
|
||||
return;
|
||||
}
|
||||
print("stopping sound", entityIdentifier, that.url);
|
||||
delete that.sound;
|
||||
delete that.url;
|
||||
if (!that.injector) {
|
||||
return;
|
||||
}
|
||||
that.injector.stop();
|
||||
delete that.injector;
|
||||
};
|
||||
this.update = function stateTransitions(expirationCutoff, userDataCutoff, now) {
|
||||
if (that.timestamp < expirationCutoff) { // EXPIRED => STOP => REMOVE
|
||||
that.stop(); // Alternatively, we could fade out and then stop...
|
||||
delete entityCache[entityIdentifier];
|
||||
return;
|
||||
}
|
||||
var properties, soundData; // Latest data, pulled from local octree.
|
||||
|
||||
// getEntityProperties locks the tree, which competes with the asynchronous processing of queryOctree results.
|
||||
// Most entity updates are fast and only a very few do getEntityProperties.
|
||||
function ensureSoundData() { // We only getEntityProperities when we need to.
|
||||
if (properties) {
|
||||
return;
|
||||
}
|
||||
properties = Entities.getEntityProperties(entityIdentifier, ['userData', 'position']);
|
||||
examinationCount++; // Collect statistics on how many getEntityProperties we do.
|
||||
debug("updating", that, properties);
|
||||
try {
|
||||
var userData = properties.userData && JSON.parse(properties.userData);
|
||||
soundData = userData && (userData[SOUND_DATA_KEY] || userData[old_sound_data_key]); // Don't store soundData yet. Let state changes compare.
|
||||
that.lastUserDataUpdate = now; // But do update these ...
|
||||
that.url = soundData && soundData.url;
|
||||
that.playAfter = that.url && now;
|
||||
} catch (err) {
|
||||
if (!(entityIdentifier in entityInvalidUserDataCache)) {
|
||||
print(err, properties.userData);
|
||||
entityInvalidUserDataCache[entityIdentifier] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stumbling on big new pile of entities will do a lot of getEntityProperties. Once.
|
||||
if (that.lastUserDataUpdate < userDataCutoff) { // NO DATA => SOUND DATA
|
||||
ensureSoundData();
|
||||
}
|
||||
|
||||
if (!that.url) { // NO DATA => NO DATA
|
||||
return that.stop();
|
||||
}
|
||||
|
||||
if (!that.sound) { // SOUND DATA => DOWNLOADING
|
||||
that.sound = SoundCache.getSound(soundData.url); // SoundCache can manage duplicates better than we can.
|
||||
}
|
||||
|
||||
if (!that.sound.downloaded) { // DOWNLOADING => DOWNLOADING
|
||||
return;
|
||||
}
|
||||
|
||||
if (that.playAfter > now) { // DOWNLOADING | WAITING => WAITING
|
||||
return;
|
||||
}
|
||||
|
||||
ensureSoundData(); // We'll try to play/setOptions and will need position, so we might as well get soundData, too.
|
||||
if (soundData.url !== that.url) { // WAITING => NO DATA (update next time around)
|
||||
return that.stop();
|
||||
}
|
||||
|
||||
var options = {
|
||||
position: properties.position,
|
||||
loop: soundData.loop || DEFAULT_SOUND_DATA.loop,
|
||||
volume: soundData.volume || DEFAULT_SOUND_DATA.volume
|
||||
};
|
||||
|
||||
function repeat() {
|
||||
return !options.loop && (soundData.playbackGap >= 0);
|
||||
}
|
||||
|
||||
function randomizedNextPlay() { // time of next play or recheck, randomized to distribute the work
|
||||
var range = soundData.playbackGapRange || DEFAULT_SOUND_DATA.playbackGapRange,
|
||||
base = repeat() ? ((that.sound.duration * MSEC_PER_SEC) + (soundData.playbackGap || DEFAULT_SOUND_DATA.playbackGap)) : RECHECK_TIME;
|
||||
return now + base + randFloat(-Math.min(base, range), range);
|
||||
}
|
||||
|
||||
if (that.injector && soundData.playing === false) {
|
||||
that.injector.stop();
|
||||
that.injector = null;
|
||||
}
|
||||
|
||||
if (!that.injector) {
|
||||
if (soundData.playing === false) { // WAITING => PLAYING | WAITING
|
||||
return;
|
||||
}
|
||||
debug("starting", that, options);
|
||||
that.injector = Audio.playSound(that.sound, options); // Might be null if at at injector limit. Will try again later.
|
||||
if (that.injector) {
|
||||
print("started", entityIdentifier, that.url);
|
||||
} else { // Don't hammer ensureSoundData or injector manager.
|
||||
that.playAfter = randomizedNextPlay();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC
|
||||
if (!that.injector.playing) { // Subtle: a looping sound will not check playbackGap.
|
||||
if (repeat()) { // WAITING => PLAYING
|
||||
// Setup next play just once, now. Changes won't be looked at while we wait.
|
||||
that.playAfter = randomizedNextPlay();
|
||||
// Subtle: if the restart fails b/c we're at injector limit, we won't try again until next playAfter.
|
||||
that.injector.restart();
|
||||
} else { // PLAYING => NO DATA
|
||||
that.playAfter = Infinity; // was one-shot and we're finished
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar) {
|
||||
ignore(avatarPosition, avatar); // We could use avatars and/or avatarPositions to prioritize which ones to play.
|
||||
var entitySound = entityCache[entityIdentifier];
|
||||
if (!entitySound) {
|
||||
entitySound = entityCache[entityIdentifier] = new EntityDatum(entityIdentifier);
|
||||
}
|
||||
entitySound.timestamp = timestamp; // Might be updated for multiple avatars. That's fine.
|
||||
}
|
||||
|
||||
var nUpdates = UPDATES_PER_STATS_LOG, lastStats = Date.now();
|
||||
|
||||
function updateAllEntityData() { // A fast update of all entities we know about. A few make sounds.
|
||||
var now = Date.now(),
|
||||
expirationCutoff = now - EXPIRATION_TIME,
|
||||
userDataRecheckCutoff = now - RECHECK_TIME;
|
||||
Object.keys(entityCache).forEach(function (entityIdentifier) {
|
||||
entityCache[entityIdentifier].update(expirationCutoff, userDataRecheckCutoff, now);
|
||||
});
|
||||
if (nUpdates-- <= 0) { // Report statistics.
|
||||
// For example, with:
|
||||
// injector-limit = 40 (in C++ code)
|
||||
// N_SOUNDS = 1000 (from userData in, e.g., acAudioSearchCompatibleEntitySpawner.js)
|
||||
// replay-period = 3 + 20 = 23 (seconds, ditto)
|
||||
// stats-period = UPDATES_PER_STATS_LOG * UPDATE_TIME / MSEC_PER_SEC = 10 seconds
|
||||
// The log should show between each stats report:
|
||||
// "start" lines ~= injector-limit * P(finish) = injector-limit * stats-period/replay-period = 17 ?
|
||||
// total attempts at starting ("start" lines + "could not thread" lines) ~= N_SOUNDS = 1000 ?
|
||||
// entities > N_SOUNDS * (1+ N_SILENT_ENTITIES_PER_SOUND) = 11000 + whatever was in the scene before running spawner
|
||||
// sounds = N_SOUNDS = 1000
|
||||
// getEntityPropertiesPerUpdate ~= playing + failed-starts/UPDATES_PER_STATS_LOG + other-rechecks-each-update
|
||||
// = injector-limit + (total attempts - "start" lines)/UPDATES_PER_STATS__LOG
|
||||
// + (entities - playing - failed-starts/UPDATES_PER_STATS_LOG) * P(recheck-in-update)
|
||||
// where failed-starts/UPDATES_PER_STATS_LOG = (1000-17)/100 = 10
|
||||
// = 40 + 10 + (11000 - 40 - 10)*UPDATE_TIME/RECHECK_TIME
|
||||
// = 40 + 10 + 10950*0.01 = 159 (mostly proportional to enties/RECHECK_TIME)
|
||||
// millisecondsPerUpdate ~= UPDATE_TIME = 100 (+ some timer machinery time)
|
||||
// this assignment client activity monitor < 100% cpu
|
||||
var stats = {
|
||||
entities: 0,
|
||||
sounds: 0,
|
||||
playing: 0,
|
||||
getEntityPropertiesPerUpdate: examinationCount / UPDATES_PER_STATS_LOG,
|
||||
millisecondsPerUpdate: (now - lastStats) / UPDATES_PER_STATS_LOG
|
||||
};
|
||||
nUpdates = UPDATES_PER_STATS_LOG;
|
||||
lastStats = now;
|
||||
examinationCount = 0;
|
||||
Object.keys(entityCache).forEach(function (entityIdentifier) {
|
||||
var datum = entityCache[entityIdentifier];
|
||||
stats.entities++;
|
||||
if (datum.url) {
|
||||
stats.sounds++;
|
||||
if (datum.injector && datum.injector.playing) {
|
||||
stats.playing++;
|
||||
}
|
||||
}
|
||||
});
|
||||
print(JSON.stringify(stats));
|
||||
}
|
||||
}
|
||||
|
||||
// Update the set of which EntityData we know about.
|
||||
//
|
||||
function updateEntiesForAvatar(avatarIdentifier) { // Just one piece of update work.
|
||||
// This does at most:
|
||||
// one queryOctree request of the entity server, and
|
||||
// one findEntities geometry query of our own octree, and
|
||||
// a quick internEntityDatum of each of what may be a large number of entityIdentifiers.
|
||||
// The idea is that this is a nice bounded piece of work that should not be done too frequently.
|
||||
// However, it means that we won't learn about new entities until, on average (nAvatars * UPDATE_TIME) + query round trip.
|
||||
var avatar = AvatarList.getAvatar(avatarIdentifier), avatarPosition = avatar && avatar.position;
|
||||
if (!avatarPosition) { // No longer here.
|
||||
return;
|
||||
}
|
||||
var timestamp = Date.now();
|
||||
if (isACScript) {
|
||||
EntityViewer.setPosition(avatarPosition);
|
||||
EntityViewer.queryOctree(); // Requests an update, but there's no telling when we'll actually see different results.
|
||||
}
|
||||
var entities = Entities.findEntities(avatarPosition, QUERY_RADIUS);
|
||||
debug("found", entities.length, "entities near", avatar.name || "unknown", "at", avatarPosition);
|
||||
entities.forEach(function (entityIdentifier) {
|
||||
internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar);
|
||||
});
|
||||
}
|
||||
|
||||
// Slowly update the set of data we have to work with.
|
||||
//
|
||||
var workQueue = [];
|
||||
function updateWorkQueueForAvatarsPresent() { // when nothing else to do, fill queue with individual avatar updates
|
||||
workQueue = AvatarList.getAvatarIdentifiers().map(function (avatarIdentifier) {
|
||||
return function () {
|
||||
updateEntiesForAvatar(avatarIdentifier);
|
||||
};
|
||||
});
|
||||
}
|
||||
Script.setInterval(function () {
|
||||
// There might be thousands of EntityData known to us, but only a few will require any work to update.
|
||||
updateAllEntityData(); // i.e., this better be pretty fast.
|
||||
// Each interval, we do no more than one updateEntitiesforAvatar.
|
||||
if (!workQueue.length) {
|
||||
workQueue = [updateWorkQueueForAvatarsPresent];
|
||||
}
|
||||
workQueue.pop()(); // There's always one
|
||||
}, UPDATE_TIME);
|
|
@ -1,3 +0,0 @@
|
|||
* home-tutorial-34
|
||||
* Update tutorial to only start if `HMD.active`
|
||||
* Update builder's grid to use "Good - Sub-meshes" for collision shape type
|
|
@ -1,131 +0,0 @@
|
|||
fireworkURLs = [
|
||||
"atp:/tutorial_models/bomb1.fbx",
|
||||
"atp:/tutorial_models/bomb2.fbx",
|
||||
"atp:/tutorial_models/bomb3.fbx",
|
||||
"atp:/tutorial_models/bomb4.fbx",
|
||||
"atp:/tutorial_models/bomb5.fbx",
|
||||
"atp:/tutorial_models/bomb6.fbx",
|
||||
];
|
||||
|
||||
fireworkBaseProps = {
|
||||
"collisionsWillMove": 1,
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -0.2,
|
||||
z: 0
|
||||
},
|
||||
"dynamic": 1,
|
||||
"gravity": {
|
||||
"x": 0,
|
||||
"y": -10,
|
||||
"z": 0
|
||||
},
|
||||
"id": "{1c4061bc-b2e7-4435-bc47-3fcc39ae6624}",
|
||||
"modelURL": "atp:/tutorial_models/bomb1.fbx",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"x": 0.11612319946289062,
|
||||
"y": 0,
|
||||
"z": 0.21749019622802734
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.24519434571266174,
|
||||
"x": -0.0064739733934402466,
|
||||
"y": -0.12259717285633087,
|
||||
"z": 0.094893023371696472
|
||||
},
|
||||
"rotation": {
|
||||
"w": -0.083054840564727783,
|
||||
"x": 0.93615627288818359,
|
||||
"y": 0.34154272079467773,
|
||||
"z": -0.0073701143264770508
|
||||
},
|
||||
"shapeType": "simple-hull",
|
||||
"type": "Model",
|
||||
"userData": "{\n \"hifiHomeKey\": {\n \"reset\": true\n }\n}"
|
||||
} ;
|
||||
|
||||
|
||||
birdFirework2 = {
|
||||
"collisionsWillMove": 1,
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -0.01,
|
||||
z: 0
|
||||
},
|
||||
"dynamic": 1,
|
||||
"gravity": {
|
||||
"x": 0,
|
||||
"y": -10,
|
||||
"z": 0
|
||||
},
|
||||
"id": "{ba067084-8d0f-4eeb-a8a1-c6814527c1bb}",
|
||||
"modelURL": "atp:/tutorial_models/bomb2.fbx",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0.014694660902023315,
|
||||
"z": 0
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.24011452496051788,
|
||||
"x": -0.12005726248025894,
|
||||
"y": -0.10536260157823563,
|
||||
"z": -0.12005726248025894
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.55410087108612061,
|
||||
"x": 0.36000609397888184,
|
||||
"y": -0.33641564846038818,
|
||||
"z": -0.67092394828796387
|
||||
},
|
||||
"shapeType": "simple-compound",
|
||||
"type": "Model",
|
||||
"userData": "{\n \"hifiHomeKey\": {\n \"reset\": true\n }\n}"
|
||||
};
|
||||
|
||||
|
||||
Step1BlockData = {
|
||||
"clientOnly": 0,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2016-08-22T22:54:07Z",
|
||||
"dimensions": {
|
||||
"x": 0.20000000298023224,
|
||||
"y": 0.20000000298023224,
|
||||
"z": 0.20000000298023224
|
||||
},
|
||||
name: "tutorial/block",
|
||||
"collisionsWillMove": 1,
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -0.2,
|
||||
z: 0
|
||||
},
|
||||
"dynamic": 1,
|
||||
"gravity": {
|
||||
"x": 0,
|
||||
"y": -10,
|
||||
"z": 0
|
||||
},
|
||||
"id": "{5c7223f8-3bc5-4cb4-913c-0e93f5994ca2}",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"queryAACube": {
|
||||
"scale": 0.34641015529632568,
|
||||
"x": -0.17320507764816284,
|
||||
"y": -0.17320507764816284,
|
||||
"z": -0.17320507764816284
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -0.0001373291015625,
|
||||
"y": -7.62939453125e-05,
|
||||
"z": -0.0003204345703125
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": JSON.stringify({ hifiHomeKey: { reset: true } }),
|
||||
};
|
|
@ -1,181 +0,0 @@
|
|||
// Originally written by James Pollack, modified by Ryan Huffman for the tutorial
|
||||
//
|
||||
// this script turns an entity into an exploder -- anything that collides with it will be vaporized!
|
||||
|
||||
(function() {
|
||||
|
||||
function debug() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
args.unshift("fire.js | ");
|
||||
print.apply(this, args);
|
||||
}
|
||||
|
||||
var _this = this;
|
||||
|
||||
function Fire() {
|
||||
_this = this;
|
||||
}
|
||||
|
||||
var RED = {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var ORANGE = {
|
||||
red: 255,
|
||||
green: 165,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var YELLOW = {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var GREEN = {
|
||||
red: 0,
|
||||
green: 255,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var BLUE = {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 255
|
||||
};
|
||||
|
||||
var INDIGO = {
|
||||
red: 128,
|
||||
green: 0,
|
||||
blue: 128
|
||||
};
|
||||
|
||||
var VIOLET = {
|
||||
red: 75,
|
||||
green: 0,
|
||||
blue: 130
|
||||
};
|
||||
|
||||
var colors = [RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET];
|
||||
|
||||
var firePitSoundURL = Script.resolvePath("fire_burst.wav");
|
||||
debug("Firepit burst sound url is: ", firePitSoundURL);
|
||||
|
||||
var explodeTextureURL = Script.resolvePath("explode.png");
|
||||
debug("Firepit explode texture url is: ", explodeTextureURL);
|
||||
|
||||
Fire.prototype = {
|
||||
preload: function(entityID) {
|
||||
debug("Preload");
|
||||
this.entityID = entityID;
|
||||
this.EXPLOSION_SOUND = SoundCache.getSound(firePitSoundURL);
|
||||
},
|
||||
collisionWithEntity: function(myID, otherID, collisionInfo) {
|
||||
debug("Collided with entity: ", myID, otherID);
|
||||
var otherProps = Entities.getEntityProperties(otherID);
|
||||
var data = null;
|
||||
try {
|
||||
data = JSON.parse(otherProps.userData);
|
||||
} catch (err) {
|
||||
debug('ERROR GETTING USERDATA!');
|
||||
}
|
||||
if (data === null || "") {
|
||||
debug("Data is null or empty", data);
|
||||
return;
|
||||
} else {
|
||||
debug("Got data", data);
|
||||
if (data.hasOwnProperty('hifiHomeKey')) {
|
||||
debug("Has hifiHomeKey");
|
||||
if (data.hifiHomeKey.reset === true) {
|
||||
debug("Reset is true");
|
||||
_this.playSoundAtCurrentPosition();
|
||||
_this.explodeWithColor();
|
||||
Entities.deleteEntity(otherID)
|
||||
debug("Sending local message");
|
||||
Messages.sendLocalMessage('Entity-Exploded', JSON.stringify({
|
||||
entityID: otherID,
|
||||
position: Entities.getEntityProperties(this.entityID).position
|
||||
}));
|
||||
debug("Done sending local message");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
explodeWithColor: function() {
|
||||
var myProps = Entities.getEntityProperties(this.entityID);
|
||||
var color = colors[Math.floor(Math.random() * colors.length)];
|
||||
var explosionParticleProperties = {
|
||||
"color": color,
|
||||
"isEmitting": 1,
|
||||
"maxParticles": 1000,
|
||||
"lifespan": 0.25,
|
||||
"emitRate": 1,
|
||||
"emitSpeed": 0.1,
|
||||
"speedSpread": 1,
|
||||
"emitOrientation": Quat.getUp(myProps.rotation),
|
||||
"emitDimensions": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"polarStart": 0,
|
||||
"polarFinish": 0,
|
||||
"azimuthStart": 0,
|
||||
"azimuthFinish": 0,
|
||||
"emitAcceleration": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"accelerationSpread": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"particleRadius": 0.829,
|
||||
"radiusSpread": 0,
|
||||
"radiusStart": 0.361,
|
||||
"radiusFinish": 0.294,
|
||||
"colorSpread": {
|
||||
"red": 0,
|
||||
"green": 0,
|
||||
"blue": 0
|
||||
},
|
||||
"colorStart": {
|
||||
"red": 255,
|
||||
"green": 255,
|
||||
"blue": 255
|
||||
},
|
||||
"colorFinish": {
|
||||
"red": 255,
|
||||
"green": 255,
|
||||
"blue": 255
|
||||
},
|
||||
"alpha": 1,
|
||||
"alphaSpread": 0,
|
||||
"alphaStart": -0.2,
|
||||
"alphaFinish": 0.5,
|
||||
"emitterShouldTrail": 0,
|
||||
"textures": explodeTextureURL,
|
||||
"type": "ParticleEffect",
|
||||
lifetime: 1,
|
||||
position: myProps.position
|
||||
};
|
||||
|
||||
var explosion = Entities.addEntity(explosionParticleProperties);
|
||||
},
|
||||
playSoundAtCurrentPosition: function() {
|
||||
|
||||
var audioProperties = {
|
||||
volume: 0.5,
|
||||
position: Entities.getEntityProperties(this.entityID).position
|
||||
};
|
||||
|
||||
Audio.playSound(this.EXPLOSION_SOUND, audioProperties);
|
||||
},
|
||||
}
|
||||
|
||||
return new Fire();
|
||||
});
|
|
@ -1,52 +0,0 @@
|
|||
// Originally written for the Home content set. Pulled into the tutorial by Ryan Huffman
|
||||
(function() {
|
||||
|
||||
var MINIMUM_LIGHT_INTENSITY = 50.0;
|
||||
var MAXIMUM_LIGHT_INTENSITY = 200.0;
|
||||
var LIGHT_FALLOFF_RADIUS = 0.1;
|
||||
var LIGHT_INTENSITY_RANDOMNESS = 0.1;
|
||||
|
||||
function randFloat(low, high) {
|
||||
return low + Math.random() * (high - low);
|
||||
}
|
||||
|
||||
var _this;
|
||||
|
||||
function FlickeringFlame() {
|
||||
_this = this;
|
||||
}
|
||||
|
||||
var totalTime = 0;
|
||||
var spacer = 2;
|
||||
FlickeringFlame.prototype = {
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
Script.update.connect(this.update);
|
||||
},
|
||||
update: function(deltaTime) {
|
||||
|
||||
totalTime += deltaTime;
|
||||
if (totalTime > spacer) {
|
||||
var howManyAvatars = AvatarList.getAvatarIdentifiers().length;
|
||||
var intensity = (MINIMUM_LIGHT_INTENSITY + (MAXIMUM_LIGHT_INTENSITY + (Math.sin(totalTime) * MAXIMUM_LIGHT_INTENSITY)));
|
||||
intensity += randFloat(-LIGHT_INTENSITY_RANDOMNESS, LIGHT_INTENSITY_RANDOMNESS);
|
||||
|
||||
Entities.editEntity(_this.entityID, {
|
||||
intensity: intensity
|
||||
});
|
||||
|
||||
spacer = Math.random(0, 100) * (2 / howManyAvatars);
|
||||
totalTime = 0;
|
||||
} else {
|
||||
//just keep counting
|
||||
}
|
||||
},
|
||||
unload: function() {
|
||||
Script.update.disconnect(this.update)
|
||||
}
|
||||
}
|
||||
|
||||
return new FlickeringFlame
|
||||
|
||||
|
||||
});
|
119
tutorial/fuse.js
119
tutorial/fuse.js
|
@ -1,119 +0,0 @@
|
|||
//
|
||||
// fuse.js
|
||||
//
|
||||
// Created by Ryan Huffman on 9/1/16.
|
||||
// Copyright 2016 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('utils.js');
|
||||
|
||||
var DEBUG = true;
|
||||
function debug() {
|
||||
if (DEBUG) {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
args.unshift("fuse.js | ");
|
||||
print.apply(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
var active = false;
|
||||
|
||||
var fuseSound = SoundCache.getSound("atp:/tutorial_sounds/fuse.wav");
|
||||
function getChildProperties(entityID, propertyNames) {
|
||||
var childEntityIDs = Entities.getChildrenIDs(entityID);
|
||||
var results = {}
|
||||
for (var i = 0; i < childEntityIDs.length; ++i) {
|
||||
var childEntityID = childEntityIDs[i];
|
||||
var properties = Entities.getEntityProperties(childEntityID, propertyNames);
|
||||
results[childEntityID] = properties;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
var Fuse = function() {
|
||||
};
|
||||
Fuse.prototype = {
|
||||
light: function() {
|
||||
debug("Received light()", this.entityID);
|
||||
|
||||
var visible = Entities.getEntityProperties(this.entityID, ['visible']).visible;
|
||||
if (!visible) {
|
||||
debug("Fuse is not visible, returning");
|
||||
return;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
debug("Fuse is active, returning");
|
||||
return;
|
||||
}
|
||||
active = true;
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
animation: {
|
||||
currentFrame: 1,
|
||||
lastFrame: 150,
|
||||
running: 1,
|
||||
url: "atp:/tutorial_models/fuse.fbx",
|
||||
loop: 0
|
||||
},
|
||||
});
|
||||
var injector = Audio.playSound(fuseSound, {
|
||||
position: Entities.getEntityProperties(this.entityID, 'position').position,
|
||||
volume: 0.7,
|
||||
loop: true
|
||||
});
|
||||
|
||||
var childrenProps = getChildProperties(this.entityID, ['type']);
|
||||
for (var childEntityID in childrenProps) {
|
||||
debug("Updating: ", childEntityID);
|
||||
var props = childrenProps[childEntityID];
|
||||
if (props.type == "ParticleEffect") {
|
||||
Entities.editEntity(childEntityID, {
|
||||
emitRate: 140,
|
||||
});
|
||||
} else if (props.type == "Light") {
|
||||
Entities.editEntity(childEntityID, {
|
||||
visible: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var self = this;
|
||||
Script.setTimeout(function() {
|
||||
debug("Setting off fireworks");
|
||||
var spinnerID = "{dd13fcd5-616f-4749-ab28-2e1e8bc512e9}";
|
||||
Entities.callEntityMethod(spinnerID, "onLit");
|
||||
injector.stop();
|
||||
|
||||
var childrenProps = getChildProperties(self.entityID, ['type']);
|
||||
for (var childEntityID in childrenProps) {
|
||||
debug("Updating: ", childEntityID);
|
||||
var props = childrenProps[childEntityID];
|
||||
if (props.type == "ParticleEffect") {
|
||||
Entities.editEntity(childEntityID, {
|
||||
emitRate: 0,
|
||||
});
|
||||
} else if (props.type == "Light") {
|
||||
Entities.editEntity(childEntityID, {
|
||||
visible: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}, 4900);
|
||||
|
||||
Script.setTimeout(function() {
|
||||
debug("Setting fuse to inactive");
|
||||
active = false;
|
||||
}, 14000);
|
||||
},
|
||||
preload: function(entityID) {
|
||||
debug("Preload");
|
||||
this.entityID = entityID;
|
||||
},
|
||||
};
|
||||
return new Fuse();
|
||||
});
|
|
@ -1,18 +0,0 @@
|
|||
(function() {
|
||||
Script.include('utils.js');
|
||||
|
||||
var Fuse = function() {
|
||||
};
|
||||
Fuse.prototype = {
|
||||
onLit: function() {
|
||||
print("fuseCollider.js | Lit", this.entityID);
|
||||
var fuseID = "{c8944a13-9acb-4d77-b1ee-851845e98357}"
|
||||
Entities.callEntityMethod(fuseID, "light");
|
||||
},
|
||||
preload: function(entityID) {
|
||||
print("fuseCollider.js | preload");
|
||||
this.entityID = entityID;
|
||||
},
|
||||
};
|
||||
return new Fuse();
|
||||
});
|
|
@ -1,192 +0,0 @@
|
|||
//
|
||||
// Created by Thijs Wenker on September 14, 2016.
|
||||
// Copyright 2016 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() {
|
||||
var _this;
|
||||
|
||||
function getResourceURL(file) {
|
||||
return 'atp:/' + file;
|
||||
};
|
||||
|
||||
const LIGHTER_ON_SOUND_URL = getResourceURL('tutorial_sounds/lighter_on.wav');
|
||||
const BUTANE_SOUND_URL = getResourceURL('tutorial_sounds/butane.wav');
|
||||
|
||||
// TODO: fix this in the client, changing the sound volume while a sound is playing doesn't seem to work right now
|
||||
const DYNAMIC_SOUND_VOLUME = false;
|
||||
const BUTANE_MIN_SOUND_VOLUME = 0.05;
|
||||
|
||||
const FLAME_LENGTH = 0.05;
|
||||
|
||||
const BUTANE_SOUND_SETTINGS = {
|
||||
volume: 0.4,
|
||||
loop: true,
|
||||
playbackGap: 1000,
|
||||
playbackGapRange: 1000
|
||||
};
|
||||
|
||||
const LIGHTER_ON_SOUND_SETTINGS = {
|
||||
volume: 0.5,
|
||||
loop: false
|
||||
};
|
||||
|
||||
function RemoteLogSender(channel, identifier) {
|
||||
this.channel = channel;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
RemoteLogSender.prototype = {
|
||||
channel: null,
|
||||
identifier: null,
|
||||
debug: function(message) {
|
||||
Messages.sendLocalMessage(this.channel, JSON.stringify({
|
||||
message: '[DEBUG ' + this.identifier + '] ' + message
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
var remoteLogSender = null;
|
||||
|
||||
function debugPrint(message) {
|
||||
if (remoteLogSender !== null) {
|
||||
remoteLogSender.debug(message);
|
||||
}
|
||||
}
|
||||
|
||||
ButaneLighter = function() {
|
||||
_this = this;
|
||||
_this.triggerValue = 0.0; // be sure to set this value in the constructor, otherwise it will be a shared value
|
||||
_this.isFiring = false;
|
||||
}
|
||||
|
||||
ButaneLighter.prototype = {
|
||||
entityID: null,
|
||||
lighterOnSound: null,
|
||||
butaneSound: null,
|
||||
lighterOnSoundInjector: null,
|
||||
butaneSoundInjector: null,
|
||||
butaneSoundInjectorOptions: null,
|
||||
lighterParticleEntity: null,
|
||||
buttonBeingPressed: null,
|
||||
triggerValue: null,
|
||||
isFiring: null,
|
||||
getLighterParticleEntity: function() {
|
||||
var result = null;
|
||||
Entities.getChildrenIDs(_this.entityID).forEach(function(entity) {
|
||||
var name = Entities.getEntityProperties(entity, ['name']).name;
|
||||
if (name === 'lighter_particle') {
|
||||
result = entity;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
},
|
||||
preload: function(entityID) {
|
||||
_this.entityID = entityID;
|
||||
_this.lighterOnSound = SoundCache.getSound(LIGHTER_ON_SOUND_URL);
|
||||
_this.butaneSound = SoundCache.getSound(BUTANE_SOUND_URL);
|
||||
var properties = Entities.getEntityProperties(_this.entityID, ['userData']);
|
||||
try {
|
||||
var userData = JSON.parse(properties.userData);
|
||||
if (userData['debug'] !== undefined && userData['debug']['sessionUUID'] === MyAvatar.sessionUUID &&
|
||||
userData['debug']['channel'] !== undefined)
|
||||
{
|
||||
remoteLogSender = new RemoteLogSender(userData['debug']['channel'], _this.entityID);
|
||||
remoteLogSender.debug('Debugger initialized');
|
||||
}
|
||||
} catch (e) {
|
||||
//failed to detect if we have a debugger
|
||||
}
|
||||
debugPrint(_this.getLighterParticleEntity());
|
||||
},
|
||||
startEquip: function(entityID, args) {
|
||||
_this.lighterParticleEntity = _this.getLighterParticleEntity();
|
||||
},
|
||||
continueEquip: function(entityID, args) {
|
||||
_this.triggerValue = Controller.getValue(args[0] === 'left' ? Controller.Standard.LT : Controller.Standard.RT);
|
||||
if (_this.triggerValue > 0.2) {
|
||||
if (!_this.isFiring) {
|
||||
_this.startFiring();
|
||||
}
|
||||
_this.tryToIgnite();
|
||||
_this.updateButaneSound()
|
||||
return;
|
||||
}
|
||||
_this.stopFiring();
|
||||
},
|
||||
startFiring: function() {
|
||||
if (_this.isFiring) {
|
||||
return;
|
||||
}
|
||||
_this.isFiring = true;
|
||||
if (_this.lighterOnSound.downloaded) {
|
||||
// We don't want to override the default volume setting, so lets clone the default SETTINGS object
|
||||
var lighterOnOptions = JSON.parse(JSON.stringify(LIGHTER_ON_SOUND_SETTINGS));
|
||||
lighterOnOptions['position'] = Entities.getEntityProperties(_this.entityID, ['position']).position;
|
||||
_this.lighterOnSoundInjector = Audio.playSound(_this.lighterOnSound, lighterOnOptions);
|
||||
}
|
||||
if (_this.butaneSound.downloaded) {
|
||||
_this.butaneSoundInjectorOptions = JSON.parse(JSON.stringify(BUTANE_SOUND_SETTINGS));
|
||||
_this.butaneSoundInjectorOptions['position'] = Entities.getEntityProperties(_this.lighterParticleEntity, ['position']).position;
|
||||
if (DYNAMIC_SOUND_VOLUME) {
|
||||
_this.butaneSoundInjectorOptions['volume'] = BUTANE_MIN_SOUND_VOLUME;
|
||||
}
|
||||
_this.butaneSoundInjector = Audio.playSound(_this.butaneSound, _this.butaneSoundInjectorOptions);
|
||||
}
|
||||
Entities.editEntity(_this.lighterParticleEntity, {isEmitting: _this.isFiring});
|
||||
|
||||
},
|
||||
stopFiring: function() {
|
||||
if (!_this.isFiring) {
|
||||
return;
|
||||
}
|
||||
_this.isFiring = false;
|
||||
Entities.editEntity(_this.lighterParticleEntity, {isEmitting: _this.isFiring});
|
||||
_this.stopButaneSound();
|
||||
},
|
||||
tryToIgnite: function() {
|
||||
var flameProperties = Entities.getEntityProperties(_this.lighterParticleEntity, ['position', 'rotation']);
|
||||
var pickRay = {
|
||||
origin: flameProperties.position,
|
||||
direction: Quat.inverse(Quat.getFront(flameProperties.rotation))
|
||||
}
|
||||
var intersection = Entities.findRayIntersection(pickRay, true, [], [_this.entityID, _this.lighterParticleEntity]);
|
||||
if (intersection.intersects && intersection.distance <= FLAME_LENGTH) {
|
||||
var properties = Entities.getEntityProperties(intersection.entityID, 'script');
|
||||
if (properties.script !== '') {
|
||||
Entities.callEntityMethod(intersection.entityID, 'onLit', [_this.triggerValue]);
|
||||
debugPrint('Light it up! found: ' + intersection.entityID);
|
||||
}
|
||||
}
|
||||
},
|
||||
releaseEquip: function(entityID, args) {
|
||||
_this.stopFiring();
|
||||
// reset trigger value;
|
||||
_this.triggerValue = 0.0;
|
||||
},
|
||||
updateButaneSound: function() {
|
||||
if (_this.butaneSoundInjector !== null && _this.butaneSoundInjector.isPlaying()) {
|
||||
_this.butaneSoundInjectorOptions = _this.butaneSoundInjector.options;
|
||||
_this.butaneSoundInjectorOptions['position'] = Entities.getEntityProperties(_this.entityID, ['position']).position;
|
||||
if (DYNAMIC_SOUND_VOLUME) {
|
||||
_this.butaneSoundInjectorOptions['volume'] = ((BUTANE_SOUND_SETTINGS.volume - BUTANE_MIN_SOUND_VOLUME) *
|
||||
_this.triggerValue) + BUTANE_MIN_SOUND_VOLUME;
|
||||
}
|
||||
_this.butaneSoundInjector.options = _this.butaneSoundInjectorOptions;
|
||||
}
|
||||
},
|
||||
stopButaneSound: function() {
|
||||
if (_this.butaneSoundInjector !== null && _this.butaneSoundInjector.isPlaying()) {
|
||||
_this.butaneSoundInjector.stop();
|
||||
}
|
||||
_this.butaneSoundInjector = null;
|
||||
},
|
||||
unload: function() {
|
||||
_this.stopButaneSound();
|
||||
},
|
||||
};
|
||||
return new ButaneLighter();
|
||||
})
|
|
@ -1,220 +0,0 @@
|
|||
//
|
||||
// Created by Thijs Wenker on September 14, 2016.
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
const TEST_MODE = false;
|
||||
const SCRIPT_URL = 'atp:/tutorial/lighter/butaneLighter.js';
|
||||
|
||||
//Creates an entity and returns a mixed object of the creation properties and the assigned entityID
|
||||
var createEntity = function(entityProperties, parent) {
|
||||
if (parent.rotation !== undefined) {
|
||||
if (entityProperties.rotation !== undefined) {
|
||||
entityProperties.rotation = Quat.multiply(parent.rotation, entityProperties.rotation);
|
||||
} else {
|
||||
entityProperties.rotation = parent.rotation;
|
||||
}
|
||||
}
|
||||
if (parent.position !== undefined) {
|
||||
var localPosition = (parent.rotation !== undefined) ? Vec3.multiplyQbyV(parent.rotation, entityProperties.position) : entityProperties.position;
|
||||
entityProperties.position = Vec3.sum(localPosition, parent.position)
|
||||
}
|
||||
if (parent.id !== undefined) {
|
||||
entityProperties.parentID = parent.id;
|
||||
}
|
||||
entityProperties.id = Entities.addEntity(entityProperties);
|
||||
return entityProperties;
|
||||
};
|
||||
|
||||
createButaneLighter = function(transform) {
|
||||
var entityProperties = {
|
||||
collisionsWillMove: true,
|
||||
dimensions: {
|
||||
x: 0.025599999353289604,
|
||||
y: 0.057399999350309372,
|
||||
z: 0.37419998645782471
|
||||
},
|
||||
dynamic: true,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
z: 0
|
||||
},
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -0.01,
|
||||
z: 0
|
||||
},
|
||||
modelURL: 'atp:/tutorial_models/lighterIceCreamSandwich.fbx',
|
||||
name: 'BrutaneLighter',
|
||||
shapeType: 'simple-compound',
|
||||
type: 'Model',
|
||||
userData: JSON.stringify({
|
||||
"tag": "equip-temporary",
|
||||
"grabbableKey": {
|
||||
"invertSolidWhileHeld": true
|
||||
},
|
||||
"wearable": {
|
||||
"joints": {
|
||||
"RightHand": [
|
||||
{
|
||||
"x": 0.049671292304992676,
|
||||
"y": 0.09825992584228516,
|
||||
"z": 0.03760027885437012
|
||||
},
|
||||
{
|
||||
"x": 0.6562752723693848,
|
||||
"y": 0.27598991990089417,
|
||||
"z": 0.6638742685317993,
|
||||
"w": -0.22890058159828186
|
||||
}
|
||||
],
|
||||
"LeftHand": [
|
||||
{
|
||||
"x": -0.028073370456695557,
|
||||
"y": 0.09609812498092651,
|
||||
"z": 0.039550721645355225
|
||||
},
|
||||
{
|
||||
"x": -0.6697965264320374,
|
||||
"y": 0.22050897777080536,
|
||||
"z": 0.6544681191444397,
|
||||
"w": 0.27283111214637756
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}),
|
||||
script: SCRIPT_URL
|
||||
};
|
||||
return createEntity(entityProperties, transform);
|
||||
}
|
||||
|
||||
function createFireParticle(butaneLighter) {
|
||||
var entityProperties = {
|
||||
userData: JSON.stringify({ tag: "equip-temporary" }),
|
||||
accelerationSpread: {
|
||||
x: 0.1,
|
||||
y: 0,
|
||||
z: 0.1
|
||||
},
|
||||
alpha: 0.039999999105930328,
|
||||
alphaFinish: 0.039999999105930328,
|
||||
alphaStart: 0.039999999105930328,
|
||||
azimuthFinish: 0.039999999105930328,
|
||||
azimuthStart: 0,
|
||||
dimensions: {
|
||||
x: 0.49194091558456421,
|
||||
y: 0.49194091558456421,
|
||||
z: 0.49194091558456421
|
||||
},
|
||||
emitAcceleration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
emitOrientation: {
|
||||
w: 1,
|
||||
x: -1.52587890625e-05,
|
||||
y: -1.52587890625e-05,
|
||||
z: -1.52587890625e-05
|
||||
},
|
||||
emitRate: 770,
|
||||
emitSpeed: 0.014000000432133675,
|
||||
isEmitting: false,
|
||||
lifespan: 0.37000000476837158,
|
||||
maxParticles: 820,
|
||||
name: 'lighter_particle',
|
||||
particleRadius: 0.0027000000700354576,
|
||||
position: {
|
||||
x: -0.00044769048690795898,
|
||||
y: 0.016354814171791077,
|
||||
z: 0.19217036664485931
|
||||
},
|
||||
radiusFinish: 0.0027000000700354576,
|
||||
radiusSpread: 3,
|
||||
radiusStart: 0.0027000000700354576,
|
||||
rotation: {
|
||||
w: 1,
|
||||
x: -0.0001678466796875,
|
||||
y: -1.52587890625e-05,
|
||||
z: -1.52587890625e-05
|
||||
},
|
||||
speedSpread: 0.56999999284744263,
|
||||
textures: 'atp:/textures/fire3.png',
|
||||
type: 'ParticleEffect',
|
||||
|
||||
|
||||
"color": {
|
||||
"red": 255,
|
||||
"green": 255,
|
||||
"blue": 255
|
||||
},
|
||||
"isEmitting": 0,
|
||||
"maxParticles": 820,
|
||||
"lifespan": 0.28,
|
||||
"emitRate": 1100,
|
||||
"emitSpeed": 0.007,
|
||||
"speedSpread": 0.5699999928474426,
|
||||
"emitOrientation": {
|
||||
"x": -0.0000152587890625,
|
||||
"y": -0.0000152587890625,
|
||||
"z": -0.0000152587890625,
|
||||
"w": 1
|
||||
},
|
||||
"emitDimensions": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"polarStart": 0,
|
||||
"polarFinish": 0,
|
||||
"azimuthStart": 0,
|
||||
"azimuthFinish": 0.03999999910593033,
|
||||
"emitAcceleration": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"accelerationSpread": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"particleRadius": 0.0037,
|
||||
"radiusSpread": 3,
|
||||
"radiusStart": 0.008,
|
||||
"radiusFinish": 0.0004,
|
||||
"colorSpread": {
|
||||
"red": 0,
|
||||
"green": 0,
|
||||
"blue": 0
|
||||
},
|
||||
"colorStart": {
|
||||
"red": 255,
|
||||
"green": 255,
|
||||
"blue": 255
|
||||
},
|
||||
"colorFinish": {
|
||||
"red": 255,
|
||||
"green": 255,
|
||||
"blue": 255
|
||||
},
|
||||
"alpha": 0.03999999910593033,
|
||||
"alphaSpread": 0,
|
||||
"alphaStart": 0.141,
|
||||
"alphaFinish": 0.02,
|
||||
"emitterShouldTrail": 0,
|
||||
"textures": "atp:/textures/fire3.png"
|
||||
};
|
||||
return createEntity(entityProperties, butaneLighter);
|
||||
}
|
||||
|
||||
doCreateButaneLighter = function(transform) {
|
||||
var butaneLighter = createButaneLighter(transform);
|
||||
createFireParticle(butaneLighter);
|
||||
return butaneLighter;
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
if (!Function.prototype.bind) {
|
||||
Function.prototype.bind = function(oThis) {
|
||||
if (typeof this !== 'function') {
|
||||
// closest thing possible to the ECMAScript 5
|
||||
// internal IsCallable function
|
||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
||||
}
|
||||
|
||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||||
fToBind = this,
|
||||
fNOP = function() {},
|
||||
fBound = function() {
|
||||
return fToBind.apply(this instanceof fNOP
|
||||
? this
|
||||
: oThis,
|
||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
|
||||
if (this.prototype) {
|
||||
// Function.prototype doesn't have a prototype property
|
||||
fNOP.prototype = this.prototype;
|
||||
}
|
||||
fBound.prototype = new fNOP();
|
||||
|
||||
return fBound;
|
||||
};
|
||||
}
|
||||
|
||||
function getOption(options, key, defaultValue) {
|
||||
if (options.hasOwnProperty(key)) {
|
||||
return options[key];
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
var TOKEN_NAME_PREFIX = "ownership_token-";
|
||||
|
||||
function getOwnershipTokenID(parentEntityID) {
|
||||
var childEntityIDs = Entities.getChildrenIDs(parentEntityID);
|
||||
var ownerID = null;
|
||||
var ownerName = '';
|
||||
for (var i = 0; i < childEntityIDs.length; ++i) {
|
||||
var childID = childEntityIDs[i];
|
||||
var properties = Entities.getEntityProperties(childID, ['name', 'userData', 'lifetime', 'age']);
|
||||
var childName = properties.name;
|
||||
if (childName.indexOf(TOKEN_NAME_PREFIX) == 0) {
|
||||
if (ownerID === null || childName < ownerName) {
|
||||
ownerID = childID;
|
||||
ownerName = childName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ownerID;
|
||||
}
|
||||
|
||||
function createOwnershipToken(name, parentEntityID) {
|
||||
return Entities.addEntity({
|
||||
type: "Box",
|
||||
name: TOKEN_NAME_PREFIX + name,
|
||||
visible: false,
|
||||
parentID: parentEntityID,
|
||||
locationPosition: { x: 0, y: 0, z: 0 },
|
||||
dimensions: { x: 100, y: 100, z: 100 },
|
||||
collisionless: true,
|
||||
lifetime: 5
|
||||
});
|
||||
}
|
||||
|
||||
var DEBUG = true;
|
||||
function debug() {
|
||||
if (DEBUG) {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
print.apply(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
var TOKEN_STATE_DESTROYED = -1;
|
||||
var TOKEN_STATE_UNOWNED = 0;
|
||||
var TOKEN_STATE_REQUESTING_OWNERSHIP = 1;
|
||||
var TOKEN_STATE_OWNED = 2;
|
||||
|
||||
OwnershipToken = function(name, parentEntityID, options) {
|
||||
this.name = MyAvatar.sessionUUID + "-" + Math.floor(Math.random() * 10000000);
|
||||
this.parentEntityID = parentEntityID;
|
||||
|
||||
// How often to check whether the token is available if we don't currently own it
|
||||
this.checkEverySeconds = getOption(options, 'checkEverySeconds', 1000);
|
||||
this.updateTokenLifetimeEvery = getOption(options, 'updateTokenLifetimeEvery', 2000);
|
||||
|
||||
this.onGainedOwnership = getOption(options, 'onGainedOwnership', function() { });
|
||||
this.onLostOwnership = getOption(options, 'onLostOwnership', function() { });
|
||||
|
||||
this.ownershipTokenID = null;
|
||||
this.setState(TOKEN_STATE_UNOWNED);
|
||||
};
|
||||
|
||||
OwnershipToken.prototype = {
|
||||
destroy: function() {
|
||||
debug(this.name, "Destroying token");
|
||||
this.setState(TOKEN_STATE_DESTROYED);
|
||||
},
|
||||
|
||||
setState: function(newState) {
|
||||
if (this.state == newState) {
|
||||
debug(this.name, "Warning: Trying to set state to the current state");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.updateLifetimeID) {
|
||||
debug(this.name, "Clearing update lifetime interval");
|
||||
Script.clearInterval(this.updateLifetimeID);
|
||||
this.updateLifetimeID = null;
|
||||
}
|
||||
|
||||
if (this.checkOwnershipAvailableID) {
|
||||
Script.clearInterval(this.checkOwnershipAvailableID);
|
||||
this.checkOwnershipAvailableID = null;
|
||||
}
|
||||
|
||||
if (this.state == TOKEN_STATE_OWNED) {
|
||||
this.onLostOwnership(this);
|
||||
}
|
||||
|
||||
if (newState == TOKEN_STATE_UNOWNED) {
|
||||
this.checkOwnershipAvailableID = Script.setInterval(
|
||||
this.tryRequestingOwnership.bind(this), this.checkEverySeconds);
|
||||
|
||||
} else if (newState == TOKEN_STATE_REQUESTING_OWNERSHIP) {
|
||||
|
||||
} else if (newState == TOKEN_STATE_OWNED) {
|
||||
this.onGainedOwnership(this);
|
||||
this.updateLifetimeID = Script.setInterval(
|
||||
this.updateTokenLifetime.bind(this), this.updateTokenLifetimeEvery);
|
||||
} else if (newState == TOKEN_STATE_DESTROYED) {
|
||||
Entities.deleteEntity(this.ownershipTokenID);
|
||||
}
|
||||
|
||||
debug(this.name, "Info: Switching to state:", newState);
|
||||
this.state = newState;
|
||||
},
|
||||
updateTokenLifetime: function() {
|
||||
if (this.state != TOKEN_STATE_OWNED) {
|
||||
debug(this.name, "Error: Trying to update token while it is unowned");
|
||||
return;
|
||||
}
|
||||
|
||||
debug(this.name, "Updating entity lifetime");
|
||||
var age = Entities.getEntityProperties(this.ownershipTokenID, 'age').age;
|
||||
Entities.editEntity(this.ownershipTokenID, {
|
||||
lifetime: age + 5
|
||||
});
|
||||
},
|
||||
tryRequestingOwnership: function() {
|
||||
if (this.state == TOKEN_STATE_REQUESTING_OWNERSHIP || this.state == TOKEN_STATE_OWNED) {
|
||||
debug(this.name, "We already have or are requesting ownership");
|
||||
return;
|
||||
}
|
||||
|
||||
var ownerID = getOwnershipTokenID(this.parentEntityID);
|
||||
if (ownerID !== null) {
|
||||
// Already owned, return
|
||||
debug(this.name, "Token already owned by another client, returning. Owner: " + owenerID + ", Us: " + this.name);
|
||||
return;
|
||||
}
|
||||
|
||||
this.ownershipTokenID = createOwnershipToken(this.name, this.parentEntityID);
|
||||
this.setState(TOKEN_STATE_REQUESTING_OWNERSHIP);
|
||||
|
||||
function checkOwnershipRequest() {
|
||||
var ownerID = getOwnershipTokenID(this.parentEntityID);
|
||||
if (ownerID == this.ownershipTokenID) {
|
||||
debug(this.name, "Info: Obtained ownership");
|
||||
this.setState(TOKEN_STATE_OWNED);
|
||||
} else {
|
||||
if (ownerID === null) {
|
||||
debug(this.name, "Warning: Checked ownership request and no tokens existed");
|
||||
}
|
||||
debug(this.name, "Info: Lost ownership request")
|
||||
this.ownershipTokenID = null;
|
||||
this.setState(TOKEN_STATE_UNOWNED);
|
||||
}
|
||||
}
|
||||
|
||||
Script.setTimeout(checkOwnershipRequest.bind(this), 2000);
|
||||
},
|
||||
};
|
||||
|
||||
debug("Returning from ownershipToken");
|
|
@ -1,84 +0,0 @@
|
|||
//
|
||||
// spinner.js
|
||||
//
|
||||
// Created by Ryan Huffman on 9/1/16.
|
||||
// Copyright 2016 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() {
|
||||
var DEBUG = true;
|
||||
function debug() {
|
||||
if (DEBUG) {
|
||||
print.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
var spinnerSound = SoundCache.getSound("atp:/tutorial_sounds/Pinwheel.L.wav");
|
||||
var Spinner = function() {
|
||||
};
|
||||
function getChildProperties(entityID, propertyNames) {
|
||||
var childEntityIDs = Entities.getChildrenIDs(entityID);
|
||||
var results = {}
|
||||
for (var i = 0; i < childEntityIDs.length; ++i) {
|
||||
var childEntityID = childEntityIDs[i];
|
||||
var properties = Entities.getEntityProperties(childEntityID, propertyNames);
|
||||
results[childEntityID] = properties;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
Spinner.prototype = {
|
||||
onLit: function() {
|
||||
debug("spinner.js | Spinner lit");
|
||||
Entities.editEntity(this.entityID, {
|
||||
"angularDamping": 0.1,
|
||||
"angularVelocity": {
|
||||
"x": 20.471975326538086,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
});
|
||||
var injector = Audio.playSound(spinnerSound, {
|
||||
position: Entities.getEntityProperties(this.entityID, 'position').position,
|
||||
volume: 1.0,
|
||||
loop: false
|
||||
});
|
||||
|
||||
var childrenProps = getChildProperties(this.entityID, ['type']);
|
||||
for (var childEntityID in childrenProps) {
|
||||
var props = childrenProps[childEntityID];
|
||||
if (props.type == "ParticleEffect") {
|
||||
debug("spinner.js | Modifying: ", childEntityID);
|
||||
Entities.editEntity(childEntityID, {
|
||||
emitRate: 35,
|
||||
});
|
||||
}
|
||||
}
|
||||
Messages.sendLocalMessage("Tutorial-Spinner", "wasLit");
|
||||
|
||||
var self = this;
|
||||
Script.setTimeout(function() {
|
||||
debug("spinner.js | Finishing spinner");
|
||||
injector.stop();
|
||||
|
||||
var childrenProps = getChildProperties(self.entityID, ['type']);
|
||||
for (var childEntityID in childrenProps) {
|
||||
var props = childrenProps[childEntityID];
|
||||
if (props.type == "ParticleEffect") {
|
||||
debug("spinner.js | Modifying: ", childEntityID);
|
||||
Entities.editEntity(childEntityID, {
|
||||
emitRate: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 4900);
|
||||
},
|
||||
preload: function(entityID) {
|
||||
debug("spinner.js | Preload");
|
||||
this.entityID = entityID;
|
||||
},
|
||||
};
|
||||
return new Spinner();
|
||||
});
|
Binary file not shown.
Binary file not shown.
1202
tutorial/tutorial.js
1202
tutorial/tutorial.js
File diff suppressed because it is too large
Load diff
|
@ -1,360 +0,0 @@
|
|||
TUTORIAL_TAG_TO_ENTITY_IDS_MAP = {
|
||||
"teleport-vive": {
|
||||
"{7df1abc4-1b7c-4352-985c-f3f6ad8d65b7}": {
|
||||
"tag": "teleport-vive"
|
||||
}
|
||||
},
|
||||
"teleport-touch": {
|
||||
"{ff064b9e-7fa4-4693-a386-a67b9f92a948}": {
|
||||
"tag": "teleport-touch"
|
||||
}
|
||||
},
|
||||
"turnAround-vive": {
|
||||
"{9b14f224-b2f6-447f-bb86-f5d875cf4c33}": {
|
||||
"tag": "turnAround-vive"
|
||||
}
|
||||
},
|
||||
"turnAround-touch": {
|
||||
"{ce74b3ca-d1c7-4980-bd98-2d488095a39e}": {
|
||||
"tag": "turnAround-touch"
|
||||
}
|
||||
},
|
||||
"teleport": {
|
||||
"{4478f7b5-d3ac-4213-9a7b-ad8cd69575b8}": {
|
||||
"tag": "teleport"
|
||||
}
|
||||
},
|
||||
"finish": {
|
||||
"{340e05b5-88df-4b2b-b43c-756dd714d6d8}": {
|
||||
"tag": "finish"
|
||||
}
|
||||
},
|
||||
"door": {
|
||||
"{9c5b0fee-e695-4516-94cd-153371e3857b}": {
|
||||
"tag": "door"
|
||||
}
|
||||
},
|
||||
"farGrab": {
|
||||
"{70fcd96c-cd59-4f23-9ca5-a167f2f85680}": {
|
||||
"visible": false,
|
||||
"tag": "farGrab"
|
||||
},
|
||||
"{ff7b9793-0d94-4f18-bc09-4ab589126e60}": {
|
||||
"tag": "farGrab"
|
||||
},
|
||||
"{fdd77d2c-af36-41c1-ba57-74b7ae79d996}": {
|
||||
"tag": "farGrab"
|
||||
},
|
||||
"{e11700f6-bc9a-411f-9ddc-bf265d4e3ccf}": {
|
||||
"tag": "farGrab"
|
||||
},
|
||||
"{95850c56-cd1c-42b9-ab6b-a163a6f2878f}": {
|
||||
"tag": "farGrab"
|
||||
}
|
||||
},
|
||||
"nearGrab-vive": {
|
||||
"{88221a22-b710-4d35-852b-5257b0aa77dc}": {
|
||||
"tag": "nearGrab-vive"
|
||||
}
|
||||
},
|
||||
"nearGrab-touch": {
|
||||
"{7c0f2fde-6c5c-459b-bf82-421979cebf2e}": {
|
||||
"tag": "nearGrab-touch"
|
||||
}
|
||||
},
|
||||
"nearGrab": {
|
||||
"{55c861ef-60ca-4722-a6c5-9c6967966ec5}": {
|
||||
"tag": "nearGrab"
|
||||
},
|
||||
"{644d655b-ae66-43b1-9bab-a44b9a8ad632}": {
|
||||
"tag": "nearGrab"
|
||||
},
|
||||
"{8bf0baa1-88d0-448a-a782-100d4413bd82}": {
|
||||
"tag": "nearGrab"
|
||||
},
|
||||
"{5cf22b9c-fb22-4854-8821-554422980b24}": {
|
||||
"visible": false,
|
||||
"tag": "nearGrab"
|
||||
}
|
||||
},
|
||||
"equip-part1-touch": {
|
||||
"{470f0634-8be7-4b52-a8bd-5183d489fcb6}": {
|
||||
"tag": "equip-part1-touch"
|
||||
}
|
||||
},
|
||||
"equip-part1-vive": {
|
||||
"{97ced5e7-fc81-40f9-a9e8-f85b4b30f24c}": {
|
||||
"tag": "equip-part1-vive"
|
||||
}
|
||||
},
|
||||
"equip-part1": {
|
||||
"{d73822ca-0a34-4cf4-a530-3258ac459a14}": {
|
||||
"tag": "equip-part1"
|
||||
},
|
||||
"{8572d991-5777-45df-97bf-7243d7b12f81}": {
|
||||
"tag": "equip-part1"
|
||||
},
|
||||
"{da5ea72e-54b6-41ac-b711-742b062b6968}": {
|
||||
"tag": "equip-part1"
|
||||
},
|
||||
"{c8944a13-9acb-4d77-b1ee-851845e98357}": {
|
||||
"tag": "equip-part1"
|
||||
},
|
||||
"{e9481c78-1a21-43f7-b54c-58f2efdf3c8f}": {
|
||||
"tag": "equip-part1"
|
||||
},
|
||||
"{ca3c28f3-15fc-4349-a85e-eaca0fad6434}": {
|
||||
"tag": "equip-part1"
|
||||
},
|
||||
"{09ddcb94-52a7-4f50-a5a2-db9db28fc519}": {
|
||||
"tag": "equip-part1"
|
||||
},
|
||||
"{dd13fcd5-616f-4749-ab28-2e1e8bc512e9}": {
|
||||
"tag": "equip-part1"
|
||||
}
|
||||
},
|
||||
"equip-part2-vive": {
|
||||
"{b5d17eda-90ab-40cf-b973-efcecb2e992e}": {
|
||||
"tag": "equip-part2-vive"
|
||||
},
|
||||
"{6307cd16-dd1d-4988-a339-578178436b45}": {
|
||||
"tag": "equip-part2-vive"
|
||||
}
|
||||
},
|
||||
"equip-part2-touch": {
|
||||
"{69195139-e020-4739-bb2c-50faebc6860a}": {
|
||||
"tag": "equip-part2-touch"
|
||||
},
|
||||
"{9b0a99ae-221b-4e59-ba3c-d8e64a083774}": {
|
||||
"tag": "equip-part2-touch"
|
||||
}
|
||||
},
|
||||
"bothGrab": {
|
||||
"{14792a6e-dc6f-4e7a-843f-4b109b06b5a4}": {
|
||||
"visible": false,
|
||||
"tag": "bothGrab",
|
||||
"collidable": true
|
||||
},
|
||||
"{215dcd14-88fc-4604-9033-cbd2a660178a}": {
|
||||
"tag": "bothGrab"
|
||||
},
|
||||
"{fbc2e40d-0633-45ac-b1c9-97fc8465f93b}": {
|
||||
"tag": "bothGrab"
|
||||
},
|
||||
"{6752dad6-109d-4dc5-aef7-dc8509468cf4}": {
|
||||
"tag": "bothGrab"
|
||||
},
|
||||
"{178e2c71-dff5-4231-8d28-df47fddf4709}": {
|
||||
"soundKey": {
|
||||
"playbackGapRange": 0,
|
||||
"url": "atp:/sounds/crackling_fire.L.wav",
|
||||
"volume": 0.5,
|
||||
"playbackGap": 5,
|
||||
"playing": false,
|
||||
"loop": true
|
||||
},
|
||||
"tag": "bothGrab"
|
||||
},
|
||||
"{52445ac5-8730-4457-827e-6c076d2c609c}": {
|
||||
"tag": "bothGrab"
|
||||
}
|
||||
},
|
||||
"raiseHands": {
|
||||
"{7139e45d-25cf-470b-b133-c0fda0099d2b}": {
|
||||
"tag": "raiseHands"
|
||||
}
|
||||
},
|
||||
"equip": {
|
||||
"{e7897c9c-f4fa-4989-a383-28af56c2e544}": {
|
||||
"visible": false,
|
||||
"tag": "equip"
|
||||
},
|
||||
"{9df518da-9e65-4b76-8a79-eeefdb0b7310}": {
|
||||
"visible": false,
|
||||
"tag": "equip"
|
||||
},
|
||||
"{1a77c20e-5d9b-4b54-bf20-1416141a7ca8}": {
|
||||
"tag": "equip"
|
||||
}
|
||||
},
|
||||
"orient-vive": {
|
||||
"{95d233ab-ed0a-46e1-b047-1c542688ef3f}": {
|
||||
"tag": "orient-vive"
|
||||
}
|
||||
},
|
||||
"orient-touch": {
|
||||
"{1c95f945-ec46-4aac-b0f1-e64e073dbfaa}": {
|
||||
"tag": "orient-touch"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TUTORIAL_NAME_TO_ENTITY_PROPERTIES_MAP = {
|
||||
"tutorial/gun_spawn": {
|
||||
"clientOnly": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2016-09-08T18:38:24Z",
|
||||
"dimensions": {
|
||||
"x": 0.0649842768907547,
|
||||
"y": 0.0649842768907547,
|
||||
"z": 0.0649842768907547
|
||||
},
|
||||
"id": "{9df518da-9e65-4b76-8a79-eeefdb0b7310}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1481926907366120,
|
||||
"lastEditedBy": "{b80185ea-0936-4397-a5a4-3a64004f545f}",
|
||||
"name": "tutorial/gun_spawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"x": 0.60231781005859375,
|
||||
"y": 0.68465065956115723,
|
||||
"z": 0.39223569631576538
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.11255607008934021,
|
||||
"x": 0.54603976011276245,
|
||||
"y": 0.62837260961532593,
|
||||
"z": 0.33595764636993408
|
||||
},
|
||||
"rotation": {
|
||||
"w": -0.025101065635681152,
|
||||
"x": 0.70666050910949707,
|
||||
"y": 0.70666050910949707,
|
||||
"z": -0.025131583213806152
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"visible\":false,\"tag\":\"equip\"}",
|
||||
"visible": 0
|
||||
},
|
||||
"tutorial/nearGrab/box_spawn": {
|
||||
"clientOnly": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 255,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2016-09-08T18:38:24Z",
|
||||
"dimensions": {
|
||||
"x": 0.082253716886043549,
|
||||
"y": 0.082253716886043549,
|
||||
"z": 0.082253716886043549
|
||||
},
|
||||
"id": "{5cf22b9c-fb22-4854-8821-554422980b24}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1481926907334206,
|
||||
"lastEditedBy": "{b80185ea-0936-4397-a5a4-3a64004f545f}",
|
||||
"name": "tutorial/nearGrab/box_spawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"x": 0.61857688426971436,
|
||||
"y": 0.80955326557159424,
|
||||
"z": 0.36191046237945557
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.14246761798858643,
|
||||
"x": 0.54734307527542114,
|
||||
"y": 0.73831945657730103,
|
||||
"z": 0.29067665338516235
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"visible\":false,\"tag\":\"nearGrab\"}",
|
||||
"visible": 0
|
||||
},
|
||||
"tutorial/farGrab/box_spawn": {
|
||||
"clientOnly": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 255,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2016-09-08T18:38:24Z",
|
||||
"dimensions": {
|
||||
"x": 0.16850528120994568,
|
||||
"y": 0.16850528120994568,
|
||||
"z": 0.16850528120994568
|
||||
},
|
||||
"id": "{70fcd96c-cd59-4f23-9ca5-a167f2f85680}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1481926908795578,
|
||||
"lastEditedBy": "{b80185ea-0936-4397-a5a4-3a64004f545f}",
|
||||
"name": "tutorial/farGrab/box_spawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"x": 3.4866282939910889,
|
||||
"y": 0.67159509658813477,
|
||||
"z": 0.47892442345619202
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.64707136154174805,
|
||||
"x": 3.2037394046783447,
|
||||
"y": 0.33042514324188232,
|
||||
"z": 0.14542555809020996
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"visible\":false,\"tag\":\"farGrab\"}",
|
||||
"visible": 0
|
||||
},
|
||||
"tutorial/teleport/pad": {
|
||||
"userData": "{\"tag\":\"teleport\"}",
|
||||
"rotation": {
|
||||
"y": -0.9702650308609009,
|
||||
"x": -2.1246911273919977e-05,
|
||||
"z": -4.222852112434339e-06,
|
||||
"w": 0.2420452982187271
|
||||
},
|
||||
"dimensions": {
|
||||
"y": 0.4365682601928711,
|
||||
"x": 2.1751723289489746,
|
||||
"z": 2.175173044204712
|
||||
},
|
||||
"collisionless": 1,
|
||||
"created": "2016-09-08T18:38:24Z",
|
||||
"queryAACube": {
|
||||
"y": -1.7979401350021362,
|
||||
"x": 7.5136213302612305,
|
||||
"scale": 3.106983184814453,
|
||||
"z": -1.4602710008621216
|
||||
},
|
||||
"visible": 0,
|
||||
"angularVelocity": {
|
||||
"y": -0.5235987901687622,
|
||||
"x": 0,
|
||||
"z": 0
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"angularDamping": 0,
|
||||
"position": {
|
||||
"y": -0.2444484978914261,
|
||||
"x": 9.067112922668457,
|
||||
"z": 0.09322060644626617
|
||||
},
|
||||
"modelURL": "atp:/alan/dev/Teleport-Pad.fbx",
|
||||
"ignoreForCollisions": 1,
|
||||
"type": "Model",
|
||||
"id": "{4478f7b5-d3ac-4213-9a7b-ad8cd69575b8}",
|
||||
"name": "tutorial/teleport/pad"
|
||||
}
|
||||
};
|
|
@ -1,51 +0,0 @@
|
|||
(function() {
|
||||
var TutorialStartZone = function() {
|
||||
print("TutorialStartZone | Creating");
|
||||
};
|
||||
|
||||
TutorialStartZone.prototype = {
|
||||
preload: function(entityID) {
|
||||
print("TutorialStartZone | Preload");
|
||||
this.entityID = entityID;
|
||||
this.sendStartIntervalID = null;
|
||||
},
|
||||
enterEntity: function() {
|
||||
var self = this;
|
||||
// send message to outer zone
|
||||
print("TutorialStartZone | Entered the tutorial start area");
|
||||
if (HMD.isHMDAvailable() && HMD.isHandControllerAvailable() && HMD.active) {
|
||||
function sendStart() {
|
||||
print("TutorialStartZone | Checking parent ID");
|
||||
var parentID = Entities.getEntityProperties(self.entityID, 'parentID').parentID;
|
||||
print("TutorialStartZone | Parent ID is: ", parentID);
|
||||
if (parentID) {
|
||||
print("TutorialStartZone | Sending start");
|
||||
Entities.callEntityMethod(parentID, 'onEnteredStartZone');
|
||||
} else {
|
||||
print("TutorialStartZone | ERROR: No parent id found on tutorial start zone");
|
||||
}
|
||||
}
|
||||
this.sendStartIntervalID = Script.setInterval(sendStart, 1500);
|
||||
sendStart();
|
||||
} else {
|
||||
print("TutorialStartZone | User tried to go to tutorial without active HMD and hand controllers, sending back to /");
|
||||
Window.alert("To proceed with this tutorial, please connect your Vive or Oculus headset and hand controllers.");
|
||||
location = "/";
|
||||
}
|
||||
},
|
||||
leaveEntity: function() {
|
||||
print("TutorialStartZone | Exited the tutorial start area");
|
||||
if (this.sendStartIntervalID) {
|
||||
Script.clearInterval(this.sendStartIntervalID);
|
||||
}
|
||||
var parentID = Entities.getEntityProperties(this.entityID, 'parentID').parentID;
|
||||
print("TutorialStartZone | Parent ID is: ", parentID);
|
||||
if (parentID) {
|
||||
print("TutorialStartZone | Sending onLeftStartZone");
|
||||
Entities.callEntityMethod(parentID, 'on');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return new TutorialStartZone();
|
||||
});
|
|
@ -1,142 +0,0 @@
|
|||
if (!Function.prototype.bind) {
|
||||
Function.prototype.bind = function(oThis) {
|
||||
if (typeof this !== 'function') {
|
||||
// closest thing possible to the ECMAScript 5
|
||||
// internal IsCallable function
|
||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
||||
}
|
||||
|
||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||||
fToBind = this,
|
||||
fNOP = function() {},
|
||||
fBound = function() {
|
||||
return fToBind.apply(this instanceof fNOP
|
||||
? this
|
||||
: oThis,
|
||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
|
||||
if (this.prototype) {
|
||||
// Function.prototype doesn't have a prototype property
|
||||
fNOP.prototype = this.prototype;
|
||||
}
|
||||
fBound.prototype = new fNOP();
|
||||
|
||||
return fBound;
|
||||
};
|
||||
}
|
||||
|
||||
(function() {
|
||||
Script.include("ownershipToken.js");
|
||||
Script.include("tutorial.js");
|
||||
|
||||
var CHANNEL_AWAY_ENABLE = "Hifi-Away-Enable";
|
||||
function setAwayEnabled(value) {
|
||||
var message = value ? 'enable' : 'disable';
|
||||
Messages.sendLocalMessage(CHANNEL_AWAY_ENABLE, message);
|
||||
}
|
||||
|
||||
var TutorialZone = function() {
|
||||
print("TutorialZone | Creating");
|
||||
this.token = null;
|
||||
};
|
||||
|
||||
TutorialZone.prototype = {
|
||||
keyReleaseHandler: function(event) {
|
||||
print(event.text);
|
||||
if (event.isShifted && event.isAlt) {
|
||||
if (event.text == "F12") {
|
||||
if (!this.tutorialManager.startNextStep()) {
|
||||
this.tutorialManager.startTutorial();
|
||||
}
|
||||
} else if (event.text == "F11") {
|
||||
this.tutorialManager.restartStep();
|
||||
} else if (event.text == "F10") {
|
||||
MyAvatar.shouldRenderLocally = !MyAvatar.shouldRenderLocally;
|
||||
} else if (event.text == "r") {
|
||||
this.tutorialManager.stopTutorial();
|
||||
this.tutorialManager.startTutorial();
|
||||
}
|
||||
}
|
||||
},
|
||||
preload: function(entityID) {
|
||||
print("TutorialZone | Preload");
|
||||
this.entityID = entityID;
|
||||
},
|
||||
onEnteredStartZone: function() {
|
||||
print("TutorialZone | Got onEnteredStartZone");
|
||||
var self = this;
|
||||
if (!this.token) {
|
||||
print("TutorialZone | Creating token");
|
||||
// The start zone has been entered, hide the overlays immediately
|
||||
setAwayEnabled(false);
|
||||
Menu.setIsOptionChecked("Overlays", false);
|
||||
MyAvatar.shouldRenderLocally = false;
|
||||
Toolbars.getToolbar("com.highfidelity.interface.toolbar.system").writeProperty("visible", false);
|
||||
this.token = new OwnershipToken(Math.random() * 100000, this.entityID, {
|
||||
onGainedOwnership: function(token) {
|
||||
print("TutorialZone | GOT OWNERSHIP");
|
||||
if (!self.tutorialManager) {
|
||||
self.tutorialManager = new TutorialManager();
|
||||
}
|
||||
self.tutorialManager.startTutorial();
|
||||
print("TutorialZone | making bound release handler");
|
||||
self.keyReleaseHandlerBound = self.keyReleaseHandler.bind(self);
|
||||
print("TutorialZone | binding");
|
||||
Controller.keyReleaseEvent.connect(self.keyReleaseHandlerBound);
|
||||
print("TutorialZone | done");
|
||||
},
|
||||
onLostOwnership: function(token) {
|
||||
print("TutorialZone | LOST OWNERSHIP");
|
||||
if (self.tutorialManager) {
|
||||
print("TutorialZone | stopping tutorial..");
|
||||
self.tutorialManager.stopTutorial();
|
||||
print("TutorialZone | done");
|
||||
Controller.keyReleaseEvent.disconnect(self.keyReleaseHandlerBound);
|
||||
} else {
|
||||
print("TutorialZone | no tutorial manager...");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
onLeftStartZone: function() {
|
||||
print("TutorialZone | Got onLeftStartZone");
|
||||
|
||||
// If the start zone was exited, and the tutorial hasn't started, go ahead and
|
||||
// re-enable the HUD/Overlays
|
||||
if (!this.tutorialManager) {
|
||||
Menu.setIsOptionChecked("Overlays", true);
|
||||
MyAvatar.shouldRenderLocally = true;
|
||||
setAwayEnabled(true);
|
||||
Toolbars.getToolbar("com.highfidelity.interface.toolbar.system").writeProperty("visible", true);
|
||||
}
|
||||
},
|
||||
|
||||
onEnteredEntryPortal: function() {
|
||||
print("TutorialZone | Got onEnteredEntryPortal");
|
||||
if (this.tutorialManager) {
|
||||
print("TutorialZone | Calling enteredEntryPortal");
|
||||
this.tutorialManager.enteredEntryPortal();
|
||||
}
|
||||
},
|
||||
|
||||
enterEntity: function() {
|
||||
print("TutorialZone | ENTERED THE TUTORIAL AREA");
|
||||
},
|
||||
leaveEntity: function() {
|
||||
print("TutorialZone | EXITED THE TUTORIAL AREA");
|
||||
if (this.token) {
|
||||
print("TutorialZone | Destroying token");
|
||||
this.token.destroy();
|
||||
this.token = null;
|
||||
}
|
||||
if (this.tutorialManager) {
|
||||
this.tutorialManager.stopTutorial();
|
||||
//this.tutorialManager = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return new TutorialZone();
|
||||
});
|
Loading…
Reference in a new issue