Roofed areas and better map engine

Modified and new code

We'll also modify the handling of triggerable tiles in the Character processMovement method; we'll replace the code:

		if(typeof tileEvents[toIndex(this.tileTo[0], this.tileTo[1])]!='undefined')
		{
			tileEvents[toIndex(this.tileTo[0], this.tileTo[1])](this);
		}

...with this...

		if(mapTileData.map[toIndex(this.tileTo[0], this.tileTo[1])].eventEnter!=null)
		{
			mapTileData.map[toIndex(this.tileTo[0], this.tileTo[1])].eventEnter(this);
		}

We also need to update the other references to gameMap in this method. We'll get the tileFloor variable like this:

		var tileFloor = tileTypes[mapTileData.map[toIndex(this.tileFrom[0], this.tileFrom[1])].type].floor;

The moveSpeed variable like this:

	var moveSpeed = this.delayMove[tileTypes[mapTileData.map[toIndex(this.tileFrom[0],this.tileFrom[1])].type].floor];

...And in the Character.canMoveTo method we'll change the line:

	if(typeof this.delayMove[tileTypes[gameMap[toIndex(x,y)]].floor]=='undefined') { return false; }

...to this...

	if(typeof this.delayMove[tileTypes[mapTileData.map[toIndex(x,y)].type].floor]=='undefined') { return false; }

More onload

The window.onload event will also be used to handle the loading of our gameMap and roofList data into our mapTileData object. Just before the end of the function, we'll add the following code to load the data:

	mapTileData.buildMapFromData(gameMap, mapW, mapH);
	mapTileData.addRoofs(roofList);

Also, we can add the following to trigger a tile event and log some text to the console when the player enters tile 2, 2; this is just to show you how the events are handled with our updated engine:

	mapTileData.map[((2*mapW)+2)].eventEnter = function()
		{ console.log("Entered tile 2,2"); };

Updating the drawGame method

We only have a little bit more to do now. Firstly, in the drawGame method, after we update the viewport, we're going to add some code to calculate the Tile roof for the tileFrom and tileTo tile of the player Character:

	var playerRoof1 = mapTileData.map[toIndex(
		player.tileFrom[0], player.tileFrom[1])].roof;
	var playerRoof2 = mapTileData.map[toIndex(
		player.tileTo[0], player.tileTo[1])].roof;

Inside our nested tile drawing loops, we'll change the way we get the tileType reference variable, tile, to the following code:

			var tile = tileTypes[mapTileData.map[toIndex(x,y)].type];

After we've called the drawImage method for the current tile, we might need to draw a loop. Firstly, we'll check if the tile has a roof (and that the roofType is not 0; we'll never draw roofType = 0, and this is how we can create none rectangular roofs), and that the tiles roof is not one that the player is currently under or entering (from the reference variables we calculated before these loops):

			if(mapTileData.map[toIndex(x,y)].roofType!=0 &&
				mapTileData.map[toIndex(x,y)].roof!=playerRoof1 &&
				mapTileData.map[toIndex(x,y)].roof!=playerRoof2)
			{

If we're ok to draw this roof, we'll get the sprite as we do for the tile floor, but use the Tile.roofType property instead of its type property, and then draw as we would a floor tile. Once this is done, we can go ahead and close this if block.

				tile = tileTypes[mapTileData.map[toIndex(x,y)].roofType];
				sprite = getFrame(tile.sprite, tile.spriteDuration,
					gameTime, tile.animated);
				ctx.drawImage(tileset,
					sprite.x, sprite.y, sprite.w, sprite.h,
					viewport.offset[0] + (x*tileW),
					viewport.offset[1] + (y*tileH),
					tileW, tileH);
			}
Page loaded in 0.01 second(s).