374 lines
No EOL
14 KiB
JavaScript
374 lines
No EOL
14 KiB
JavaScript
/* eslint-disable indent */
|
|
|
|
|
|
// PARTICLE SEQUENCER CONSTS
|
|
// ////////////////////////////////////////////////////////////////////////
|
|
|
|
var
|
|
LOOP = "loop",
|
|
POSITION = "position",
|
|
ROTATION = "rotation"
|
|
;
|
|
|
|
// Init
|
|
// ////////////////////////////////////////////////////////////////////////
|
|
|
|
var
|
|
_this
|
|
;
|
|
|
|
// HELPER FUNCTIONS
|
|
// ////////////////////////////////////////////////////////////////////////
|
|
|
|
function log(label, value, isActive){
|
|
if (!isActive) {
|
|
return;
|
|
}
|
|
print("\n" + label + "\n" + "***************************************\n", JSON.stringify(value));
|
|
}
|
|
|
|
// Get Particle in front of you
|
|
function getPosition(x, y, z) {
|
|
var localOffset = { x: x, y: y, z: z };
|
|
var worldOffset = Vec3.multiplyQbyV(MyAvatar.orientation, localOffset);
|
|
return Vec3.sum(MyAvatar.position, worldOffset);
|
|
}
|
|
|
|
// GROUP DEFINITIONS
|
|
// ////////////////////////////////////////////////////////////////////////
|
|
|
|
var _Sequence = function () {
|
|
this._entities = {};
|
|
this._nameMap = {};
|
|
this._sequences = {};
|
|
this._anchorPosition = {};
|
|
this._totalDelta = 0;
|
|
this._currentSequence;
|
|
this._isRunning = false;
|
|
this._textures = null;
|
|
_this = this;
|
|
};
|
|
|
|
_Sequence.prototype = {
|
|
add: function(entity){
|
|
this._entities[entity.getID()] = entity;
|
|
},
|
|
addSequence: function(name) {
|
|
this._sequences[name] = {
|
|
start: [],
|
|
stop: []
|
|
};
|
|
},
|
|
addTextures: function(textures) {
|
|
this._textures = textures;
|
|
},
|
|
remove: function(){},
|
|
getAll: function(){},
|
|
removeAll: function(){},
|
|
|
|
getIsRunning: function(){
|
|
return this._isRunning;
|
|
},
|
|
getHooks: function(){
|
|
var hookObject = {};
|
|
var sequenceKeys = Object.keys(this._sequences);
|
|
sequenceKeys.forEach(function(sequence){
|
|
// Create an object of the registered hooks
|
|
["start", "stop"].forEach(function(type){
|
|
this._sequences[sequence][type].forEach(function(hook){
|
|
if (!hookObject[hook]) {
|
|
hookObject[hook] = {
|
|
start: [],
|
|
stop: []
|
|
};
|
|
}
|
|
hookObject[hook][type].push(sequence);
|
|
});
|
|
}, _this);
|
|
});
|
|
return hookObject;
|
|
},
|
|
getTexture: function(key){
|
|
return this._textures[key];
|
|
},
|
|
update: function(){},
|
|
|
|
getAnchorPosition: function(position) {
|
|
return this._anchorPosition;
|
|
},
|
|
setAnchorPosition: function(position) {
|
|
this._anchorPosition = position;
|
|
},
|
|
|
|
addNameToMap: function(name, id){
|
|
this.nameMap[name] = id;
|
|
},
|
|
getIdFromNameMap: function(name) {
|
|
return _this.nameMap[name];
|
|
},
|
|
onUpdate: function(delta) {
|
|
var deltaInMs = delta * 1000;
|
|
var withinMargin = 15;
|
|
var entityIDs = Object.keys(_this._entities);
|
|
_this._totalDelta += deltaInMs;
|
|
|
|
// Run through the entities and check if any are ready for edits
|
|
entityIDs.forEach(function(ID){
|
|
var entity = _this._entities[ID];
|
|
var currentIndexTimeStamp = entity._sequenceStartDelta + Number(entity._currentKeys[entity._currentIndex]);
|
|
log("CURRENT TIMESTAMP", currentIndexTimeStamp, false);
|
|
var timeStampDifference = Math.abs(_this._totalDelta - currentIndexTimeStamp);
|
|
log("timeStampDifference", timeStampDifference, false);
|
|
|
|
if (timeStampDifference <= withinMargin) {
|
|
log("entity within timestamp");
|
|
entity.editCurrentIndex();
|
|
}
|
|
});
|
|
},
|
|
onStart: function(name, hook) {
|
|
this._sequences[name].start = this._sequences[name].start.concat(hook);
|
|
return this;
|
|
},
|
|
onStop: function(name, hook) {
|
|
this._sequences[name].stop.push(hook);
|
|
return this;
|
|
},
|
|
start: function(){
|
|
log("starting animation")
|
|
this._isRunning = true;
|
|
var entityIDs = Object.keys(_this._entities);
|
|
entityIDs.forEach(function(ID){
|
|
var entity = _this._entities[ID];
|
|
entity.setRunningSequence(this._currentSequence);
|
|
entity.updateKeys();
|
|
}, this);
|
|
Script.update.connect(this.onUpdate);
|
|
},
|
|
stop: function(){
|
|
log("stop is called");
|
|
this._totalDelta = 0;
|
|
if (this._isRunning) {
|
|
log("about to discconect")
|
|
Script.update.disconnect(this.onUpdate);
|
|
}
|
|
var entityIDs = Object.keys(_this._entities);
|
|
entityIDs.forEach(function(ID){
|
|
var entity = _this._entities[ID];
|
|
entity.reset();
|
|
}, this);
|
|
this._isRunning = false;
|
|
},
|
|
triggerOn: function(name){
|
|
log("trigger on called with", name);
|
|
if (this._isRunning) {
|
|
return;
|
|
}
|
|
if (!name) {
|
|
name = Object.keys(this._sequences)[0];
|
|
}
|
|
this._currentSequence = name;
|
|
this._isRunning = true;
|
|
this.start();
|
|
},
|
|
triggerOff: function(name){
|
|
log("trigger off called with", name);
|
|
if (!this._isRunning) {
|
|
return;
|
|
}
|
|
this._currentSequence = null;
|
|
this.stop();
|
|
this._isRunning = false;
|
|
}
|
|
};
|
|
|
|
|
|
// SEQUENCER DEFINITIONS
|
|
// ////////////////////////////////////////////////////////////////////////
|
|
|
|
var SEQUENCER = new _Sequence();
|
|
|
|
SEQUENCER.Particle = function (properties, name) {
|
|
|
|
log("properties", properties, false)
|
|
var orientation = properties.emitOrientation;
|
|
log("ORIENTATION:", orientation, false);
|
|
orientation = Quat.fromPitchYawRollDegrees(orientation.x,orientation.y,orientation.z);
|
|
properties["emitOrientation"] = orientation;
|
|
properties.type = "ParticleEffect";
|
|
properties.position = SEQUENCER.getAnchorPosition();
|
|
properties.name = name;
|
|
|
|
this._id = Entities.addEntity(properties);
|
|
this._name = name;
|
|
this._properties = properties;
|
|
this._rotation = Entities.getEntityProperties(this._id,'rotation').rotation;
|
|
this._currentIndex = 0;
|
|
this._currentChangeProperty = null;
|
|
this._currentToValue = null;
|
|
this._currentSequenceName = null;
|
|
this._currentTempSequence = {};
|
|
this._runningSequence = null;
|
|
this._sequence = {};
|
|
this._currentKeys = [];
|
|
this._sequenceStartDelta = 0;
|
|
this._shouldLoop = false;
|
|
this._loopStart = 0;
|
|
this._loopEnd = 0;
|
|
this._duration = 0;
|
|
|
|
SEQUENCER.add(this);
|
|
};
|
|
|
|
SEQUENCER.Particle.prototype = {
|
|
at: function(time) {
|
|
log("AT", time, false);
|
|
if (!this._currentTempSequence[String(time)]) {
|
|
this._currentTempSequence[String(time)] = [];
|
|
}
|
|
if (this._currentChangeProperty === LOOP) {
|
|
this._shouldLoop = true;
|
|
this._loopStart = this.currentToValue;
|
|
this._loopEnd = time;
|
|
}
|
|
this._currentTempSequence[String(time)].push({ change: this._currentChangeProperty, to: this._currentToValue });
|
|
this._currentChangeProperty = null;
|
|
this._currentToValue = null;
|
|
// log("updateKeys", this.currentKeys);
|
|
// log("sequence", this.sequence);
|
|
return this;
|
|
},
|
|
change: function (property) {
|
|
log("CHANGE", property, false);
|
|
this._currentChangeProperty = property;
|
|
log("IN CHANGE", this._currentChangeProperty, false);
|
|
return this;
|
|
},
|
|
to: function (value) {
|
|
log("IN TO", this._currentChangeProperty, true);
|
|
log("VALUE", value, true)
|
|
var newValue = value;
|
|
if (arguments.length === 3 || (value instanceof Array && value.length > 1)) {
|
|
if (this._currentChangeProperty.toLowerCase().indexOf("color") > -1) {
|
|
|
|
if (arguments.length === 3) {
|
|
newValue = {
|
|
red: arguments[0],
|
|
green: arguments[1],
|
|
blue: arguments[2]
|
|
};
|
|
} else {
|
|
newValue = {
|
|
red: value[0],
|
|
green: value[1],
|
|
blue: value[2]
|
|
};
|
|
}
|
|
|
|
} else if (
|
|
|
|
(this._currentChangeProperty.toLowerCase().indexOf("rotation") > -1 ||
|
|
this._currentChangeProperty.toLowerCase().indexOf("orientation") > -1) ) {
|
|
if (arguments.length === 3) {
|
|
newValue = Quat.fromPitchYawRollDegrees(arguments[0], arguments[1], arguments[2]);
|
|
} else {
|
|
newValue = Quat.fromPitchYawRollDegrees(value[0], value[1], value[2]);
|
|
}
|
|
|
|
} else {
|
|
if (arguments.length === 3) {
|
|
newValue = {
|
|
x: arguments[0],
|
|
y: arguments[1],
|
|
z: arguments[2]
|
|
};
|
|
} else {
|
|
newValue = {
|
|
x: value[0],
|
|
y: value[1],
|
|
z: value[2]
|
|
};
|
|
}
|
|
}
|
|
}
|
|
if (this._currentChangeProperty.toLowerCase().indexOf("textures") > -1){
|
|
newValue = SEQUENCER.getTexture(value);
|
|
log("newValue Texture", newValue, false)
|
|
}
|
|
this._currentToValue = newValue;
|
|
// log("currentToValue", this.currentToValue);
|
|
return this;
|
|
},
|
|
start: function(name) {
|
|
log("START", name);
|
|
this._sequence[this._currentSequenceName];
|
|
this._currentSequenceName = name;
|
|
return this;
|
|
},
|
|
end: function() {
|
|
log("END");
|
|
|
|
this._sequence[this._currentSequenceName] = this._currentTempSequence;
|
|
SEQUENCER.addSequence(this._currentSequenceName);
|
|
this._currentTempSequence = {};
|
|
this._currentSequenceName = null;
|
|
this._currentOnHooks = [];
|
|
return this;
|
|
},
|
|
incrementIndex: function() {
|
|
this._currentIndex =
|
|
this._currentIndex >= this._currentKeys.length - 1
|
|
? this._currentIndex = 0
|
|
: this._currentIndex += 1;
|
|
},
|
|
edit: function (propArray) {
|
|
var self = this;
|
|
var propertiesToChange = propArray.reduce(function (prev, cur) {
|
|
var changeAmount = cur.to;
|
|
log("CUR.CHANGE", cur.change, true);
|
|
if (cur.change === LOOP) {
|
|
self._sequenceStartDelta = SEQUENCER._totalDelta;
|
|
log("self._sequenceStartDelta", self._sequenceStartDelta);
|
|
}
|
|
if (cur.change === POSITION) {
|
|
var worldOffset = Vec3.multiplyQbyV(self._rotation, cur.to);
|
|
var moveTo = Vec3.sum(SEQUENCER.getAnchorPosition(), worldOffset);
|
|
changeAmount = moveTo;
|
|
}
|
|
prev[cur.change] = changeAmount;
|
|
return prev;
|
|
}, {});
|
|
log("propertiesToChange", propertiesToChange, true)
|
|
Entities.editEntity(this._id, propertiesToChange);
|
|
this.incrementIndex();
|
|
},
|
|
editCurrentIndex: function() {
|
|
this.edit(this._sequence[this._currentSequenceName][this._currentKeys[this._currentIndex]]);
|
|
},
|
|
getID: function() {
|
|
return this._id;
|
|
},
|
|
sortKeys: function(keys) {
|
|
return keys.map(function(key){
|
|
return +key
|
|
}).sort(function(a, b){return a-b});
|
|
},
|
|
updateKeys: function() {
|
|
log("this.sequence", this._sequence, false);
|
|
log("this._currentSequenceName", this._currentSequenceName, false);
|
|
this._currentKeys = this.sortKeys(Object.keys(this._sequence[this._currentSequenceName]));
|
|
},
|
|
reset: function() {
|
|
Entities.editEntity(this._id, this._properties);
|
|
this._sequenceStartDelta = 0;
|
|
},
|
|
setName: function(name) {
|
|
this._name = name;
|
|
},
|
|
setRunningSequence: function(name) {
|
|
log("setRunningSequence called with", name, false)
|
|
this._currentSequenceName = name;
|
|
}
|
|
};
|
|
|
|
module.exports = SEQUENCER; |