lettuce
Version:
Lettuce JS, Mini Mobile Framework for Romantic with DSL.
498 lines (446 loc) • 18.8 kB
JavaScript
(function() {
var pe = game.ParticleEditor = game.ParticleEditor || {};
pe.EmitterList = Object.extend({
init : function(emitterController, container) {
this.emitterController = emitterController;
this.emitters = [];
this.rootNode = container;
var separator = document.createElement("div");
separator.classList.add("category");
separator.appendChild(document.createTextNode("emitter list"));
this.rootNode.appendChild(separator);
var select = this.emitterList = document.createElement("select");
select.setAttribute("size", 10);
select.addEventListener("change", this.onChange.bind(this));
this.rootNode.appendChild(select);
var createButton = document.createElement("input");
createButton.value = "create";
createButton.setAttribute("type", "button");
createButton.addEventListener("click", this.createEmitter.bind(this));
this.rootNode.appendChild(createButton);
var destroyButton = document.createElement("input");
destroyButton.value = "destroy";
destroyButton.setAttribute("type", "button");
destroyButton.addEventListener("click", this.destroyEmitter.bind(this));
this.rootNode.appendChild(destroyButton);
},
clear : function() {
for ( var emitters = this.emitters, i = emitters.length, obj; i--, obj = emitters[i];) {
me.game.world.removeChild(obj.container);
me.game.world.removeChild(obj);
}
this.emitters.length = 0;
this.updateList();
},
createEmitter : function(params) {
var x = me.game.viewport.getWidth() / 2;
var y = me.game.viewport.getHeight() / 2;
var emitter = new me.ParticleEmitter(x, y, params);
emitter.name = "emitter" + me.utils.createGUID();
emitter.z = 10;
me.game.world.addChild(emitter);
me.game.world.addChild(emitter.container);
emitter.streamParticles();
this.addEmitter(emitter);
this.selectEmitter(emitter);
return emitter;
},
destroyEmitter : function() {
var emitter = this.emitters[this.emitterList.selectedIndex];
if (emitter) {
this.removeEmitter(emitter);
me.game.world.removeChild(emitter.container);
me.game.world.removeChild(emitter);
return emitter;
}
return null;
},
addEmitter : function(emitter) {
this.emitters.push(emitter);
this.updateList();
},
removeEmitter : function(emitter) {
for ( var emitters = this.emitters, i = emitters.length, obj; i--, obj = emitters[i];) {
if (obj === emitter) {
emitters.splice(i, 1);
this.updateList();
break;
}
}
},
selectEmitter : function(emitter) {
this.emitterList.selectedIndex = -1;
for ( var emitters = this.emitters, i = emitters.length, obj; i--, obj = emitters[i];) {
if (obj === emitter) {
this.emitterList.selectedIndex = i;
break;
}
}
this.onChange();
},
updateList : function() {
var select = this.emitterList;
var options = [];
var option = select.firstChild;
while (option) {
options[option.value] = option;
option = option.nextSibling;
}
for ( var i = 0, emitters = this.emitters, length = emitters.length, emitter; i < length; ++i) {
emitter = emitters[i];
if (options[i]) {
option = options[i];
option.firstChild.textContent = emitter.name;
options[i] = null;
} else {
option = document.createElement("option");
option.appendChild(document.createTextNode(emitter.name));
}
option.setAttribute("value", i);
select.appendChild(option);
}
for ( var i = options.length, obj; i--, obj = options[i];) {
if (!!obj) {
if (obj.remove) {
obj.remove();
} else if (obj.removeNode) {
obj.removeNode(true);
} else {
console.warn("cannot remove DOM element");
}
}
}
var index = (select.selectedIndex === -1) ? this.emitters.length - 1 : select.selectedIndex;
this.selectEmitter(this.emitters[index]);
},
onChange : function() {
var emitter = this.emitters[this.emitterList.selectedIndex];
this.emitterController.setEmitter(emitter || null);
me.event.publish("emitterChanged", [ emitter ]);
}
});
pe.EmitterController = Object.extend({
init : function(container) {
this.widgets = [];
this.ingameWidgets = [];
this.syncId = null;
this.rootNode = container;
var widget;
this.addCategorySeparator("controls");
this.addControlButtons();
this.addCategorySeparator("ingame widgets");
this.addWidgetButtons();
this.addWidget(new pe.ShapeWidget(), true);
this.addWidget(new pe.VelocityWidget(), true);
this.addWidget(new pe.VelocityVariationWidget(), true);
this.addWidget(new pe.ForceWidget(), true);
this.addCategorySeparator("general");
widget = new pe.TextInputWidget("name");
widget.property.setValue = function(value) {
if (!this.object) {
return false;
}
var object = this._getNestedObject(), propertyName = this.propertyName;
if (object[propertyName] !== value) {
object[propertyName] = value;
game.EmitterList.updateList();
me.event.publish("propertyChanged", [ this.object ]);
return true;
}
return false;
};
widget.sync = function() {
var value = this.property.getValue() || "";
if (value !== this.input.value) {
this.input.value = value;
game.EmitterList.updateList();
}
}
this.addWidget(widget);
this.addWidget(new pe.NumberInputWidget("z", {
min : 0,
sliderMax : 100,
step : 1
}));
this.addWidget(new pe.BooleanInputWidget("onlyInViewport"));
this.addWidget(new pe.BooleanInputWidget("floating"));
this.addWidget(new pe.NumberInputWidget("framesToSkip", {
min : 0,
sliderMax : 5,
step : 1
}));
this.addCategorySeparator("emitter properties");
widget = new pe.NumberInputWidget("width", {
min : 0,
sliderMax : 800,
step : 1
});
widget.property.setValue = function(value) {
var object = this.object;
if (object.width !== value) {
object.resize(value, object.height);
me.event.publish("propertyChanged", [ object ]);
}
};
this.addWidget(widget);
widget = new pe.NumberInputWidget("height", {
min : 0,
sliderMax : 600,
step : 1
});
widget.property.setValue = function(value) {
var object = this.object;
if (object.height !== value) {
object.resize(object.width, value);
me.event.publish("propertyChanged", [ object ]);
}
};
this.addWidget(widget);
this.addWidget(new pe.NumberInputWidget("totalParticles", {
min : 1,
sliderMax : 500,
step : 1
}));
this.addWidget(new pe.NumberInputWidget("maxParticles", {
min : 1,
sliderMax : 100,
step : 1
}));
this.addWidget(new pe.NumberInputWidget("frequency", {
min : 1,
sliderMax : 100,
step : 1
}));
this.addWidget(new pe.NumberInputWidget("duration", {
min : 0,
sliderMax : 10000,
step : 100
}));
this.addCategorySeparator("particle path");
this.addWidget(new pe.NumberInputWidget("angle", {
min : -Math.PI,
max : Math.PI,
}));
this.addWidget(new pe.NumberInputWidget("angleVariation", {
min : 0,
max : Math.PI,
}));
this.addWidget(new pe.NumberInputWidget("speed", {
min : 0,
sliderMax : 30,
}));
this.addWidget(new pe.NumberInputWidget("speedVariation", {
min : 0,
sliderMax : 30,
}));
this.addWidget(new pe.NumberInputWidget("gravity", {
sliderMin : -5,
sliderMax : 5,
}));
this.addWidget(new pe.NumberInputWidget("wind", {
sliderMin : -5,
sliderMax : 5,
}));
this.addCategorySeparator("particle properties");
this.addWidget(new pe.ImageSelectionWidget("image"));
this.addWidget(new pe.NumberInputWidget("minLife", {
min : 0,
sliderMax : 10000,
step : 100
}));
this.addWidget(new pe.NumberInputWidget("maxLife", {
min : 0,
sliderMax : 10000,
step : 100
}));
this.addWidget(new pe.NumberInputWidget("minRotation", {
min : -Math.PI,
max : Math.PI,
}));
this.addWidget(new pe.NumberInputWidget("maxRotation", {
min : -Math.PI,
max : Math.PI,
}));
this.addWidget(new pe.NumberInputWidget("minStartScale", {
min : 0,
sliderMax : 5,
}));
this.addWidget(new pe.NumberInputWidget("maxStartScale", {
min : 0,
sliderMax : 5,
}));
this.addWidget(new pe.NumberInputWidget("minEndScale", {
min : 0,
sliderMax : 5,
}));
this.addWidget(new pe.NumberInputWidget("maxEndScale", {
min : 0,
sliderMax : 5,
}));
this.addWidget(new pe.BooleanInputWidget("followTrajectory"));
this.addWidget(new pe.BooleanInputWidget("textureAdditive"));
me.event.subscribe("propertyChanged", this.onChange.bind(this));
this.ingameWidgets.forEach(this.showIngameWidgets);
},
addControlButtons : function() {
var buttonContainer = document.createElement("div");
buttonContainer.classList.add("buttons");
this.rootNode.appendChild(buttonContainer);
var streamButton = this.streamButton = document.createElement("input");
streamButton.value = "stream";
streamButton.setAttribute("type", "button");
streamButton.addEventListener("click", this.controlStream.bind(this));
buttonContainer.appendChild(streamButton);
var burstButton = document.createElement("input");
burstButton.value = "burst";
burstButton.setAttribute("type", "button");
burstButton.addEventListener("click", this.controlBurst.bind(this));
buttonContainer.appendChild(burstButton);
},
addWidgetButtons : function() {
var buttonContainer = document.createElement("div");
buttonContainer.classList.add("buttons");
this.rootNode.appendChild(buttonContainer);
var showButton = this.showButton = document.createElement("input");
showButton.value = "show all";
showButton.setAttribute("type", "button");
showButton.addEventListener("click", this.ingameWidgets.forEach.bind(this.ingameWidgets, this.showIngameWidgets));
buttonContainer.appendChild(showButton);
var hideButton = document.createElement("input");
hideButton.value = "hide all";
hideButton.setAttribute("type", "button");
hideButton.addEventListener("click", this.ingameWidgets.forEach.bind(this.ingameWidgets, this.hideIngameWidgets));
buttonContainer.appendChild(hideButton);
},
showIngameWidgets : function(widget) {
widget.show();
},
hideIngameWidgets : function(widget) {
widget.hide();
},
addCategorySeparator : function(label) {
var separator = document.createElement("div");
separator.classList.add("category");
separator.appendChild(document.createTextNode(label));
this.rootNode.appendChild(separator);
},
controlStream : function(event) {
if (!this.emitter.isRunning()) {
this.emitter.streamParticles();
} else {
this.emitter.stopStream();
}
this.updateStreamButton();
},
controlBurst : function(event) {
this.emitter.burstParticles();
this.updateStreamButton();
},
setEmitter : function(emitter) {
this.emitter = emitter;
this.widgets.forEach(this.sync, this);
this.updateStreamButton();
},
updateStreamButton : function() {
if (this.emitter && this.emitter.isRunning()) {
this.streamButton.value = "stop stream";
} else {
this.streamButton.value = "start stream";
}
},
onChange : function(emitter) {
if (this.emitter === emitter && this.syncId === null) {
this.syncId = setTimeout(this.doSync.bind(this), 50);
}
},
doSync : function() {
this.syncId = null;
this.updateStreamButton();
this.widgets.forEach(this.sync, this);
},
sync : function(widget) {
widget.setObject(this.emitter);
widget.sync();
},
addWidget : function(widget, ingame) {
widget.appendTo(this.rootNode);
this.widgets.push(widget);
if (ingame) {
this.ingameWidgets.push(widget);
}
},
});
pe.CodeGenerator = Object.extend({
init : function(controller, container) {
this.emitter = null;
this.syncId = null;
me.event.subscribe("propertyChanged", this.onChange.bind(this));
me.event.subscribe("emitterChanged", this.setEmitter.bind(this));
this.rootNode = container;
var separator = document.createElement("div");
separator.classList.add("category");
separator.appendChild(document.createTextNode("source code"));
this.rootNode.appendChild(separator);
var output = this.output = document.createElement("textarea");
this.rootNode.appendChild(output);
},
setEmitter : function(emitter) {
this.emitter = emitter;
this.onChange(emitter);
},
onChange : function(emitter) {
if (this.emitter === emitter && this.syncId === null) {
this.syncId = setTimeout(this.generateCode.bind(this), 100);
}
},
generateCode : function() {
var emitter = this.emitter;
if (emitter) {
var defaults = me.ParticleEmitterSettings;
var code = [];
var settings = [];
code.push("var x = me.game.viewport.getWidth() / 2;");
code.push("var y = me.game.viewport.getHeight() / 2;");
if (emitter.image !== defaults.image) {
code.push("var image = me.loader.getImage('" + this.getImageName() + "');");
settings.push(" image: image");
}
for ( var i in defaults) {
if (defaults.hasOwnProperty(i) && i !== "image" && emitter[i] !== defaults[i]) {
settings.push(" " + i + ": " + emitter[i]);
}
}
if (settings.length > 0) {
code.push("var emitter = new me.ParticleEmitter(x, y, {");
code.push(settings.join(",\n"));
code.push("});");
} else {
code.push("var emitter = new me.ParticleEmitter(x, y);");
}
code.push("emitter.name = '" + emitter.name + "';");
code.push("emitter.z = " + emitter.z + ";");
code.push("me.game.world.addChild(emitter);");
code.push("me.game.world.addChild(emitter.container);");
code.push("emitter.streamParticles();");
this.output.value = code.join("\n");
} else {
this.output.value = "";
}
this.syncId = null;
},
getImageName : function() {
var image = this.emitter.image, imageName = "";
if (image) {
var resourceList = game.resources;
for ( var i = 0, length = resourceList.length, resource; i < length; ++i) {
resource = resourceList[i];
if (image === me.loader.getImage(resource.name)) {
imageName = resource.name;
break;
}
}
}
return imageName;
}
});
})();