Source: TileMap.js

/*global FM*/
/**
 * Represent a tile map for build tiled games.
 * No need to add the tilemap to the state, it's done when the tilemap is 
 * loaded.
 * By default a tilemap does not collide to anything.
 * @class FM.TileMap
 * @param {FM.ImageAsset} tileSet Image of the tile set in the order of 
 * the data given.
 * @param {int} pWidth The number of tiles constituing the width of the tile 
 * map.
 * @param {int} pHeight The number of tiles constituing the height of the tile
 * map.
 * @param {int} pTileWidth The width of a tile.
 * @param {int} pTileHeight The height of a tile.
 * @param {Array} pTypes The types to set the tiles of the tile map to.
 * @param {int} pZIndex The depth of the tiles of the tile map.
 * @param {boolean} pCollide Whether the tile map should collide or not.
 * @constructor
 * @author Simon Chauvin
 */
FM.TileMap = function (pTileSet, pWidth, pHeight, pTileWidth, pTileHeight, pTypes, pZIndex, pCollide) {
    "use strict";
    /**
     * Array containing the IDs of tiles.
     * @type Array
     * @private
     */
    this.data = [];
    /**
     * Image of the tile set.
     * @type Image
     * @private
     */
    this.tileSet = pTileSet;
    /**
     * Width of the map, in columns.
     * @type int
     * @private
     */
    this.width = pWidth;
    /**
     * Height of the map, in lines.
     * @type int
     * @private
     */
    this.height = pHeight;
    /**
     * Width of a tile.
     * @type int
     * @private
     */
    this.tileWidth = pTileWidth;
    /**
     * Height of a tile.
     * @type int
     * @private
     */
    this.tileHeight = pTileHeight;
    /**
     * Types the tile map is associated to.
     * @type Array
     * @private
     */
    this.types = pTypes;
    /**
     * Z-index of the tilemap.
     * @type int
     * @private
     */
    this.zIndex = pZIndex;
    /**
     * Allow collisions or not with this tile map.
     * @type boolean
     * @private
     */
    this.collide = pCollide;
};
FM.TileMap.prototype.constructor = FM.TileMap;
/**
 * Load the tilemap.
 * @method FM.TileMap#load
 * @memberOf FM.TileMap
 * @param {string} pData Comma and line return sparated string of numbers 
 * representing the position and type of tiles.
 */
FM.TileMap.prototype.load = function (pData) {
    "use strict";
    var rows = pData.split("\n"),
        row = null,
        resultRow = null,
        columns = null,
        gid = null,
        tile = null,
        state = FM.Game.getCurrentState(),
        renderer,
        xOffset,
        yOffset,
        image = this.tileSet.getImage(),
        i,
        j,
        n;
    for (i = 0; i < rows.length; i = i + 1) {
        row = rows[i];
        if (row) {
            resultRow = [];
            columns = row.split(",", this.width);
            for (j = 0; j < columns.length; j = j + 1) {
                gid = parseInt(columns[j]);
                if (gid > 0) {
                    tile = new FM.GameObject(this.zIndex);
                    for (n = 0; n < this.types.length; n = n + 1) {
                        tile.addType(this.types[n]);
                    }
                    tile.addComponent(new FM.SpatialComponent(j * this.tileWidth, i * this.tileHeight, tile));
                    renderer = tile.addComponent(new FM.SpriteRendererComponent(this.tileSet, this.tileWidth, this.tileHeight, tile));
                    //Select the right tile in the tile set
                    xOffset = gid * this.tileWidth;
                    yOffset = Math.floor(xOffset / image.width) * this.tileHeight;
                    if (xOffset >= image.width) {
                        yOffset = Math.floor(xOffset / image.width) * this.tileHeight;
                        xOffset = (xOffset % image.width);
                    }
                    renderer.offset.reset(xOffset, yOffset);
                    //Add tile to the state
                    state.add(tile);
                    //Add the game object's ID
                    resultRow.push(tile.getId());
                } else {
                    //No tile
                    resultRow.push(-1);
                }
            }
            //New line
            this.data.push(resultRow);
        }
    }
};
/**
 * Allow collisions for this tile map.
 * @method FM.TileMap#allowCollisions
 * @memberOf FM.TileMap
 */
FM.TileMap.prototype.allowCollisions = function () {
    "use strict";
    this.collide = true;
};
/**
 * Prevent collisions for this tile map.
 * @method FM.TileMap#preventCollisions
 * @memberOf FM.TileMap
 */
FM.TileMap.prototype.preventCollisions = function () {
    "use strict";
    this.collide = false;
};
/**
 * Check if this tile map can collide.
 * @method FM.TileMap#canCollide
 * @memberOf FM.TileMap
 * @return {boolean} Whether this tile map can collide or not.
 */
FM.TileMap.prototype.canCollide = function () {
    "use strict";
    return this.collide;
};
/**
 * Check if this tile map has a specified type.
 * @method FM.TileMap#hasType
 * @memberOf FM.TileMap
 * @return {boolean} Whether this tile map has the given type or not.
 */
FM.TileMap.prototype.hasType = function (pType) {
    "use strict";
    return this.types.indexOf(pType) !== -1;
};
/**
 * Retrive the 2D array of tile IDs.
 * @method FM.TileMap#getData
 * @memberOf FM.TileMap
 * @return {Array} The list of tile IDs of tile map.
 */
FM.TileMap.prototype.getData = function () {
    "use strict";
    return this.data;
};
/**
 * Retrive the tile set.
 * @method FM.TileMap#getTileSet
 * @memberOf FM.TileMap
 * @return {Image} The tile set.
 */
FM.TileMap.prototype.getTileSet = function () {
    "use strict";
    return this.tileSet;
};
/**
 * Retrieve the tile ID associated to a given position.
 * @method FM.TileMap#getTileId
 * @memberOf FM.TileMap
 * @param {int} pX The x position of the tile to retrieve.
 * @param {int} pY The y position of the tile to retrieve.
 * @return {int} The ID of the tile at the given position.
 */
FM.TileMap.prototype.getTileId = function (pX, pY) {
    "use strict";
    return this.data[Math.floor(pY / this.tileHeight)][Math.floor(pX / this.tileWidth)];
};
/**
 * Get the width of the map.
 * @method FM.TileMap#getWidth
 * @memberOf FM.TileMap
 * @return {int} The number of tiles constituing the width of the tile map.
 */
FM.TileMap.prototype.getWidth = function () {
    "use strict";
    return this.width;
};
/**
 * Get the height of the map.
 * @method FM.TileMap#getHeight
 * @memberOf FM.TileMap
 * @return {int} The number of tiles constituing the height of the tile map.
 */
FM.TileMap.prototype.getHeight = function () {
    "use strict";
    return this.height;
};
/**
 * Get the width of a tile.
 * @method FM.TileMap#getTileWidth
 * @memberOf FM.TileMap
 * @return {int} The width of a tile.
 */
FM.TileMap.prototype.getTileWidth = function () {
    "use strict";
    return this.tileWidth;
};
/**
 * Get the height of a tile.
 * @method FM.TileMap#getTileHeight
 * @memberOf FM.TileMap
 * @return {int} The height of a tile.
 */
FM.TileMap.prototype.getTileHeight = function () {
    "use strict";
    return this.tileHeight;
};
/**
 * Get the z-index of the map.
 * @method FM.TileMap#getZIndex
 * @memberOf FM.TileMap
 * @return {int} The depth of the tiles of the tile map.
 */
FM.TileMap.prototype.getZIndex = function () {
    "use strict";
    return this.zIndex;
};
/**
* Destroy the tile map and its objects.
* @method FM.TileMap#destroy
 * @memberOf FM.TileMap
*/
FM.TileMap.prototype.destroy = function () {
    "use strict";
    this.data = null;
    this.tileSet = null;
    this.width = null;
    this.height = null;
    this.tileWidth = null;
    this.tileHeight = null;
    this.types = null;
    this.zIndex = null;
    this.collide = null;
};