1 var jaws = (function(jaws) { 2 3 /** 4 * @class Manages an animation with a given list of frames. "Field Summary" contains options for the Animation()-constructor. 5 * 6 * @property {bool} loop Restart animation when end is reached 7 * @property {bool} bounce Rewind the animation frame by frame when end is reached 8 * @property {int} index Start on this frame 9 * @property {array} frames Images/canvaselements 10 * @property {milliseconds} frame_duration How long should each frame be displayed 11 * @property {int} frame_direction -1 for backwards animation. 1 is default 12 * @property {array} frame_size Containing width/height, eg. [32, 32] 13 * @property {int} offset When cutting out frames from a sprite sheet, start at this frame 14 * @property {string} orientation How to cut out frames frmo sprite sheet, possible values are "down" or "right" 15 * @property {function} on_end Function to call when animation ends. triggers only on non-looping, non-bouncing animations 16 * @property {object} subsets Name specific frames-intervals for easy access later, i.e. {move: [2,4], fire: [4,6]}. Access with animation.subset[name] 17 * 18 * @example 19 * // in setup() 20 * anim = new jaws.Animation({sprite_sheet: "droid_11x15.png", frame_size: [11,15], frame_duration: 100}) 21 * player = new jaws.Sprite({y:300, anchor: "center_bottom"}) 22 * 23 * // in update() 24 * player.setImage( anim.next() ) 25 * 26 * // in draw() 27 * player.draw() 28 * 29 */ 30 jaws.Animation = function Animation(options) { 31 if( !(this instanceof arguments.callee) ) return new arguments.callee( options ); 32 33 jaws.parseOptions(this, options, this.default_options); 34 35 if(options.sprite_sheet) { 36 var sprite_sheet = new jaws.SpriteSheet({image: options.sprite_sheet, scale_image: this.scale_image, frame_size: this.frame_size, orientation: this.orientation, offset: this.offset}) 37 this.frames = sprite_sheet.frames 38 this.frame_size = sprite_sheet.frame_size 39 } 40 41 if(options.scale_image) { 42 var image = (jaws.isDrawable(options.sprite_sheet) ? options.sprite_sheet : jaws.assets.get(options.sprite_sheet)) 43 this.frame_size[0] *= options.scale_image 44 this.frame_size[1] *= options.scale_image 45 options.sprite_sheet = jaws.retroScaleImage(image, options.scale_image) 46 } 47 48 /* Initializing timer-stuff */ 49 this.current_tick = (new Date()).getTime(); 50 this.last_tick = (new Date()).getTime(); 51 this.sum_tick = 0 52 53 if(options.subsets) { 54 this.subsets = {} 55 for(subset in options.subsets) { 56 start_stop = options.subsets[subset] 57 this.subsets[subset] = this.slice(start_stop[0], start_stop[1]) 58 } 59 } 60 } 61 62 jaws.Animation.prototype.default_options = { 63 frames: [], 64 subsets: [], 65 frame_duration: 100, // default: 100ms between each frameswitch 66 index: 0, // default: start with the very first frame 67 loop: 1, 68 bounce: 0, 69 frame_direction: 1, 70 frame_size: null, 71 orientation: "down", 72 on_end: null, 73 offset: 0, 74 scale_image: null, 75 sprite_sheet: null 76 } 77 78 /** 79 * Return a special animationsubset created with "subset"-parameter when initializing 80 * 81 */ 82 jaws.Animation.prototype.subset = function(subset) { 83 return this.subsets[subset] 84 } 85 86 /** 87 Propells the animation forward by counting milliseconds and changing this.index accordingly 88 Supports looping and bouncing animations 89 */ 90 jaws.Animation.prototype.update = function() { 91 this.current_tick = (new Date()).getTime(); 92 this.sum_tick += (this.current_tick - this.last_tick); 93 this.last_tick = this.current_tick; 94 95 if(this.sum_tick > this.frame_duration) { 96 this.index += this.frame_direction 97 this.sum_tick = 0 98 } 99 if( (this.index >= this.frames.length) || (this.index < 0) ) { 100 if(this.bounce) { 101 this.frame_direction = -this.frame_direction 102 this.index += this.frame_direction * 2 103 } 104 else if(this.loop) { 105 if(this.frame_direction < 0) { 106 this.index = this.frames.length -1; 107 } else { 108 this.index = 0; 109 } 110 } 111 else { 112 this.index -= this.frame_direction 113 if (this.on_end) { 114 this.on_end() 115 this.on_end = null 116 } 117 } 118 } 119 return this 120 } 121 122 /** 123 works like Array.slice but returns a new Animation-object with a subset of the frames 124 */ 125 jaws.Animation.prototype.slice = function(start, stop) { 126 var o = {} 127 o.frame_duration = this.frame_duration 128 o.loop = this.loop 129 o.bounce = this.bounce 130 o.on_end = this.on_end 131 o.frame_direction = this.frame_direction 132 o.frames = this.frames.slice().slice(start, stop) 133 return new jaws.Animation(o) 134 }; 135 136 /** 137 Moves animation forward by calling update() and then return the current frame 138 */ 139 jaws.Animation.prototype.next = function() { 140 this.update() 141 return this.frames[this.index] 142 }; 143 144 /** returns true if animation is at the very last frame */ 145 jaws.Animation.prototype.atLastFrame = function() { return (this.index == this.frames.length-1) } 146 147 /** returns true if animation is at the very first frame */ 148 jaws.Animation.prototype.atFirstFrame = function() { return (this.index == 0) } 149 150 151 /** 152 returns the current frame 153 */ 154 jaws.Animation.prototype.currentFrame = function() { 155 return this.frames[this.index] 156 }; 157 158 /** 159 * Debugstring for Animation()-constructor 160 * @example 161 * var anim = new Animation(...) 162 * console.log(anim.toString()) 163 */ 164 jaws.Animation.prototype.toString = function() { return "[Animation, " + this.frames.length + " frames]" } 165 166 return jaws; 167 })(jaws || {}); 168 169