Best way to create background map for 2D top down game
Shri

Gio,

 

Thanks for the quick info on my last question. I wil wait for the next release for the bug fix and then post the framework.

 

On another matter, I am creating an 2D top down game. It involves a ship sailing around on the water.

 

I was wondering what is the best way to go about creating the background water image.

I was going for something where the player could sail a good distance say world size 7000 px by 4000 px or even twice as  large.

 

Right now, I set the max screen size to 700 x 400.

Then I have a water' tile' image which is the same as the max screen size.

On game startup, I create a background image of the whole sea by tiling all the above mentioned water tiles onto one background scene object at the correct x and y offsets.

Everything works as advertised but I'm not sure what the best method for creating the background should be.

As I see it, my options are a couple

1) just set the sprite size of my single background image to be the world size I want - but then the resolution falls off and it looks blurry.

2) do the tiling method like I am now - attaching all the tiles to one background scene object

3) do the tiling method, but attach each tile to an individual scene object

4) other options ???

 

Basically, I'm curious what method is used by the iso plugin since that does what I'm looking for with a large world sizes

 

As a side question.Is there a way to stop the camera from moving past a certain world height / width. Right now, the camera follows the player ship around. It all works fine, until the player moves to the end of the world. The camera dutifully follows and half of the screen then contains only the html page background. When the player moves the other way, the camera follows and the screen is restored.

Do I have to check the camera position and then set the position manually if it crosses a min/max boundary ? Or is there another way to force a world boundary on the camera ?

 

Anyway, hope you had a good semi-vacanza.

 

As always, any help you can provide is appreciated.

 

cheers,

Shri

All 4 Comments
Gio

Hi Shri

 

I think tiles are the way to go, and you're right that's what the iso plug-in does pretty much (except that iso tiles are a weird shape).  In the iso terrain case, it's all one single scene object with lots of sprites. Performance-wise, it's a bit faster than having many scene objects, but it does depend on what you do with it. If you want to detect clicks and input events on the individual sprites, then it might be better to have one SceneObject for each Sprite (the iso plug-in handles input events in a different, more efficient way to determine which tile has been clicked).

 

One thing I want to do at some point, is writing a small TileMap behavior that can read maps generated with tools such as Tiled. It's on my to-do list and will happen at some point in the future.

 

Regarding your camera question: we did something like this just the other day while working on a WADE game. Basically we had one single big sprite for the map (2600x720 or something like that). We didn't use wade.setCameraTarget() which does what it's supposed to do, but has the problem you described. Instead, the map had a behavior with an onUpdate function where we moved the camera to the player's position, and every time we moved the camera we called this function to make sure it never went off the map:

this.limitCamera = function(){    var screenBox = {minX: -wade.getScreenWidth()/2, maxX: wade.getScreenWidth() / 2, minY: -wade.getScreenHeight() / 2, maxY: wade.getScreenHeight() / 2};    var screenInWorldSpace = wade.screenBoxToWorld(wade.app.layers.background, screenBox);    var mapBB = this.mapSprite.boundingBox;    var newCameraPosition = wade.getCameraPosition();    if (screenInWorldSpace.minX < mapBB.minX)    {        newCameraPosition.x += mapBB.minX - screenInWorldSpace.minX;    }    if (screenInWorldSpace.minY < mapBB.minY)    {        newCameraPosition.y += mapBB.minY - screenInWorldSpace.minY;    }    if (screenInWorldSpace.maxX > mapBB.maxX)    {        newCameraPosition.x += mapBB.maxX - screenInWorldSpace.maxX;    }    if (screenInWorldSpace.maxY > mapBB.maxY)    {        newCameraPosition.y += mapBB.maxY - screenInWorldSpace.maxY;    }    wade.setCameraPosition(newCameraPosition);};
Shri

Gio,

 

As always, the help is appreciated. How does anyone figure out this stuff on their own ?

 

I think I follow what you are doing in the code snippet above, except for one line ?

"var mapBB = this.mapSprite.boundingBox;"

What do you define as the bounding box of the background sprite ? and how would that translate if you were tiling sprites to make one large background ?

 

anyway, again thanks for the help

 

cheers,

Shri

Gio

That boundingBox is a property that all WADE Sprites have, and is automatically set and updated by WADE - you don't need to set it, unless you want to do it in some very special cases (if you're using some weird custom draw functions for example).

It's an object with 4 properties: minX, maxX, minY and maxY. They represent the minimum and maximum coordinates of the sprite in world space (top-left and bottom-right corners).

Each sprite has its own bounding box. The code above worked for us because we only had one single map sprite. If you have multiple sprites, you may want to create your own mapBB object, for which you can use the minX and minY from the bounding box of your top-left sprite, and the maxX and maxY of your bottom-right sprite.

I know it may not be easy to figure everything out on your own, that's what the forum and community are for :) So please keep asking any questions you may have, that'll help you and others reading these forums.
 

Shri

Gio,

 

Thanks for the clarification.

I got it to work as advertised, even with zooming !

I'll look at making some optimization and moving it to its own map object,

but I thought I would share a working copy now.

 

The comments should be self explanatory, but in a nutshell:

This routine lays down a number of tiles for a solid background.

In my case, I am developing a water game, so this draws the ocean.

It takes one map tile which is defined as the same size as the min/max screen width.

This tile is 700px x 400 px and is only 12 k in size, I have attached the file.

This is opposed to loading a very large image and losing resolution as you scale the game board size up.

The tile sprites are all attached to one scene object

The screen is defined to be 700 x 400 via wade.setMaxScreenSize(gameWidth, gameHeight);

I have tried it with a 2x2 board size (1400px x 800px) and a 20 x 20 board size (14000 px x 8000 px) and it seems to work fine.

Not sure how a very large game board effects the performance, but in this stage of the game's life everything works smoothly.

 

-- You could easily modify this to work with multiple tile types by loading them from an array and adding a different tile image based on the array value like you do with the iso plugin

 

-- If you have a menu area at say the bottom of the screen that you don't want your character to go over, then just change the relevant value in the mapBB object. For example, if you wanted to 'reserve' a 100 px space at the bottom of the screen for the

game gui, then the value of mapBB.maxy = gameHeight/2*maxY - 100.

 

A big shout out to Gio for being so helpful with this. Hopefully this can help some others out too.

 

cheers,

Shri

	/****************************************************	// load a background image onto the game screen	//	read the max number or rows and columns from the json level data	//	create the starting x and y pos for the first tile	//	inner for handles the rows	//		for each tile - position, image, layer	//	outer for handles the columns	// define the game worlds bounding box - mapBB	// ** x and y boundary used for stopping game characters, not 	//	  for anything to do with the background stuff	// onUpdate - set the camera position to the player, with current z	//			- get the cameras position	//			- limit the range of the camera based on bounding boxes 	//			- limiting routine courtesy of gio at clockwork chilli	//****************************************************/	this.createBackground = function() {		console.log('create background');		var xMax = currentLevelData.xMax;		var yMax = currentLevelData.yMax;		var xStart = -gameWidth/2*(xMax-1);		var yStart = -gameHeight/2*(yMax-1);		var back = new SceneObject(0,0,0,0);		for (var i=0; i<yMax; i++) {			for (j=0;j<xMax; j++) {				var sp = new Sprite('./images/waterTile.png',self.BACKGROUND_LAYER);				back.addSprite(sp,{x:xStart, y:yStart});				//console.log('water tile added at ' + xStart + '  ' + yStart);				xStart += gameWidth;			}			xStart = -gameWidth/2*(xMax-1);			yStart += gameHeight;		}				mapBB = {minX: -gameWidth/2*xMax, minY: -gameHeight/2*yMax,				 maxX: gameWidth/2*xMax, maxY: gameHeight/2*yMax};		xBoundary = gameWidth/2*xMax -100;		yBoundary = gameHeight/2*yMax - 100;		console.log(mapBB);				back.onUpdate = function() {			var pos = player.getPosition()			var cPos = wade.getCameraPosition();			wade.setCameraPosition({x:pos.x, y:pos.y, z: cPos.z});			var newCameraPosition = wade.getCameraPosition();						// the limiter routine			var screenBox = {minX: -wade.getScreenWidth()/2, maxX: wade.getScreenWidth() / 2, 							minY: -wade.getScreenHeight() / 2, maxY: wade.getScreenHeight() / 2};			var screenInWorldSpace = wade.screenBoxToWorld(wade.app.BACKGROUND_LAYER, screenBox);			if (screenInWorldSpace.minX < mapBB.minX) {				newCameraPosition.x += mapBB.minX - screenInWorldSpace.minX;			}			if (screenInWorldSpace.minY < mapBB.minY) {				newCameraPosition.y += mapBB.minY - screenInWorldSpace.minY;			}			if (screenInWorldSpace.maxX > mapBB.maxX) {				newCameraPosition.x += mapBB.maxX - screenInWorldSpace.maxX;			}			if (screenInWorldSpace.maxY > mapBB.maxY) {				newCameraPosition.y += mapBB.maxY - screenInWorldSpace.maxY;			}			wade.setCameraPosition(newCameraPosition);		}	// end back onUpdate				wade.addSceneObject(back,true);	};	// end createBackground
Post a reply
Add Attachment
Submit Reply
Login to Reply