I am trying to work out the best way of implementing a camera in my simple 2d game.

The way it is structured at the moment is my game objects all have draw functions, which are passed a canvas instance to draw themselves to (at whatever position they are currently at).

I now need to add a camera to the mix, so that i can have a bigger world, but i'm not sure of the best way to implement it.

The way I see it, I can either translate the whole canvas and let the objects carry on drawing themselves at whatever position they are at, eg:


This seems easy enough, but doesn't seem right somehow. Alternatively, I could pass the camera in to the objects with the canvas, and let the objects calculate a relative screen position before drawing, eg:

player.draw(canvas, camera);
// inside the draw function:    
var position = this.position.subtract(camera.position);
canvas.drawStuff(stuff, position);

But that seems wrong too. How do other 2d engines handle this? Is there an established best way of doing it, or any pitfalls I should avoid?


I don't know what you think is wrong with those two approaches - both seem fine to me.

The only thing you have to watch out for is that you don't draw your whole world offscreen. Drawing offscreen is relatively cheap in most canvas implementations, but iterating completely through your data structure which stores the world data likely isn't. So before you draw a frame you should first determine the subset of objects and tiles which are actually in the viewport and only draw these. This means that you have to design your data structures in a way that you can determine these efficiently (without checking every single one, every single frame).

For the tilemap, a two-dimensional array will do. When you draw a frame, first calculate the array indices of the outmost tiles in x and y direction and then iterate the arrays in two nested for-loops which only iterate between these coordinates.

For the objects, however, the issue becomes more complex because they can move between frames. There are several approaches to this issue.

One way to do it would be to build an auto-balancing 2d-tree data structure.

Another way would be to divide the game world into chunks of uniform size and make each chunk keep an own array of objects. Store the objects in a two-dimensional array just like the map tiles. When an object moves, check if it has passed a chunk border, and when it did, remove it from the old chunk and add it to the new one. When you draw a frame, only draw the objects on the object lists of the chunks which intersect the viewport.

  • \$\begingroup\$ Maybe i'm just over thinking it (as usual). Thanks for the tip though, I have a simple culling function on the camera already, but I know I need to investigate quad trees or similar at some point. \$\endgroup\$ – beeglebug Mar 5 '13 at 10:19
  • \$\begingroup\$ @beeglebug I edited my answer and added a lot of content after you posted your comment. \$\endgroup\$ – Philipp Mar 5 '13 at 10:32
  • 1
    \$\begingroup\$ I used the first approach and used the context translate method. You will definitely need to reset the canvas transformation each frame, for example, using ctx.setTransform(1,0,0,1,0,0) (identify). calls to translate() are cumulative. \$\endgroup\$ – MarkR Mar 5 '13 at 13:03
  • \$\begingroup\$ For culling, definitely do the simplest thing which works. It doesn't need to be perfect. \$\endgroup\$ – MarkR Mar 5 '13 at 13:05

I gave this answer as my proof of concept or method of creating a camera. You can also view it in it's repo

Long story short, you draw the World once with any static objects/sprites (e.g. walls), you then project it onto a viewport canvas as the player moves. All objects/sprites that move or animate are drawn onto the player canvas (a canvas that overlays the viewport canvas)

But yea, hope this helps as well. The answer is very detailed so I hope it's helpful.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.