Source: anime/index.js

/**
 * Animation system is consist of two powerful sub-systems:
 *
 * 1. Tween : a classic but better tween engine.
 * 2. Action: a Blender/Flash like, keyframe based timeline animation system.
 *
 * @module engine/anime
 *
 * @requires engine/system
 * @requires engine/utils/array
 * @requires engine/anime/tween
 * @requires engine/anime/action
 */
const System = require('engine/system');
const { removeItems } = require('engine/utils/array');

const Tween = require('./tween');
const { ActionPlayer } = require('./action');

/**
 * Anime sub-system.
 * @class
 * @extends {System}
 */
class SystemAnime extends System {
  /**
   * @constructor
   */
  constructor() {
    super();

    /**
     * Name of this system.
     * @type {String}
     */
    this.name = 'Anime';

    /**
     * Animation item collection
     * @type {Object}
     */
    this.anims = {
      '0': [],
    };

    /**
     * Activated tags
     * @type {Array}
     */
    this.activeTags = ['0'];
    /**
     * Deactivated tags
     * @type {Array}
     */
    this.deactiveTags = [];
  }

  /**
   * Overrided update.
   * @memberof SystemAnime#
   * @method update
   * @protected
   * @param  {number} dt Delta time
   */
  update(dt) {
    let i, key, anims, t;
    for (key in this.anims) {
      if (this.activeTags.indexOf(key) < 0) {continue;}

      anims = this.anims[key];
      for (i = 0; i < anims.length; i++) {
        t = anims[i];

        if (!t.isRemoved) {
          t._step(dt);

          if (t.isRemoved) {
            t.recycle();
            removeItems(anims, i--, 1);
          }
        }
      }
    }
  }

  /**
   * Pause animations with a specific tag.
   * @memberof SystemAnime#
   * @method pauseAnimesTagged
   * @param  {string} tag   Tag of the animations to pause.
   * @return {SystemAnime}  System itself.
   */
  pauseAnimesTagged(tag) {
    if (this.timers[tag]) {
      removeItems(this.activeTags, this.activeTags.indexOf(tag), 1);
      this.deactiveTags.push(tag);
    }

    return this;
  }

  /**
   * Resume animations with a specific tag.
   * @memberof SystemAnime#
   * @method resumeAnimesTagged
   * @param  {string} tag     Tag of the animations to resume.
   * @return {SySystemAnime}  System itself.
   */
  resumeAnimesTagged(tag) {
    if (this.timers[tag]) {
      removeItems(this.deactiveTags, this.deactiveTags.indexOf(tag), 1);
      this.activeTags.push(tag);
    }

    return this;
  }

  /**
   * Create a tween for an object.
   * @method tween
   * @memberOf SystemAnime#
   * @param {Oblject} context Context of this tween.
   * @param {string}  [tag]   Tag of this tween (default is '0').
   * @return {module:engine/anime/tween~Tween} Tween instance.
   */
  tween(context, tag = '0') {
    if (!this.anims[tag]) {
      // Create a new tween list
      this.anims[tag] = [];

      // Active new tag by default
      this.activeTags.push(tag);
    }

    let tween = Tween.create(context);
    this.anims[tag].push(tween);

    return tween;
  }

  /**
   * Run an action on a target object
   * @memberof SystemAnime#
   * @method runAction
   * @param {module:engine/animation/action~Action}  action Action to run
   * @param {object}  target Target object
   * @param {string}  [tag]  Tag of this action player (default is '0')
   * @return {module:engine/anime/action~ActionPlayer}  An ActionPlayer instance that runs the specific Action
   */
  runAction(action, target, tag = '0') {
    if (!this.anims[tag]) {
      // Create a new tween list
      this.anims[tag] = [];

      // Active new tag by default
      this.activeTags.push(tag);
    }

    let player = ActionPlayer.create(action, target);
    this.anims[tag].push(player);

    return player;
  }
}

module.exports = SystemAnime;