API Docs for: 1.4.0
Show:

File: src\gameobjects\tilemap\TileMapLayer.ts

/**
* 
* @module GameObjects
* @submodule Tilemap
* 
*/

module Kiwi.GameObjects.Tilemap {


	/**
	* GameObject containing the core functionality for every type of tilemap layer that can be generated. 
    * This class should not be directly used. Classes extending this should be used instead.
	* 
	* @class TileMapLayer
	* @extends Kiwi.Entity
	* @namespace Kiwi.GameObjects.Tilemap
    * @since 1.3.0
	* @constructor
	* @param tilemap {Kiwi.GameObjects.Tilemap.TileMap} The TileMap that this layer belongs to.
	* @param name {String} The name of this TileMapLayer.
	* @param atlas {Kiwi.Textures.TextureAtlas} The texture atlas that should be used when rendering this TileMapLayer onscreen.
	* @param data {Number[]} The information about the tiles.
	* @param tw {Number} The width of a single tile in pixels. Usually the same as the TileMap unless told otherwise.
	* @param th {Number} The height of a single tile in pixels. Usually the same as the TileMap unless told otherwise.
	* @param [x=0] {Number} The x coordinate of the tilemap in pixels.
	* @param [y=0] {Number} The y coordinate of the tilemap in pixels.
	* @param [w=0] {Number} The width of the whole tilemap in tiles. Usually the same as the TileMap unless told otherwise.
	* @param [h=0] {Number} The height of the whole tilemap in tiles. Usually the same as the TileMap unless told otherwise.
	* @return {TileMapLayer}
	*/
    export class TileMapLayer extends Kiwi.Entity {

		constructor(tilemap: Kiwi.GameObjects.Tilemap.TileMap, name: string, atlas: Kiwi.Textures.TextureAtlas, data: number[], tw: number, th: number, x: number= 0, y: number= 0, w:number=0, h:number=0) {
			super(tilemap.state, x, y);

			//Request the Shared Texture Atlas renderer.
			if (this.game.renderOption === Kiwi.RENDERER_WEBGL) {
				this.glRenderer = this.game.renderer.requestSharedRenderer("TextureAtlasRenderer");
            }

            if (Kiwi.Utils.Common.isString(atlas)) {
                atlas = this.state.textures[<any>atlas];
            }

			this.name = name;
			this.atlas = atlas;
			this.tilemap = tilemap;
			this._data = data;
			this.tileWidth = tw;
			this.tileHeight = th;
			this.width = w;
			this.height = h;

			this._corner1 = new Kiwi.Geom.Point(0,0);
			this._corner2 = new Kiwi.Geom.Point(0,0);
			this._corner3 = new Kiwi.Geom.Point(0,0);
			this._corner4 = new Kiwi.Geom.Point(0,0);

            this.physics = this.components.add(new Kiwi.Components.ArcadePhysics(this, null));
            this.physics.immovable = true;
        }

		/**
		* The physics component contained on the Tilemap. Use for basic collisions between People and Tiles.
		* Note: That tilemap layers a immovable and collisions with tiles are set on the individual TileTypes that are contained on the TileMap. 
		* @property physics
		* @type ArcadePhysics
		* @public
		*/
        public physics: Kiwi.Components.ArcadePhysics;

		/**
		* Returns the type of child that this is. 
		* @type Number
		* @return {Number} returns the type of child that the entity is
		* @public
		*/
		public childType(): number {
			return Kiwi.TILE_LAYER;
		}

		/**
		* The type of object that it is.
		* @method objType
		* @return {String} "TileMapLayer"
		* @public
		*/
		public objType() {
			return "TileMapLayer";
		}

		/**
		* The tilemap that this TileMapLayer is a part of.
		* @property tilemap
		* @type TileMap
		* @public
		*/
		public tilemap: Kiwi.GameObjects.Tilemap.TileMap;

		/**
		* Properties about that this TileMapLayer has when it was created from a JSON file.
		* @property properties
		* @type Object
		* @public
		*/
		public properties: any = {};

		/**
		* The width of this TileMap in tiles.
		* @property width
		* @type Number
		* @public
		*/
		public width: number;

		/**
		* The height of this TileMap in tiles.
		* @property height
		* @type Number
		* @public
		*/
		public height: number;

		/**
		* The width of a single tile.
		* @property tileWidth
		* @type Number
		* @public
		*/
		public tileWidth: number;

		/**
		* The height of a single tile.
		* @property tileHeight
		* @type Number
		* @public
		*/
		public tileHeight: number;

		/**
		* The texture atlas that should be used when rendering.
		* @property atlas
		* @type Kiwi.Textures.TextureAtlas
		* @public
		*/
		public atlas: Kiwi.Textures.TextureAtlas;

		/**
		* The width of the layer in pixels. This property is READ ONLY.
		* @property widthInPixels
		* @type number
		* @public
		*/
		public get widthInPixels(): number {
			return this.width * this.tilemap.tileWidth;
		}

		/**
		* The height of the layer in pixels. This property is READ ONLY.
		* @property heightInPixels
		* @type number
		* @public
		*/
		public get heightInPixels(): number {
			return this.height * this.tilemap.tileHeight;
		}

		/**
		* Override function to prevent unwanted inherited behaviour. Do not call.
		* Because TileMapLayer extends Entity, it has a cellIndex parameter. 
        * However, it does not use a single atlas index, so this parameter is meaningless. It has deliberately been set to do nothing.
		*
        * @property cellIndex
		* @type number
		* @public
		* @deprecated Not functional on this object.
		* @since 1.1.0
		*/
		public get cellIndex():number {
			return null;
		}
        public set cellIndex(val: number) { }

        /**
        * Scales the tilemap to the value passed.
        * @method scaleToWidth 
        * @param value {Number}
        * @public
        */
		public scaleToWidth(value: number) {
			this.scale = value / this.widthInPixels;
        }

        /**
        * Scales the tilemaps to the value passed.
        * @method scaleToHeight
        * @param value {Number}
        * @public
        */
		public scaleToHeight(value: number) {
			this.scale = value / this.heightInPixels;
        }

        /**
        * Centers the anchor point to the middle of the width/height of the tilemap.
        * @method centerAnchorPoint
        * @public
        */
		public centerAnchorPoint() {
			this.anchorPointX = this.widthInPixels * 0.5;
			this.anchorPointY = this.heightInPixels * 0.5;
		}

		/**
		* A list containing all the types of tiles found on this TileMapLayer.
		* @property _data
		* @type Array
		* @protected
		*/
        protected _data: number[];

        /**
        * READ ONLY: Returns the raw data for this tilemap.
        * @property data
        * @type Array
        * @readOnly
        * @public
        * @since 1.3.0
        */      
        public get data(): number[] {
            return this._data;
        }


		/**
		* READ ONLY: A list containing all of the types of tiles found on this TileMapLayer. 
        * Same as the `data` property.
        *
		* @property tileData
		* @type Array
        * @readOnly
		* @public
		*/
        public get tileData(): number[] {
            return this._data;
        }

		/**
		* Returns the total number of tiles. Either for a particular type if passed, otherwise of any type if not passed.
		* @method countTiles
		* @param [type] {Number} The type of tile you want to count.
		* @return {Number} The number of tiles on this layer.
		* @public
		*/
		public countTiles(type?:number):number {

			var cnt = 0;

			for (var i = 0; i < this._data.length; i++) {
				if (type == undefined && this._data[i] !== 0) cnt++;
				else if (type === this._data[i]) cnt++; 
			}

			return cnt;
		}

		/**
		* The orientation of the of tilemap. 
		* TileMaps can be either 'orthogonal' (normal) or 'isometric'.
		* @property orientation
		* @type String
		* @public
		*/
		public orientation: string = null;


		/**
		*-----------------------
		* Getting Tiles
		*-----------------------
		*/


		/**
		* Returns the index of the tile based on the x and y coordinates of the tile passed. 
		* If no tile is a the coordinates given then -1 is returned instead.
		* Coordinates are in tiles not pixels.
		* @method getIndexFromXY
		* @param x {Number} The x coordinate of the Tile you would like to retrieve. 
		* @param y {Number} The y coordinate of the Tile you would like to retrieve.
		* @return {Number} Either the index of the tile retrieved or -1 if none was found.
		* @public
		*/
		public getIndexFromXY(x: number, y: number): number {
			var num = x + y * this.width;

			//Does the index exist?
			if (num < 0 || num >= this._data.length) return -1;
			else return num;
		}

		/**
		* Returns the TileType for a tile that is at a particular set of coordinates passed. 
		* If no tile is found the null is returned instead.
		* Coordinates passed are in tiles.
		* @method getTileFromXY
		* @param x {Number}
		* @param y {Number}
		* @return {Kiwi.GameObjects.Tilemap.TileType}
		* @public
		*/
		public getTileFromXY(x: number, y: number): TileType {
			var t = this.getIndexFromXY(x, y);
			return (t !== -1) ? this.tilemap.tileTypes[ this._data[t] ] : null;
        }

		/**
		* Returns the indexes of every tile of a type you pass. 
		* @method getIndexsByType
		* @param type {Number}
		* @return {Number[]}
		* @public
		*/
        public getIndexesByType(type: number): number[] {
            var tiles = [];
            for (var i = 0; i < this._data.length; i++) {
                if (this._data[i] == type) tiles.push(i);
            }
            return tiles;
        }

        /**
        * Returns the TileType of a tile by an index passed.
        * Thanks to @rydairegames 
        * 
        * @method getTileFromIndex
        * @param index {Number}
        * @return {Kiwi.GameObjects.Tilemap.TileType} 
        * @public
        */
        public getTileFromIndex(index: number): TileType {
            return (index !== -1) ? this.tilemap.tileTypes[this._data[index]] : null;
        }

		/**
		* Returns the index of the tile based on the x and y pixel coordinates that are passed. 
		* If no tile is a the coordinates given then -1 is returned instead.
		* Coordinates are in pixels not tiles and use the world coordinates of the tilemap.
        *
        * Functionality needs to be added by classes extending this class.
		*
		* @method getIndexFromCoords
		* @param x {Number} The x coordinate of the Tile you would like to retrieve. 
		* @param y {Number} The y coordinate of the Tile you would like to retrieve.
		* @return {Number} Either the index of the tile retrieved or -1 if none was found.
		* @public
		*/
        public getIndexFromCoords(x: number, y: number): number {
            return -1;
        }
        
		/**
		* Returns the TileType for a tile that is at a particular coordinate passed. 
		* If no tile is found then null is returned instead.
		* Coordinates passed are in pixels and use the world coordinates of the tilemap.
        * 
		* @method getTileFromCoords
		* @param x {Number}
		* @param y {Number}
		* @return {Kiwi.GameObjects.Tilemap.TileType} 
		* @public
		*/
        public getTileFromCoords(x: number, y: number): TileType {

            var t = this.getIndexFromCoords(x, y);
            return (t !== -1) ? this.tilemap.tileTypes[this.data[t]] : null;

        }

		/**
		*-----------------------
		* Tiles Manipulation
		*-----------------------
		*/

		/**
		* Sets the tile to be used at the coordinates provided. 
		* Can be used to override a tile that may already exist at the location.
		* @method setTile
		* @param x {Number} The coordinate of the tile on the x axis. 
		* @param y {Number} The coordinate of the tile on the y axis.
		* @param tileType {Number} The type of tile that should be now used.
		* @return {Boolean} If a tile was changed or not.
		* @public
		*/
		public setTile(x: number, y: number, tileType:number):boolean {
			var x = this.getIndexFromXY(x, y);

			if (x !== -1) {
				this._data[x] = tileType;
				return true;
			} 

			return false;
		}

		/**
		* Sets the tile to be used at the index provided.
		* Can be used to override a tile that may already exist at the location.
		* @method setTileByIndex
		* @param index {Number} The index of the tile that you want to change.
		* @param tileType {Number} The new tile type to be used at that position.
		* @public
		*/
		public setTileByIndex(index: number, tileType: number) {
			this._data[index] = tileType;
		}

		/**
		* Randomizes the types of tiles used in an area of the layer. You can choose which types of tiles to use, and the area.
		* Default tile types used are everyone avaiable. 
		* @method randomizeTiles
		* @param [types] {Number[]} A list of TileTypes that can be used. Default is every tiletype on the TileMap.
		* @param [x=0] {Number} The starting tile on the x axis to fill. 
		* @param [y=0] {Number} The starting tile on the y axis to fill.
		* @param [width=this.width] {Number} How far across you want to go.
		* @param [height=this.height] {Number} How far down you want to go.
		* @public
		*/
		public randomizeTiles(types?: number[], x: number= 0, y: number= 0, width: number= this.width, height: number= this.height) {

			if (types == undefined) {
				types = [];
				var i = 0;
				while (i++ < this.tilemap.tileTypes.length) {
					types.push(i);
				}
			}

			for (var j = y; j < y + height; j++) {
				for (var i = x; i < x + width; i++) {

					var tile = this.getIndexFromXY(i, j);
					if (tile !== -1) this._data[tile] = this.game.rnd.pick(types);

				}
			}

		}

		/**
		* Makes all of the tiles in the area specified a single type that is passed.
		* @method fill
		* @param type {Number} The type of tile you want to fill in the area with.
		* @param [x=0] {Number} The starting tile on the x axis to fill. 
		* @param [y=0] {Number} The starting tile on the y axis to fill.
		* @param [width=this.width] {Number} How far across you want to go.
		* @param [height=this.height] {Number} How far down you want to go.
		* @public
		*/
		public fill(type: number, x: number= 0, y: number= 0, width: number= this.width, height: number= this.height) {

			for (var j = y; j < y + height; j++) {
				for (var i = x; i < x + width; i++) {

					var tile = this.getIndexFromXY(i, j);
					if (tile !== -1) this._data[tile ] = type;

				}
			}

		}

		/**
		* Replaces all tiles of typeA to typeB in the area specified. If no area is specified then it is on the whole layer.
		* @method replaceTiles
		* @param typeA {Number} The type of tile you want to be replaced.
		* @param typeB {Number} The type of tile you want to be used instead.
		* @param [x=0] {Number} The starting tile on the x axis to fill. 
		* @param [y=0] {Number} The starting tile on the y axis to fill.
		* @param [width=this.width] {Number} How far across you want to go.
		* @param [height=this.height] {Number} How far down you want to go.
		* @public
		*/
		public replaceTiles(typeA: number, typeB: number, x:number=0, y:number=0, width:number=this.width,height:number=this.height) {

			for (var j = y; j < y + height; j++) {
				for (var i = x; i < x + width; i++) {

					var tile = this.getIndexFromXY(i, j);
					if (tile !== -1 && this._data[tile] == typeA) this._data[tile] = typeB; 

				}
			}

		}

		/**
		* Swaps all the tiles that are typeA -> typeB and typeB -> typeA inside the area specified. If no area is specified then it is on the whole layer.
		* @method swapTiles
		* @param typeA {number} The type of tile you want to be replaced with typeB.
		* @param typeB {number} The type of tile you want to be replaced with typeA.
		* @param [x=0] {number} The starting tile on the x axis to fill. 
		* @param [y=0] {number} The starting tile on the y axis to fill.
		* @param [width=this.width] {number} How far across you want to go.
		* @param [height=this.height] {number} How far down you want to go.
		* @public
		*/
		public swapTiles(typeA: number, typeB: number, x: number= 0, y: number= 0, width: number= this.width, height: number= this.height) {

			for (var j = y; j < y + height; j++) {
				for (var i = x; i < x + width; i++) {
					var tile = this.getIndexFromXY(i, j);

					if (tile !== -1) {
						if (this._data[tile] == typeA) this._data[tile] = typeB;
						else if (this._data[tile] == typeB) this._data[tile] = typeA;
					} 
				}
			}

		}

		/**
		*-----------------------
		* Get Tiles By Collision Methods
		*-----------------------
		*/

		/**
		* Returns the tiles which overlap with a provided entities hitbox component. 
		* Only collidable tiles on ANY side will be returned unless you pass a particular side.
		* Note: Classes extending this class need to 
		* 
		* @method getOverlappingTiles
		* @param entity {Kiwi.Entity} The entity you would like to check for the overlap.
		* @param [collisionType=ANY] {Number} The particular type of collidable tiles which you would like to check for.
		* @return {Object[]} Returns an Array of Objects containing information about the tiles which were found. Index/X/Y information is contained within each Object. 
		* @public
		*/
		public getOverlappingTiles(entity: Kiwi.Entity, collisionType: number= Kiwi.Components.ArcadePhysics.ANY): any {
			return [];
		}


		/**
		* Returns the tiles which can collide with other objects (on ANY side unless otherwise specified) within an area provided.
		* By default the area is the whole tilemap.
		* 
		* @method getCollidableTiles
		* @param [x=0] {Number} The x coordinate of the first tile to check.
		* @param [y=0] {Number} The y coordinate of the first tile to check.
		* @param [width=widthOfMap] {Number} The width from the x coordinate.
		* @param [height=heightOfmap] {Number} The height from the y coordinate.
		* @param [collisionType=ANY] {Number} The type of collidable tiles that should be return. By default ANY type of collidable tiles will be returned. 
		* @return {Object[]} Returns an Array of Objects containing information about the tiles which were found. Index/X/Y information is contained within each Object. 
		* @public
		*/
		public getCollidableTiles(x: number= 0, y: number= 0, width: number= this.width, height: number = this.height, collisionType: number= Kiwi.Components.ArcadePhysics.ANY): any {

			var tiles = [];

			//Make sure its within the map.
			if (x > this.width || y > this.height) return; 

			if (x < 0) x = 0;
			if (y < 0) y = 0;

			if (x + width > this.width) width = this.width - x;
			if (y + height > this.height) height = this.height - y;

			//Loop through and of the tiles.
			for (var j = y; j < y + height; j++) {
				for (var i = x; i < x + width; i++) {

					//Get the tile index.
					var index = this.getIndexFromXY(i, j);

					//Does that index exist? Should do but just in case.
					if (index === -1) continue;

					var type = this.tileData[index];

					//If the collision type matches the one passed. 
					if ((this.tilemap.tileTypes[type].allowCollisions & collisionType) !== Kiwi.Components.ArcadePhysics.NONE) {

						tiles.push({
							index: index,
							type: type,
							x: i * this.tileWidth,
							y: j * this.tileHeight
						});


					}

				}
			}

			return tiles;
		}


		/**
		* The update loop that is executed when this TileMapLayer is add to the Stage.
		* @method update
		* @public 
		*/
		public update() {
			super.update();
		}

		/**
		*-----------------------
		* Temp Properties used During Rendering
		*-----------------------
		*/

		/**
		* Used whilst rendering to calculate the number of tiles to be rendered on the X axis.
		* Is updated each frame, via the _calculateBoundaries method.
		* @property _maxX
		* @type number
		* @protected
		*/
        protected _maxX: number;

		/**
		* Used whilst rendering to calculate the number of tiles to be rendered on the Y axis.
		* Is updated each frame, via the _calculateBoundaries method.
		* @property _maxY
		* @type number
		* @protected
		*/
        protected _maxY: number;

		/**
		* Used whilst rendering to calculate which is the first tile to be rendered on the X axis.
		* Is updated each frame, via the _calculateBoundaries method.
		* @property _startX
		* @type number
		* @protected
		*/
        protected _startX: number;

		/**
		* Used whilst rendering to calculate which is the first tile to be rendered on the Y axis.
		* Is updated each frame, via the _calculateBoundaries method.
		* @property _startY
		* @type number
		* @protected
		*/
        protected _startY: number;

		/**
		* Temporary property that holds the tileType of the current tile being rendered.
		* @property _temptype
		* @type TileType
		* @protected
		*/
        protected _temptype: TileType;

		/**
		* Corner values used internally.
		* @property corner1
		* @type {Kiwi.Geom.Point}
		* @protected
		* @since 1.1.0
		*/
        protected _corner1: Kiwi.Geom.Point;
		/**
		* Corner values used internally.
		* @property corner2
		* @type {Kiwi.Geom.Point}
		* @protected
		* @since 1.1.0
		*/
        protected _corner2: Kiwi.Geom.Point;

		/**
		* Corner values used internally.
		* @property corner3
		* @type {Kiwi.Geom.Point}
		* @protected
		* @since 1.1.0
		*/
        protected _corner3: Kiwi.Geom.Point;

		/**
		* Corner values used internally.
		* @property corner4
		* @type {Kiwi.Geom.Point}
		* @protected
		* @since 1.1.0
		*/
        protected _corner4: Kiwi.Geom.Point;

		/**
		* Used to calculate the position of the tilemap on the stage as well as how many tiles can fit on the screen. 
		* All coordinates calculated are stored as temporary properties (maxX/Y, startX/Y).
		*
		* @method _calculateBoundaries
		* @param camera {Camera}
		* @param matrix {Matrix} 
		* @protected
		*/
		protected _calculateBoundaries(camera: Kiwi.Camera, matrix: Kiwi.Geom.Matrix) {

			this._startX = 0;
			this._startY = 0;
			this._maxX = this.width;
			this._maxY = this.height;

		}

		/** 
		* The render loop which is used when using the Canvas renderer.
		* @method render
		* @param camera {Camera}
		* @public
		*/
		public render(camera: Kiwi.Camera) {

		}

		public renderGL(gl: WebGLRenderingContext, camera: Kiwi.Camera, params: any = null) {

        }


		/** 
        * Deprecated on the TileMapLayer class since it is for 'Isometric' maps only.
		*
		* @method chartToScreen
		* @param chartPt {any} A Object containing x/y properties of the tile.
		* @param [tileW] {Number} The width of the tile
		* @param [tileH] {Number} The height of the tile
		* @return {Object} With x/y properties of the location of the map onscreen.
        * @deprecated
        * @since 1.3.0
		* @public
		*/
        public chartToScreen(chartPt: any, tileW: number = this.tileWidth / 2, tileH: number = this.tileHeight): any {
            return {
                x: chartPt.x * tileW - chartPt.y * tileW,
                y: chartPt.x * tileH / 2 + chartPt.y * tileH / 2
            };
        }

		/**
        * Deprecated on the TileMapLayer class since it is for 'Isometric' maps only.
		*
		* @method screenToChart
		* @param scrPt {any} An object containing x/y coordinates of the point on the screen you want to convert to tile coordinates.
		* @param [tileW] {Number} The width of a single tile.
		* @param [tileH] {Number} The height of a single tile.
		* @return {Object} With x/y properties of the location of tile on the screen.
        * @deprecated
        * @since 1.3.0
		* @public
		*/
        public screenToChart(scrPt: any, tileW: number = this.tileWidth / 2, tileH: number = this.tileHeight): any {
            var column = Math.floor(scrPt.x / tileW);
            var row = Math.floor((scrPt.y - column * (tileH / 2)) / tileH);
            return { x: column + row, y: row };
        } 


	}
}