UNPKG

lettuce

Version:

Lettuce JS, Mini Mobile Framework for Romantic with DSL.

294 lines (272 loc) 11.1 kB
/* * MelonJS Game Engine * Copyright (C) 2011 - 2014 Olivier Biot, Jason Oster, Aaron McLeod * http://www.melonjs.org * */ (function () { /** * an object to manage animation * @class * @extends me.Sprite * @memberOf me * @constructor * @param {Number} x the x coordinates of the sprite object * @param {Number} y the y coordinates of the sprite object * @param {Object} settings Contains additional parameters for the animation sheet: * <ul> * <li>{Image} image to use for the animation</li> * <li>{Number} framewidth - of a single frame within the spritesheet</li> * <li>{Number} frameheight - height of a single frame within the spritesheet</li> * <li>{Object} region an instance of: me.video.renderer.Texture#getRegion. The region for when the animation sheet is part of a me.video.renderer.Texture</li> * </ul> * @example * // standalone image * var animationSheet = new me.AnimationSheet(0, 0, { * image: me.loader.getImage('animationsheet'), * framewidth: 64, * frameheight: 64 * }); * // from a texture * var texture = new me.video.renderer.Texture(me.loader.getJSON('texture'), me.loader.getImage('texture')); * var animationSheet = new me.AnimationSheet(0, 0, { * image: texture.getTexture(), * framewidth: 64, * frameheight: 64, * region: texture.getRegion('animationsheet') * }); */ me.AnimationSheet = me.Sprite.extend( /** @scope me.AnimationSheet.prototype */ { /** @ignore */ init : function (x, y, settings) { /** * pause and resume animation<br> * default value : false; * @public * @type Boolean * @name me.AnimationSheet#animationpause */ this.animationpause = false; /** * animation cycling speed (delay between frame in ms)<br> * default value : 100ms; * @public * @type Number * @name me.AnimationSheet#animationspeed */ this.animationspeed = 100; // hold all defined animation this.anim = {}; // a flag to reset animation this.resetAnim = null; // default animation sequence this.current = null; // default animation speed (ms) this.animationspeed = 100; // call the constructor this._super(me.Sprite, "init", [x, y, settings.image, settings.framewidth, settings.frameheight]); // store/reset the current atlas information if (typeof(settings.atlas) !== "undefined") { this.textureAtlas = settings.atlas; this.atlasIndices = settings.atlasIndices; } else { // "regular" spritesheet this.textureAtlas = me.video.renderer.cache.get(settings, settings.image).getAtlas(); this.atlasIndices = null; } // create a default animation sequence with all sprites this.addAnimation("default", null); // set as default this.setCurrentAnimation("default"); }, /** * add an animation <br> * For fixed-sized cell sprite sheet, the index list must follow the * logic as per the following example :<br> * <img src="images/spritesheet_grid.png"/> * @name addAnimation * @memberOf me.AnimationSheet * @function * @param {String} name animation id * @param {Number[]|String[]} index list of sprite index or name * defining the animation * @param {Number} [animationspeed] cycling speed for animation in ms * (delay between each frame). * @see me.AnimationSheet#animationspeed * @example * // walking animation * this.addAnimation("walk", [ 0, 1, 2, 3, 4, 5 ]); * // eating animation * this.addAnimation("eat", [ 6, 6 ]); * // rolling animation * this.addAnimation("roll", [ 7, 8, 9, 10 ]); * // slower animation * this.addAnimation("roll", [ 7, 8, 9, 10 ], 200); */ addAnimation : function (name, index, animationspeed) { this.anim[name] = { name : name, frame : [], idx : 0, length : 0, animationspeed: animationspeed || this.animationspeed, nextFrame : 0 }; if (index == null) { index = []; var j = 0; // create a default animation with all frame this.textureAtlas.forEach(function () { index[j] = j++; }); } // set each frame configuration (offset, size, etc..) for (var i = 0, len = index.length; i < len; i++) { if (typeof(index[i]) === "number") { this.anim[name].frame[i] = this.textureAtlas[index[i]]; } else { // string if (this.atlasIndices === null) { throw new me.Renderable.Error( "string parameters for addAnimation are not allowed for standard spritesheet based Texture" ); } else { this.anim[name].frame[i] = this.textureAtlas[this.atlasIndices[index[i]]]; } } } this.anim[name].length = this.anim[name].frame.length; }, /** * set the current animation * this will always change the animation & set the frame to zero * @name setCurrentAnimation * @memberOf me.AnimationSheet * @function * @param {String} name animation id * @param {String|Function} [onComplete] animation id to switch to when * complete, or callback * @example * // set "walk" animation * this.setCurrentAnimation("walk"); * * // set "walk" animation if it is not the current animation * if (this.isCurrentAnimation("walk")) { * this.setCurrentAnimation("walk"); * } * * // set "eat" animation, and switch to "walk" when complete * this.setCurrentAnimation("eat", "walk"); * * // set "die" animation, and remove the object when finished * this.setCurrentAnimation("die", (function () { * me.game.world.removeChild(this); * return false; // do not reset to first frame * }).bind(this)); * * // set "attack" animation, and pause for a short duration * this.setCurrentAnimation("die", (function () { * this.animationpause = true; * * // back to "standing" animation after 1 second * setTimeout(function () { * this.setCurrentAnimation("standing"); * }, 1000); * * return false; // do not reset to first frame * }).bind(this)); **/ setCurrentAnimation : function (name, resetAnim) { if (this.anim[name]) { this.current = this.anim[name]; this.resetAnim = resetAnim || null; this.setAnimationFrame(this.current.idx); // or 0 ? this.current.nextFrame = this.current.animationspeed; } else { throw new me.Renderable.Error("animation id '" + name + "' not defined"); } }, /** * return true if the specified animation is the current one. * @name isCurrentAnimation * @memberOf me.AnimationSheet * @function * @param {String} name animation id * @return {Boolean} * @example * if (!this.isCurrentAnimation("walk")) { * // do something funny... * } */ isCurrentAnimation : function (name) { return this.current.name === name; }, /** * force the current animation frame index. * @name setAnimationFrame * @memberOf me.AnimationSheet * @function * @param {Number} [index=0] animation frame index * @example * //reset the current animation to the first frame * this.setAnimationFrame(); */ setAnimationFrame : function (idx) { this.current.idx = (idx || 0) % this.current.length; var frame = this.current.frame[this.current.idx]; this.offset = frame.offset; this.width = frame.width; this.height = frame.height; this._sourceAngle = frame.angle; }, /** * return the current animation frame index. * @name getCurrentAnimationFrame * @memberOf me.AnimationSheet * @function * @return {Number} current animation frame index */ getCurrentAnimationFrame : function () { return this.current.idx; }, /** * update the animation<br> * this is automatically called by the game manager {@link me.game} * @name update * @memberOf me.AnimationSheet * @function * @protected * @param {Number} dt time since the last update in milliseconds. */ update : function (dt) { // update animation if necessary if (!this.animationpause && this.current.length > 1) { this.current.nextFrame -= dt; if (this.current.nextFrame <= 0) { this.setAnimationFrame(++this.current.idx); // switch animation if we reach the end of the strip // and a callback is defined if (this.current.idx === 0 && this.resetAnim) { // if string, change to the corresponding animation if (typeof this.resetAnim === "string") { this.setCurrentAnimation(this.resetAnim); } // if function (callback) call it else if (typeof this.resetAnim === "function" && this.resetAnim() === false) { this.current.idx = this.current.length - 1; this.setAnimationFrame(this.current.idx); this._super(me.Sprite, "update", [dt]); return false; } } // set next frame timestamp this.current.nextFrame = this.current.animationspeed; return this._super(me.Sprite, "update", [dt]) || true; } } return this._super(me.Sprite, "update", [dt]); } }); })();