Using circular linked lists for tile animations
This will drastically simplify animations and allow for a more basic mapping of "game objects" to tilesmaster
parent
ae01d6ee08
commit
5e60d6c9e5
|
@ -30,8 +30,8 @@ ltjs.ClassicTileDfn = Class( 'ClassicTileDfn' )
|
||||||
*
|
*
|
||||||
* The definition should be an array of arrays, with the first index
|
* The definition should be an array of arrays, with the first index
|
||||||
* representing the tile id and the second index representing whether or not
|
* representing the tile id and the second index representing whether or not
|
||||||
* a mask should be applied (0 or 1). A list of standard tile ids are
|
* a mask should be applied (0 or 1). Multiple tiles with the same id will
|
||||||
* provided at the top of this file.
|
* be combined into frames for animation.
|
||||||
*
|
*
|
||||||
* The tiles are expected to be parsed per row, beginning at the upper-left
|
* The tiles are expected to be parsed per row, beginning at the upper-left
|
||||||
* corner. Specifying the tiles in this manner is both concise and helps to
|
* corner. Specifying the tiles in this manner is both concise and helps to
|
||||||
|
@ -49,19 +49,19 @@ ltjs.ClassicTileDfn = Class( 'ClassicTileDfn' )
|
||||||
[ 'tdown', 1 ], /* tank down */
|
[ 'tdown', 1 ], /* tank down */
|
||||||
[ 'tleft', 1 ], /* tank left */
|
[ 'tleft', 1 ], /* tank left */
|
||||||
[ 'base', 0 ], /* base */
|
[ 'base', 0 ], /* base */
|
||||||
[ 'basealt', 0 ], /* base alt */
|
[ 'base', 0 ], /* base alt */
|
||||||
[ 'basealt2', 0 ], /* base alt 2 */
|
[ 'base', 0 ], /* base alt 2 */
|
||||||
[ 'water', 0 ], /* water */
|
[ 'water', 0 ], /* water */
|
||||||
[ 'wateralt', 0 ], /* water alt */
|
[ 'water', 0 ], /* water alt */
|
||||||
|
|
||||||
[ 'wateralt2', 0 ], /* water alt 2 */
|
[ 'water', 0 ], /* water alt 2 */
|
||||||
[ 'atdownb', 1 ], /* anti-tank, blown up, down */
|
[ 'atdownb', 1 ], /* anti-tank, blown up, down */
|
||||||
[ 'block', 0 ], /* non-movable block */
|
[ 'block', 0 ], /* non-movable block */
|
||||||
[ 'mblock', 0 ], /* movable block */
|
[ 'mblock', 0 ], /* movable block */
|
||||||
[ 'brick', 0 ], /* brick */
|
[ 'brick', 0 ], /* brick */
|
||||||
[ 'atup', 1 ], /* anti-tank up */
|
[ 'atup', 1 ], /* anti-tank up */
|
||||||
[ 'atupalt', 1 ], /* anti-tank up alt */
|
[ 'atup', 1 ], /* anti-tank up alt */
|
||||||
[ 'atupalt2', 1 ], /* anti-tank up alt 2 */
|
[ 'atup', 1 ], /* anti-tank up alt 2 */
|
||||||
[ 'mblockw', 0 ], /* movable block in water */
|
[ 'mblockw', 0 ], /* movable block in water */
|
||||||
[ 'mirrorul', 1 ], /* mirror up-left */
|
[ 'mirrorul', 1 ], /* mirror up-left */
|
||||||
|
|
||||||
|
@ -69,28 +69,28 @@ ltjs.ClassicTileDfn = Class( 'ClassicTileDfn' )
|
||||||
[ 'mirrordr', 1 ], /* mirror down-right */
|
[ 'mirrordr', 1 ], /* mirror down-right */
|
||||||
[ 'mirrordl', 1 ], /* mirror down-left */
|
[ 'mirrordl', 1 ], /* mirror down-left */
|
||||||
[ 'owup', 0 ], /* one-way up */
|
[ 'owup', 0 ], /* one-way up */
|
||||||
[ 'owupalt', 0 ], /* one-way up alt */
|
[ 'owup', 0 ], /* one-way up alt */
|
||||||
[ 'owupalt2', 0 ], /* one-way up alt 2 */
|
[ 'owup', 0 ], /* one-way up alt 2 */
|
||||||
[ 'owright', 0 ], /* one-way right */
|
[ 'owright', 0 ], /* one-way right */
|
||||||
[ 'owrightalt', 0 ], /* one-way right alt */
|
[ 'owright', 0 ], /* one-way right alt */
|
||||||
[ 'owrightalt2', 0 ], /* one-way right alt 2 */
|
[ 'owright', 0 ], /* one-way right alt 2 */
|
||||||
[ 'owdown', 0 ], /* one-way down */
|
[ 'owdown', 0 ], /* one-way down */
|
||||||
|
|
||||||
[ 'owdownalt', 0 ], /* one-way down alt */
|
[ 'owdown', 0 ], /* one-way down alt */
|
||||||
[ 'owdownalt2', 0 ], /* one-way down alt 2 */
|
[ 'owdown', 0 ], /* one-way down alt 2 */
|
||||||
[ 'owleft', 0 ], /* one-way left */
|
[ 'owleft', 0 ], /* one-way left */
|
||||||
[ 'owleftalt', 0 ], /* one-way left alt */
|
[ 'owleft', 0 ], /* one-way left alt */
|
||||||
[ 'owleftalt2', 0 ], /* one-way left alt 3 */
|
[ 'owleft', 0 ], /* one-way left alt 3 */
|
||||||
[ 'atright', 1 ], /* anti-tank right */
|
[ 'atright', 1 ], /* anti-tank right */
|
||||||
[ 'atrightalt', 1 ], /* anti-tank right alt */
|
[ 'atright', 1 ], /* anti-tank right alt */
|
||||||
[ 'atrightalt2', 1 ], /* anti-tank right alt 2 */
|
[ 'atright', 1 ], /* anti-tank right alt 2 */
|
||||||
[ 'atdown', 1 ], /* anti-tank down */
|
[ 'atdown', 1 ], /* anti-tank down */
|
||||||
[ 'atdownalt', 1 ], /* anti-tank down alt */
|
[ 'atdown', 1 ], /* anti-tank down alt */
|
||||||
|
|
||||||
[ 'atdownalt2', 1 ], /* anti-tank down alt 2 */
|
[ 'atdown', 1 ], /* anti-tank down alt 2 */
|
||||||
[ 'atleft', 1 ], /* anti-tank left */
|
[ 'atleft', 1 ], /* anti-tank left */
|
||||||
[ 'atleftalt', 1 ], /* anti-tank left alt */
|
[ 'atleft', 1 ], /* anti-tank left alt */
|
||||||
[ 'atleftalt2', 1 ], /* anti-tank left alt 2 */
|
[ 'atleft', 1 ], /* anti-tank left alt 2 */
|
||||||
[ 'cblock', 0 ], /* crystal block */
|
[ 'cblock', 0 ], /* crystal block */
|
||||||
[ 'cblockht', 0 ], /* crystal block hit by tank */
|
[ 'cblockht', 0 ], /* crystal block hit by tank */
|
||||||
[ 'rmirrorul', 0 ], /* roto-mirror up-left */
|
[ 'rmirrorul', 0 ], /* roto-mirror up-left */
|
||||||
|
|
|
@ -28,9 +28,13 @@
|
||||||
* add additional features to the game, or even to simply restructure the tile
|
* add additional features to the game, or even to simply restructure the tile
|
||||||
* positions of the current one), we have them covered.
|
* positions of the current one), we have them covered.
|
||||||
*
|
*
|
||||||
|
* Many tiles are used for the purpose of creating animations. In order to
|
||||||
|
* support an arbitrary number of frame tiles for any type of tile, animations
|
||||||
|
* will be created from tiles that share the same id. When a tile is encountered
|
||||||
|
* with a duplicate id, it is added to any previous tiles to create animation
|
||||||
|
* frames in the order in which they appear in the definition.
|
||||||
|
*
|
||||||
* Below is a list of standard ids that must be mapped for classic game play.
|
* Below is a list of standard ids that must be mapped for classic game play.
|
||||||
* The *alt tiles are used in animation (the terminology comes from the original
|
|
||||||
* game sources).
|
|
||||||
*
|
*
|
||||||
* dirt - dirt
|
* dirt - dirt
|
||||||
* tup - tank up
|
* tup - tank up
|
||||||
|
@ -38,55 +42,30 @@
|
||||||
* tdown - tank down
|
* tdown - tank down
|
||||||
* tleft - tank left
|
* tleft - tank left
|
||||||
* base - base
|
* base - base
|
||||||
* basealt - base alt
|
|
||||||
* basealt2 - base alt 2
|
|
||||||
* water - water
|
* water - water
|
||||||
* wateralt - water alt
|
|
||||||
*
|
|
||||||
* wateralt2 - water alt 2
|
|
||||||
* atdownb - anti-tank down
|
* atdownb - anti-tank down
|
||||||
* block - block
|
* block - block
|
||||||
* mblock - movable block
|
* mblock - movable block
|
||||||
* brick - brick
|
* brick - brick
|
||||||
* atup - anti-tank up
|
* atup - anti-tank up
|
||||||
* atupalt - anti-tank up alt
|
|
||||||
* atupalt2 - anti-tank up alt 2
|
|
||||||
* mblockw - movable block in water
|
* mblockw - movable block in water
|
||||||
* mirrorul - mirror up-left
|
* mirrorul - mirror up-left
|
||||||
*
|
|
||||||
* mirrorur - mirror up-right
|
* mirrorur - mirror up-right
|
||||||
* mirrordr - mirror down-right
|
* mirrordr - mirror down-right
|
||||||
* mirrordl - mirror down-left
|
* mirrordl - mirror down-left
|
||||||
* owup - one-way up
|
* owup - one-way up
|
||||||
* owupalt - one-way up alt
|
|
||||||
* owupalt2 - one-way up alt 2
|
|
||||||
* owright - one-way right
|
* owright - one-way right
|
||||||
* owrightalt - one-way right alt
|
|
||||||
* owrightalt2 - one-way right alt 2
|
|
||||||
* owdown - one-way down
|
* owdown - one-way down
|
||||||
*
|
|
||||||
* owdownalt - one-way down alt
|
|
||||||
* owdownalt2 - one-way down alt 2
|
|
||||||
* owleft - one-way left
|
* owleft - one-way left
|
||||||
* owleftalt - one-way left alt
|
|
||||||
* owleftalt2 - one-way left alt 3
|
|
||||||
* atright - anti-tank right
|
* atright - anti-tank right
|
||||||
* atrightalt - anti-tank right alt
|
|
||||||
* atrightalt2 - anti-tank right alt 2
|
|
||||||
* atdown - anti-tank down
|
* atdown - anti-tank down
|
||||||
* atdownalt - anti-tank down alt
|
|
||||||
*
|
|
||||||
* atdownalt2 - anti-tank down alt 2
|
|
||||||
* atleft - anti-tank left
|
* atleft - anti-tank left
|
||||||
* atleftalt - anti-tank left alt
|
|
||||||
* atleftalt2 - anti-tank left alt 2
|
|
||||||
* cblock - crystal block
|
* cblock - crystal block
|
||||||
* cblockht - crystal block hit by tank
|
* cblockht - crystal block hit by tank
|
||||||
* rmirrorul - roto-mirror up-left
|
* rmirrorul - roto-mirror up-left
|
||||||
* rmirrorur - roto-mirror up-right
|
* rmirrorur - roto-mirror up-right
|
||||||
* rmirrordr - roto-mirror down-right
|
* rmirrordr - roto-mirror down-right
|
||||||
* rmirrordl - roto-mirror down-left
|
* rmirrordl - roto-mirror down-left
|
||||||
*
|
|
||||||
* cblockhat - crystal block hit by anti-tank
|
* cblockhat - crystal block hit by anti-tank
|
||||||
* atrightb - anti-tank, blown up, right
|
* atrightb - anti-tank, blown up, right
|
||||||
* atleftb - anti-tank, blown up, left
|
* atleftb - anti-tank, blown up, left
|
||||||
|
@ -112,7 +91,8 @@ ltjs.TileDfn = Interface( 'TileDfn',
|
||||||
* The definition should be an array of arrays, with the first index
|
* The definition should be an array of arrays, with the first index
|
||||||
* representing the tile id and the second index representing whether or not
|
* representing the tile id and the second index representing whether or not
|
||||||
* a mask should be applied (0 or 1). A list of standard tile ids are
|
* a mask should be applied (0 or 1). A list of standard tile ids are
|
||||||
* provided at the top of this file.
|
* provided at the top of this file. Multiple tiles with the same id will be
|
||||||
|
* combined into frames to create an animation.
|
||||||
*
|
*
|
||||||
* The tiles are expected to be parsed per row, beginning at the upper-left
|
* The tiles are expected to be parsed per row, beginning at the upper-left
|
||||||
* corner. Specifying the tiles in this manner is both concise and helps to
|
* corner. Specifying the tiles in this manner is both concise and helps to
|
||||||
|
|
|
@ -258,7 +258,7 @@ ltjs.TileMasker = Class( 'TileMasker',
|
||||||
// create each tile (preserving order, thus no decrementing)
|
// create each tile (preserving order, thus no decrementing)
|
||||||
while ( ++i < len )
|
while ( ++i < len )
|
||||||
{
|
{
|
||||||
var name = tdata[ i ][ 0 ],
|
var id = tdata[ i ][ 0 ],
|
||||||
mask = tdata[ i ][ 1 ],
|
mask = tdata[ i ][ 1 ],
|
||||||
|
|
||||||
// calculate the X and Y position of this tile based on the tile
|
// calculate the X and Y position of this tile based on the tile
|
||||||
|
@ -268,15 +268,48 @@ ltjs.TileMasker = Class( 'TileMasker',
|
||||||
|
|
||||||
// the third index indicates whether or not a mask should be applied
|
// the third index indicates whether or not a mask should be applied
|
||||||
// to the tile
|
// to the tile
|
||||||
tiles[ name ] = ( mask === 1 )
|
this.appendTileFrame( tiles, id, ( mask === 1 )
|
||||||
? this.getMaskedTileData( data_mask, x, y )
|
? this.getMaskedTileData( data_mask, x, y )
|
||||||
: this.getTileData( x, y );
|
: this.getTileData( x, y )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
callback( tiles );
|
callback( tiles );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a tile frame to the set, permitting animation
|
||||||
|
*
|
||||||
|
* This creates a circular linked list with each of the frames for a given
|
||||||
|
* tile id. This structure is ideal for looping animations. One can simply
|
||||||
|
* check to see if the tile has a single frame by performing a strict
|
||||||
|
* equality check on the current tile and its 'next' entry.
|
||||||
|
*
|
||||||
|
* @param {Object.<string>} set set to append tile frame to
|
||||||
|
* @param {string} id tile id
|
||||||
|
* @param {Object} data tile ImageData
|
||||||
|
*
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
'protected appendTileFrame': function( set, id, data )
|
||||||
|
{
|
||||||
|
var prev = set[ id ];
|
||||||
|
|
||||||
|
set[ id ] = { data: data };
|
||||||
|
|
||||||
|
// If there is a previous frame, set the 'next' entry to its 'next'
|
||||||
|
// entry to maintain the circular reference. Otherwise, set to self.
|
||||||
|
set[ id ].next = ( prev )
|
||||||
|
? prev.next
|
||||||
|
: set[ id ];
|
||||||
|
|
||||||
|
// if there was a previous entry, set its 'next' entry to our new frame,
|
||||||
|
// expanding the linked list
|
||||||
|
prev && ( prev.next = set[ id ] )
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a tile with the mask applied
|
* Retrieve a tile with the mask applied
|
||||||
*
|
*
|
||||||
|
|
|
@ -97,15 +97,27 @@
|
||||||
// clear canvas to erase any previous LTG contents
|
// clear canvas to erase any previous LTG contents
|
||||||
ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height );
|
ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height );
|
||||||
|
|
||||||
var i = 0;
|
var i = j = 0;
|
||||||
for ( var tile in tiles )
|
for ( var tile in tiles )
|
||||||
{
|
{
|
||||||
var x = ( ( i % 10 ) * 50 ),
|
var cur, end;
|
||||||
y = ( Math.floor( i / 10 ) * 50 );
|
|
||||||
|
|
||||||
ctx.putImageData( tiles[ tile ], x, y );
|
// the default position is the last tile in the animation, so
|
||||||
|
// advance one before beginning output to keep consistent with the
|
||||||
|
// tile set
|
||||||
|
end = cur = tiles[ tile ].next;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
var x = ( ( j % 10 ) * 50 ),
|
||||||
|
y = ( Math.floor( j / 10 ) * 50 );
|
||||||
|
|
||||||
|
ctx.putImageData( cur.data, x, y );
|
||||||
ctx.fillText( tile, x, ( y + 43 ), 50 );
|
ctx.fillText( tile, x, ( y + 43 ), 50 );
|
||||||
|
|
||||||
|
j++;
|
||||||
|
} while ( ( cur = cur.next ) !== end )
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
Loading…
Reference in New Issue