Jump to content
  • Advertisement
Sign in to follow this  
Onigiri Flash

2D Platformer Camera

This topic is 1081 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm having a bit of trouble programming the camera view for a 2D platformer. Essentially, I want to scroll the camera in a tile-based level when the player moves in a particular direction. I'm storing the entire level in an array like so:

// Just an example

var level = [ 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
  1, 1, 1, 1, 0, 1, 1, 1, 1, 1
];

// 0 = empty, 1 = tile

I know how to scroll the camera by altering its (X,Y) coordinates within the overworld width and height, but how do I figure out which tiles to draw on the canvas (only the tiles within the camera's view, including partial tiles)?

Share this post


Link to post
Share on other sites
Advertisement

I know how to scroll the camera by altering its (X,Y) coordinates within the overworld width and height, but how do I figure out which tiles to draw on the canvas (only the tiles within the camera's view, including partial tiles)?


TBH, I don't think its worth it to try to "cull" the tiles

I'm not sure what framework / lib you are using, but I am assuming since this is a 2D game you are using a sprite batcher to draw stuff. Internally, I would think that the sprite batcher would cull off things that are not on the screen. Basically speaking in terms of the GPU, sprites added to a batch that are actually off screen wont make it past the fragment shader stage. Saving you some GPU time.

However, they are not being culled off on the CPU side of things. In order to cull them off on the CPU side of things, this would require some kind of check. Such as:

for(int i = 0; i < tiles.length; ++i)
{
   if(tile[i].Intersects(ScreenBox)
      tile[i].Draw(spriteBatch);
}

BUT the reason I say its not worth it is because this check still costs CPU time. So in the end you are probably going to end up spending more CPU time just doing the check, then just telling the sprite batcher to draw it and have the GPU deal with culling it. 

Share this post


Link to post
Share on other sites

Tile culling logic for this type of game is so trivial that there's no reason why you shouldn't do it. Not only will you avoid sending throwaway data to the rendering engine, but knowing which tiles are on-screen can allow for certain gameplay benefits and optimizations.

 

Just transform the upper-left screen coordinate and lower-right screen coordinate to tile-space (you can also go directly from view-space coordinates to save a transformation). Truncate to integers, and that's your upper-left and lower-right visible tile bounds.

Share this post


Link to post
Share on other sites

Thank you so much for responding, everyone! I forgot to mention that I'm using HTML5 canvas and Javascript for this game (no engine, just my own implementation). This is a drawing of what I wish to achieve (Mario as a reference):

 

example.png  super_mario_allstars_4.jpg

 

The red tiles represent partial tiles that become visible when the camera scrolls. The camera represents a bounding box within the level than contains the viewport.

 

So I would have to store an array of static bounding boxes for each tile and check for collision with the camera's bounding box. Combined with Istarnion's method, I think this will work well.

Share this post


Link to post
Share on other sites

Does your 2D camera or any of the tiles rotate? If not, your camera and all tiles are axis-aligned bounding boxes (AABBs). For a simple culling test, you could just loop through every tile in your level, and do a simple AABB intersection test. Looping through each tile in your scene can also be a bottleneck if you have a lot of tiles. A better solution would be to use a scene graph at that point. You'd pre-calculate them into a quadtree, or whatever scene graph you'd like. Then, loop through the scene graph's nodes recursively, and add all bottom-level nodes' tiles to the batch buffer for that frame.

Share this post


Link to post
Share on other sites

 

So I would have to store an array of static bounding boxes for each tile and check for collision with the camera's bounding box. Combined with Istarnion's method, I think this will work well.

No.
You only use what Istarnion mentioned.
Calculating the start and end indices already instantly gives you the correct horizontal and vertical ranges of tiles to draw.  Adding AABB tests on top of that is completely superfluous, not to mention poor in performance and costly in memory.  There is absolutely no reason to be discussing AABB’s here at all.
 
Assume tile sizes are 32×32.

unsigned int uiLeft = camPos.x / 32; 				// 32 = Tile Width.
unsigned int uiRight = (camPos.x + camPos.width - 1) / 32; 	// 32 = Tile Width.
unsigned int uiTop = camPos.y / 32; 				// 32 = Tile Height.
unsigned int uiBottom = (camPos.y + camPos.height - 1) / 32; 	// 32 = Tile Height.
for ( unsigned int Y = uiTop; Y <= uiBottom; ++Y ) {
	for ( unsigned int X = uiLeft; X <= uiRight; ++X ) {
		DrawTile( X, Y );
	}
}

 

Thank you very much for this! I understand how this works now.

 

 

 


It is trivial.

 

I'm sorry. happy.png I've never programmed a [platformer] tilemap before...

Edited by Onigiri Flash

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!