Source: core/components/sprite_animation.js

if (typeof define !== "function") {
    var define = require("amdefine")(module);
}
define([
        "odin/base/time",
        "odin/core/assets/assets",
        "odin/core/components/component",
        "odin/core/enums"
    ],
    function(Time, Assets, Component, Enums) {
        "use strict";


        var abs = Math.abs,
            WrapMode = Enums.WrapMode;


        /**
         * @class SpriteAnimation
         * @extends Component
         * @brief base class for handling sprite animation sheets
         * @param Object options
         */
        function SpriteAnimation(opts) {
            opts || (opts = {});

            Component.call(this, "SpriteAnimation", opts);

            this.sheet = opts.sheet != undefined ? opts.sheet : undefined;

            this.current = opts.current != undefined ? opts.current : "idle";
            this.mode = opts.mode != undefined ? opts.mode : WrapMode.Loop;

            this.rate = opts.rate != undefined ? opts.rate : 1 / 24;

            this._time = 0;
            this._frame = 0;
            this._order = 1;

            this.playing = this.sheet ? true : false;
        }

        Component.extend(SpriteAnimation);


        SpriteAnimation.prototype.copy = function(other) {

            this.sheet = other.sheet;

            this.current = other.current;
            this.mode = other.mode;

            this.rate = other.rate;

            this._time = other._time;
            this._frame = other._frame;
            this._order = other._order;

            this.playing = other.playing;

            return this;
        };


        SpriteAnimation.prototype.clear = function() {
            Component.prototype.clear.call(this);

            this.sheet = undefined;

            return this;
        };


        SpriteAnimation.prototype.play = function(name, mode, rate) {
            if (!this.sheet) return this;
            if ((this.playing && this.current === name) || !this.sheet[name]) return this;

            this.current = name;
            this.rate = rate != undefined ? rate : (rate = this.rate);
            this.mode = mode || (mode = this.mode);
            this._frame = 0;
            this._order = 1;
            this._time = 0;

            this.playing = true;
            this.emit("play", name, mode, rate);

            return this;
        };


        SpriteAnimation.prototype.stop = function() {

            if (this.playing) this.emit("stop");
            this.playing = false;
            this._frame = 0;
            this._order = 1;
            this._time = 0;

            return this;
        };


        SpriteAnimation.prototype.update = function() {
            if (!this.playing) return;
            var sprite = this.sprite,
                sheet = this.sheet,
                current = sheet[this.current],
                rate, dt, count, length, order, frame, mode, animation;

            if (!sprite || !sheet || !current) return;

            rate = this.rate;
            dt = Time.delta;
            order = this._order;
            frame = this._frame;
            mode = this.mode;

            if (!rate || rate === Infinity || rate < 0) {
                frame = abs(frame) % current.length;
            } else {
                this._time += dt;
                count = this._time / rate;

                if (count >= 1) {
                    this._time = 0;
                    length = current.length;
                    frame += (order * (count | 0));

                    if (mode === WrapMode.Loop) {
                        frame = frame % length;
                    } else if (mode === WrapMode.Once) {
                        if (order > 0) {
                            if (frame >= length) {
                                frame = length - 1;
                                this.stop();
                            }
                        } else {
                            if (frame < 0) {
                                frame = 0;
                                this.stop();
                            }
                        }
                    } else if (mode === WrapMode.PingPong) {
                        if (order > 0) {
                            if (frame >= length) {
                                this._order = -1;
                                frame = length - 1;
                            }
                        } else {
                            if (frame < 0) {
                                this._order = 1;
                                frame = 0;
                            }
                        }
                    } else if (mode === WrapMode.Clamp) {
                        if (order > 0) {
                            if (frame >= length) frame = length - 1;
                        } else {
                            if (frame < 0) frame = 0;
                        }
                    }
                }
            }

            animation = current[frame];
            sprite.x = animation[0];
            sprite.y = animation[1];
            sprite.w = animation[2];
            sprite.h = animation[3];

            this._frame = frame;
        };


        SpriteAnimation.prototype.toJSON = function(json) {
            json = Component.prototype.toJSON.call(this, json);

            json.sheet = this.sheet ? this.sheet.name : undefined;

            json.current = this.current;
            json.mode = this.mode;

            json.rate = this.rate;

            json._time = this._time;
            json._frame = this._frame;
            json._order = this._order;

            json.playing = this.playing;

            return json;
        };


        SpriteAnimation.prototype.fromJSON = function(json) {
            Component.prototype.fromJSON.call(this, json);

            this.sheet = json.sheet ? Assets.get(json.sheet) : undefined;

            this.current = json.current;
            this.mode = json.mode;

            this.rate = json.rate;

            this._time = json._time;
            this._frame = json._frame;
            this._order = json._order;

            this.playing = json.playing;

            return this;
        };


        return SpriteAnimation;
    }
);