diff --git a/lib/MapRender.js b/lib/MapRender.js index dc51667..39b9cc9 100644 --- a/lib/MapRender.js +++ b/lib/MapRender.js @@ -29,6 +29,12 @@ ltjs.MapRender = Class( 'MapRender', */ 'private const _LOCK': '__$$MapRenderLock$$', + /** + * Animation interval in milliseconds + * @type {number} + */ + 'private const _ANIM_INTERVAL': 200, + /** * 2d context to which map should be drawn @@ -48,6 +54,12 @@ ltjs.MapRender = Class( 'MapRender', */ 'private _tiles': {}, + /** + * Animation timer + * @type {number} + */ + 'private _animTimer': 0, + /** * Initialize renderer with a canvas context and a tile set @@ -114,6 +126,9 @@ ltjs.MapRender = Class( 'MapRender', { var c = this._ctxObj.canvas; + // clear any running animations + this._clearAnimation(); + // destroy the overlay canvas c.parentNode.removeChild( c ); @@ -168,6 +183,9 @@ ltjs.MapRender = Class( 'MapRender', sizey = size[ 1 ], i = objs.length, + // tiles to animate + anim = [], + // get the width and height from one of the tiles t = this._tiles.dirt.data, w = t.width, @@ -177,10 +195,12 @@ ltjs.MapRender = Class( 'MapRender', // see Map.getObjects()) while ( i-- ) { - var oid = objs[ i ], - tid = omap[ oid ], - x = ( Math.floor( i / sizex ) * w ), - y = ( ( i % sizey ) * h ); + var oid = objs[ i ], + tid = omap[ oid ], + tile = ( this._tiles[ tid ] || {} ).first, + + x = ( Math.floor( i / sizex ) * w ), + y = ( ( i % sizey ) * h ); // tunnels are handled a bit differently than other objects if ( map.isObjectTunnel( oid ) ) @@ -189,13 +209,28 @@ ltjs.MapRender = Class( 'MapRender', continue; } - this._drawTile( tid, x, y ); + // queue for animation if it contains more than a single frame + if ( this._canAnimate( tid ) ) + { + anim.push( [ tile, x, y ] ); + } + + this._drawTile( tile, x, y ); } + this._beginAnimation( anim ); + return this; }, + 'private _canAnimate': function( tid ) + { + var tdata = this._tiles[ tid ]; + return ( tdata.next !== tdata ); + }, + + /** * Draw the tile identified by the given id * @@ -209,12 +244,11 @@ ltjs.MapRender = Class( 'MapRender', * * @return {undefined} */ - 'private _drawTile': function( tid, x, y ) + 'private _drawTile': function( tile, x, y ) { - var tile = this._tiles[ tid ], - ctx = ( tile.masked ) ? this._ctxObj : this._ctx; + var ctx = ( tile.masked ) ? this._ctxObj : this._ctx; - ctx.putImageData( this._tiles[ tid ].first.data, x, y ); + ctx.putImageData( tile.data, x, y ); if ( tile.masked ) { @@ -246,5 +280,53 @@ ltjs.MapRender = Class( 'MapRender', // render the tile to the overlay canvas this._ctxObj.putImageData( tdata, x, y ); + }, + + + /** + * Begin basic tile animation + * + * At each animation interval, each tile will be advanced a single frame and + * rendered atop of the previous. + * + * @param {Array.>} anim array of tiles to + * animate; tdata,x,y + * + * @return {number} animation timer id + */ + 'private _beginAnimation': function( anim ) + { + var _self = this; + + // clear any existing rendering animations + this._clearAnimation(); + + return this._animTimer = setInterval( function() + { + var i = anim.length; + + while ( i-- ) + { + var cur = anim[ i ]; + + // draw next frame + cur[ 0 ] = cur[ 0 ].next; + _self._drawTile.apply( _self, anim[ i ] ); + } + }, this.__self.$( '_ANIM_INTERVAL' ) ); + }, + + + /** + * Clear any running animation timers + * + * It is important that this be done when a MapRender instance is done being + * used, or it will remain in memory indefinitely! + * + * @return {undefined} + */ + 'private _clearAnimation': function() + { + this._animTimer = +clearInterval( this._animTimer ); } } );