3.3. BASICS OF 2D MAPS - CAMERAS

Intro

In the last lessons we have seen little maps (the BoF2 Screenshot, the [lame ^_-] example maps), and we have used them for explaining the basic aspects of a map. But in a real game, a map is huge - you can only actually see a little portion of the map in your computer's monitor (or console screen ^_-). As an example, here it is the FF6 world map of the world of Balance:

 Breath of Fire II for SNES

Look at the brown rectangle at the left-side of the screen. This is the size of the map that you see in your screen when playing FF6. In fact, that brown rectangle is a "camera", because shows to you only a little part of the existent world. Is like when you take a camera and make a photo of the world - you cannot have all the world in your photo, just a little part of it.
But you can manage more than one "camera" - remember films like "Kill Bill" or "The Boston Strangler" [<= old but good, with Tony Curtis ^_-]. They used split screen (two cameras) for showing two actions that were happening at the same time. So you can have more than one camera, if your screen can show them at the same time.
So, the reason of this lesson is how to manage these "cameras" - how to capture a little part of the world and showing them to your player.

Map size, Camera size

How large can be a map? Depends on the memory you want to spend in storing the map.
A single tile is just a number, as seen in previous lessons. Imagine that the number is a Long Integer, or 4 Bytes (a byte [most times] is the smallest unit you can use in a program). A 128x128 single-layer tile map is 64KB. A usual personal computer (as a PC) has 256 MB (± 256000 KB). And a portable game console (as the GBA) has 128+256 KB.
So, in the PC world, you can use 64KB without problems. But if we want our game to work in a portable game console, or a mobile phone, 64KB is a nice bite on the system's memory.
Summarizing, you can make your maps as large as possible, but always have the memory constraints of your systems in mind. Finally, the best thing you can do is to allow maps of different sizes. This way, if you need to map a huge mega-complex, just make it huge. But if you have to map a little outpost, make a little map - this way, you will not waste space (or lack of it).

And how large can be a camera?. As little as you want, but not as bigger as you want. You can fit as many cameras as you like in the screen, but the maximum size of a camera (thus the maximum size of all combined cameras) depends of the size of your screen.
In a personal computer (PC) you can have several pixel resolutions, from 320x200 to 1024x768 and more, so you can have cameras of very different sizes. But in a portable game console (GBA) the screen size is more restricted (240x160).

Drawing a portion of the map in the camera (basic)

In this section we will show how to draw a portion on the map in a single camera, using tiles as coordinates. We'll use a 18x12 example map with 24x24 tiles, showing a (lame :-P) map of both Spanish (home! ^_^) and Portugal. And the camera will almost have the size of a GBA screen, 240x168. Therefore, the camera can only show 10x7 tiles.

 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 0 1 2 3 4 5 6 7 8 9 10 11

First, we need to know where IS the camera. When you are using a camera in the real world, the position of your camera can be expressed in three dimensional coordinates X,Y,Z (the same for 3D games ^_-). But these coordinates are related to an origin, where X=0, Y=0, Z=0 (we'll forget the fact about where the camera is focusing ^_-).
The same in a 2D map. Usually, in 2D maps, the upper-left corner of the map is the origin, where X=0 and Y=0. So, the position of our 2D camera (it upper-left corner) can be expressed in terms of that place. If your camera is in (0,0) [where (X coord,Y coord)], the upper-left corner of your camera is in the upper-left corner of the map. And if you camera is in (5,2)...

 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 0 1 2 ...This is where the camera is pointing to, so this is the portion of the map (10x7) that will be drawn in your screen ^_-. 3 4 5 6 7 8 9 10 11

About drawing in the screen, Just take all the tiles in the rectangle defined by your camera (see image above), and draw them in your screen (see below). Remember that you must drawn your tiles based on the screen coordinates - the tile (5,2) of the map will we located in the tile (0,0) of your screen - the (0,0) pixel coordinate.

 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6

Drawing a portion of the map in the camera (complex)

Ok, now we know how to draw a camera in a screen. But the coordinates of the camera are based on tiles... what happens if the coordinates of the camera are based on pixels? This is the usual case, when the entities in a map move pixel-by-pixel (remember previous lesson). But there is nothing to fear, because the solution is quite simple.

The origin of the map is still (0,0), the upper-left corner. But these coordinates are in pixels, not tiles anymore. Also the coordinates of the camera are expressed in pixels. An example: if the upper-left corner of the camera was before in (5,2), now it is in (120,48).
Now, imagine that the camera is located in (120,36). There is two rows (1 and 8) that must be drawn in the screen, but not completely. And when using tiles we can usually only draw the entire tile, not a part of it. What we can do?.
Easy - We draw all the tiles that are part of the camera, even those rows and columns that must not be completely drawn on the screen...

 5 6 7 8 9 10 11 12 13 14 1 2 3 4 5 6 7 8

..but when drawing on the screen, we don't start drawing the tiles on the coordinate (0,0) - we start to draw the tiles in the coordinate (0,-12).
This way, half a section of both row 1 (lower part) and row 8 (upper part) will be drawn on the screen. And you will have the section you want on your screen.

In a more formal way: When we have a camera located in a (XPixel,YPixel) coordinate [(120,36)], we must know to what tile that coordinate belongs, using a div (integer division) operation and the size of a tile [(120 mod 24,36 mod 24) = (5,1)]. Then, we check where is the lower-right part of the camera, and to what tile it belongs [(120+(240-1)) div 24,(36+(168-1)) div 24) = (14,8)].
After that, we draw the tiles that the camera "see" [from (5,1) to (14,8)], but moved (-XPixel mod TamTile,-YPixel mod TamTile) [(120 mod 24,36 mod 24) = (0,-12)] from the screen upper-left corner.

Multiple Cameras

Having multiple cameras in the screen is an easy task. The usual way is to draw every camera you have in a "Virtual Screen" (Surface, Virtual screen, ...the name depends on your graphics library), not in the real screen. Then just compose (draw) every camera in the real screen, in a position that does not overlap with the other cameras.
If the system cannot have "Virtual screens", then the cameras must be drawn directly on the screen. However, there is problems if the camera must draw parts of tiles ^_-.

 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 0 1 2 Camera 1 To be drawn in (0,0) of final screen 3 4 5 Camera 2 To be drawn in (120,0) of final screen 6 7 8 9 10 11

Contributors

Thanks to Final Fantasy Infinate and FF Online for the FF6 take of the "world of balance" overworld map.