API Docs for: 0.3
Show:

File: src\sim\Engine.js

'use strict';

//var $ = jQuery =

/**
 * The simulation engine. Manages the state running of the simulation
 *
 * @class Engine
 * @module CrowdSim
 * @submodule Engine
 * @constructor
 * @param {World} world
 * @param {Object} options
 */
var Engine = function(world, options) {
  this.running = false;
  this.iterations = 0;
  //this.agentsSave = JSON.parse(JSON.stringify(world.agents));
  this.world = world || {};
  this.settings = Lazy(options).defaults(Engine.defaults).toObject();
  this.callbacks = this.settings.callbacks;
  delete this.settings.callbacks;
};

/**
 * Get the engine settings, configured in constructor [options]
 *
 * @method getSettings
 * @return {Object} options
 */
Engine.prototype.getSettings = function() {
  return this.settings;
};

/**
 * Sets the simulation world
 *
 * @method setWorld
 * @param {World} world
 */
Engine.prototype.setWorld = function(world) {
  this.world = world;
};

/**
 * Gets the simulation world
 *
 * @method getWorld
 * @return {World}
 */
Engine.prototype.getWorld = function() {
  return this.world;
};

/**
 * Starts the simulation
 *
 * @method run
 * @param {Entity} entity to report in the onStart callback as trigger
 * @return {Boolean} true if running; false otherwise
 */
Engine.prototype.run = function(entity) {
  if (this.running) {
    return;
  }
  this.running = true;
  this.world.freeze(false);
  if (this.callbacks.onStart) {
    this.callbacks.onStart(entity);
  }
  this._step();
  return this.running;
};

/**
 * Advance one step the simulation and stops.
 *
 * @method step
 * @return {Boolean} true if running; false otherwise
 */
Engine.prototype.step = function() {
  if (this.running) {
    this.stop();
  }
  this._step();
  return this.running;
};

/**
 * Internal step of the simulation engine. Periodically called.
 * @method _step
 */
Engine.prototype._step = function() {
  // calculate next execution
  var startTime = new Date();
  var opts = this.settings;
  var timeStepSize = opts.timeStepSize;

  var entity = this.world.step(timeStepSize); // returns entity that request stop a contexts
  this.iterations++;
  if (this.callbacks.onStep) {
    this.callbacks.onStep(this.world);
  }
  // entity requests stop of simulation
  if (entity) {
    this.stop(entity);
  }

  if (this.running) {
    var that = this;
    // using setTimeout instead of setInterval allows dinamycally changing timeStep while running
    var endTime = new Date();
    var timeToWait = (opts.timeStepRun * 1000) - (endTime - startTime);
    timeToWait = timeToWait > 0 ? timeToWait : 0;
    setTimeout(function() {
      that._step();
    }, timeToWait);
  }
};

/**
 * Stops the simulation
 *
 * @method stop
 * @param {Entity} entity to report in the onStart callback as trigger
 * @return {Boolean} true if running; false otherwise
 */
Engine.prototype.stop = function(entity) {
  if (!this.running) {
    return;
  }
  this.world.freeze(true);
  this.running = false;
  if (this.callbacks.onStop) {
    this.callbacks.onStop(entity);
  }
  return this.running;
};

/**
 * Resets=Restarts the state of the simulation.
 *
 * @method reset
 * @return {Boolean} true if running; false otherwise
 */
Engine.prototype.reset = function() {
  var groups = this.world.getGroups();
  Lazy(groups).each(function(g) {
    g.emptyAgents();
  });
  this.stop();
  this.iterations = 0;
  return this.running;
};

Engine.defaults = {
  timeStepSize: 0.05,
  timeStepRun: 0.01,
  callbacks: {
    onStart: null,
    onStep: null,
    onStop: null
  }
};

module.exports = Engine;