splat-ecs
Version:
A 2D HTML5 Canvas game engine
138 lines (124 loc) • 4.14 kB
JavaScript
var clone = require("./clone");
var components = require("./components");
var ECS = require("entity-component-system").EntityComponentSystem;
var EntityPool = require("entity-component-system").EntityPool;
var registerComponents = require("./components/register");
function Scene(name, globals) {
this.data = {};
this.entities = new EntityPool();
this.globals = globals;
this.name = name;
this.onEnter = function() {};
this.onExit = function() {};
this.renderer = new ECS();
this.state = "stopped";
this.speed = 1.0;
this.simulation = new ECS();
this.simulationStepTime = 5;
this.firstTime = true;
this.accumTime = 0;
this.sceneConfig = globals.require("./data/scenes")[name];
if (typeof this.sceneConfig.onEnter === "string") {
this.onEnter = globals.require(this.sceneConfig.onEnter);
}
if (typeof this.sceneConfig.onExit === "string") {
this.onExit = globals.require(this.sceneConfig.onExit);
}
}
Scene.prototype.start = function(sceneArgs) {
if (this.state !== "stopped") {
return;
}
this.state = "starting";
this.tempArguments = sceneArgs;
};
Scene.prototype._initialize = function() {
this.entities = new EntityPool();
this.firstTime = true;
this.accumTime = 0;
this.data = {
animations: this.globals.animations,
arguments: this.tempArguments || {},
canvas: this.globals.canvas,
context: this.globals.context,
entities: this.entities,
images: this.globals.images,
inputs: this.globals.inputs,
prefabs: this.globals.prefabs,
require: this.globals.require,
scaleCanvasToCssSize: this.globals.scaleCanvasToCssSize,
scaleCanvasToFitRectangle: this.globals.scaleCanvasToFitRectangle,
sceneConfig: this.sceneConfig,
scenes: this.globals.scenes,
sounds: this.globals.sounds,
switchScene: this.switchScene.bind(this)
};
this.simulation = new ECS();
this.renderer = new ECS();
this.simulation.add(function processInputUpdates() {
this.globals.inputs.processUpdates();
}.bind(this));
var systems = this.globals.require("./data/systems");
this.installSystems(systems.simulation, this.simulation, this.data);
this.installSystems(systems.renderer, this.renderer, this.data);
registerComponents(this.entities, components);
registerComponents(this.entities, this.globals.require("./data/components"));
var entities = this.globals.require("./data/entities");
this.entities.load(clone(entities[this.name]) || []);
this.onEnter(this.data);
};
Scene.prototype.stop = function() {
if (this.state === "stopped") {
return;
}
this.state = "stopped";
this.onExit(this.data);
};
Scene.prototype.switchScene = function(scene, sceneArgs) {
this.stop();
this.data.scenes[scene].start(sceneArgs);
};
Scene.prototype.installSystems = function(systems, ecs, data) {
for (var i = 0; i < systems.length; i++) {
var system = systems[i];
if (system.scenes.indexOf(this.name) === -1 && system.scenes !== "all") {
continue;
}
var script = this.globals.require(system.name);
if (script === undefined) {
console.error("failed to load script", system.name);
}
script(ecs, data);
}
};
Scene.prototype.simulate = function(elapsed) {
if (this.state === "stopped") {
return;
}
if (this.state === "starting") {
var start = window.performance.now();
this._initialize();
var end = window.performance.now();
this.accumTime = start - end; // negative so a long initialize doesn't make the first few frames slow
this.state = "started";
}
if (this.firstTime) {
this.firstTime = false;
// run simulation the first time, because not enough time will have elapsed
this.simulation.run(this.entities, 0);
elapsed = 0;
}
elapsed *= this.speed;
this.accumTime += elapsed;
while (this.accumTime >= this.simulationStepTime) {
this.accumTime -= this.simulationStepTime;
this.simulation.run(this.entities, this.simulationStepTime);
}
};
Scene.prototype.render = function(elapsed) {
if (this.state !== "started") {
return;
}
this.renderer.run(this.entities, elapsed);
};
module.exports = Scene;