From 2c018a94b5870fd56b61fbdde58aed71c381fe33 Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Tue, 27 Mar 2012 21:34:33 -0400 Subject: [PATCH] Began refactoring game logic into ClassicGame --- index.html | 2 + lib/ClassicGame.js | 191 +++++++++++++++++++++++++++++++++++++++++++++ lib/Game.js | 73 +++++++++++++++++ scripts/game.js | 42 ++++------ 4 files changed, 282 insertions(+), 26 deletions(-) create mode 100644 lib/ClassicGame.js create mode 100644 lib/Game.js diff --git a/index.html b/index.html index 491d539..3a596ca 100644 --- a/index.html +++ b/index.html @@ -131,6 +131,8 @@ + + diff --git a/lib/ClassicGame.js b/lib/ClassicGame.js new file mode 100644 index 0000000..6e14a86 --- /dev/null +++ b/lib/ClassicGame.js @@ -0,0 +1,191 @@ +/** + * Interface representing a facade for a game type + * + * Copyright (C) 2012 Mike Gerwitz + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + + +/** + * Facade for the classic (original) game of LaserTank + */ +ltjs.ClassicGame = Class( 'ClassicGame' ) + .implement( ltjs.Game ) + .extend( +{ + /** + * LTG loader + * @type {ltjs.LtgLoader} + */ + 'private _ltgLoader': null, + + /** + * Tile masker + * @type {ltjs.TileMasker} + */ + 'private _masker': null, + + /** + * Tiles + * @type {Object.} + */ + 'private _tileSet': null, + + /** + * Set of available maps + * @type {ltjs.MapSet} + */ + 'private _mapSet': null, + + /** + * Event handlers + * @type {Object.} + */ + 'private _callback': {}, + + /** + * Performs map rendering + * @type {ltjs.MapRender} + */ + 'private _render': null, + + + /** + * Initialize game with LTG and LVL data + * + * The LTG and LVL data can be changed at any time, but are required in the + * constructor because they are needed in order for the game to be + * functional. + * + * @param {string} ltg_data binary string containing LTG file data + * @param {string} lvl_data binary string containing LVL file data + */ + __construct: function( ltg_data, lvl_data ) + { + var _self = this; + + this._ltgLoader = ltjs.LtgLoader(); + this._masker = ltjs.TileMasker( ltjs.ClassicTileDfn() ); + + // load initial tile and map data from the LTG and LVL data + this.setTileData( ltg_data, function() + { + this.setMapData( lvl_data, function() + { + _self._trigger( 'ready' ); + } ); + } ); + }, + + + /** + * Render to the given 2d canvas context + * + * @param {CanvasRenderingContext2d} ctx 2d canvas context + * + * @return {ClassicGame} self + */ + 'public renderTo': function( ctx ) + { + // if there is a previous renderer, free its canvas before continuing + // (to both clean up and to free any locks, allowing for tile set and + // map changes) + if ( this._render ) + { + this._render.clearCanvas(); + } + + // render the first map (hardcoded for now) + this._render = ltjs.MapRender( ctx, this._tileSet ) + .render( this._mapSet.getMapByNumber( 1 ) ); + + return this; + }, + + + /** + * Set LTG data for tiles + * + * @param {string} data binary string containing LTG data + * @param {function()} callback function to call when complete + * + * @return {ClassicGame} self + */ + 'public setTileData': function( data, callback ) + { + // get tile metadata + var _self = this, + meta = this._ltgLoader.fromString( data ); + + this._masker.getMaskedTiles( meta.tiles, meta.mask, function( tdata ) + { + _self._tileSet = tdata; + callback.call( _self.__inst ); + } ); + + return this; + }, + + + /** + * Set LVL data for maps + * + * @param {string} data binary string containing LVL data + * @param {function()} callback function to call when complete + * + * @return {ClassicGame} self + */ + 'public setMapData': function( data, callback ) + { + this._mapSet = ltjs.MapSet( data, ltjs.ClassicMap ); + + callback.call( this.__inst ); + return this; + }, + + + /** + * Attach event handler + * + * This is a very basic system and allows for only a single event to be + * attached at a time (that is all that is needed at this point) + * + * @param {string} name event name + * @param {Function} callback event callback + * + * @return {ClassicGame} self + */ + 'public on': function( name, callback ) + { + this._callback[ name ] = callback; + return this; + }, + + + /** + * Trigger an event, invoking its callback + * + * @param {string} name event name + * + * @return {ClassicGame} self + */ + 'private _trigger': function( name ) + { + if ( typeof this._callback[ name ] === 'function' ) + { + this._callback[ name ].call( this.__inst ); + } + } +} ); diff --git a/lib/Game.js b/lib/Game.js new file mode 100644 index 0000000..bcd377f --- /dev/null +++ b/lib/Game.js @@ -0,0 +1,73 @@ +/** + * Interface representing a facade for a game type + * + * Copyright (C) 2012 Mike Gerwitz + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + + +/** + * Represents a game type + * + * The facade should perform all necessary loading for support of a specific + * type of game play. All DOM elements should be injected. + */ +ltjs.Game = Interface( 'Game', +{ + /** + * Render to the given 2d canvas context + * + * @param {CanvasRenderingContext2d} ctx 2d canvas context + * + * @return {Game} self + */ + 'public renderTo': [ 'ctx' ], + + + /** + * Set LTG data for tiles + * + * @param {string} data binary string containing LTG data + * @param {function()} callback function to call when complete + * + * @return {Game} self + */ + 'public setTileData': [ 'data', 'callback' ], + + + /** + * Set LVL data for maps + * + * @param {string} data binary string containing LVL data + * @param {function()} callback function to call when complete + * + * @return {Game} self + */ + 'public setMapData': [ 'data', 'callback' ], + + + /** + * Attach event handler + * + * This is a very basic system and allows for only a single event to be + * attached at a time (that is all that is needed at this point) + * + * @param {string} name event name + * @param {Function} callback event callback + * + * @return {Game} self + */ + 'public on': [ 'name', 'callback' ] +} ); diff --git a/scripts/game.js b/scripts/game.js index 2587d26..f3810e3 100644 --- a/scripts/game.js +++ b/scripts/game.js @@ -25,57 +25,47 @@ var load_ltg = ltjs.FileLoader( document.getElementById( 'ltg' ) ), menu_bar = ltjs.ui.MenuBar( document.getElementById( 'menubar' ) ), - game = document.getElementById( 'game' ), - ctx = document.getElementById( 'render' ).getContext( '2d' ), + ele_game = document.getElementById( 'game' ), + ctx = document.getElementById( 'render' ).getContext( '2d' ), + + ltg_data = '', + lvl_data = ''; - ltg_loader = ltjs.LtgLoader(), - masker = ltjs.TileMasker( ltjs.ClassicTileDfn() ), - tile_set = null, - map_set = null, - render = null; load_ltg.onLoad( function( e, data ) { if ( e ) throw e; - // get tile metadata - var meta = ltg_loader.fromString( data ); - - masker.getMaskedTiles( meta.tiles, meta.mask, function( tdata ) - { - tile_set = tdata; - gamechk(); - } ); + ltg_data = data; + gamechk(); } ); load_lvl.onLoad( function( e, data ) { if ( e ) throw e; - map_set = ltjs.MapSet( data, ltjs.ClassicMap ); - + lvl_data = data; gamechk(); } ); function gamechk() { - if ( !( tile_set && map_set ) ) return; + if ( !( ltg_data && lvl_data ) ) return; // temporary - if ( game.className.search( 'opening' ) > -1 ) return; + if ( ele_game.className.search( 'opening' ) > -1 ) return; - // clear any existing locks before rendering (allowing the user to change - // tile sets and map sets) - render && render.freeCanvas(); - - render = ltjs.MapRender( ctx, tile_set ); - render.render( map_set.getMapByNumber( 1 ) ); + ltjs.ClassicGame( ltg_data, lvl_data ) + .on( 'ready', function() + { + this.renderTo( ctx ); + } ); } // temporary document.getElementById( 'new' ).onclick = function() { - game.className = game.className.replace( ' opening', '' ); + ele_game.className = ele_game.className.replace( ' opening', '' ); gamechk(); };