In an earlier post I talked about getting into Nintendo DS homebrew development. I’ve already read a lot and played with quite a few examples. There seem to be many basic tutorials on the topic, but unfortunately only a few tutorials pick up more advanced themes.
Anyway, there is a nice tutorial on handling tilemaps at Dev-Scene by Captain Apathy. This is again about the basics of tilemaps in the beginning, but in the end he talks about scrolling such maps with dynamically loading tile data from a bigger map as the biggest tilemap the NDS offers is 64 by 64 tiles. Unfortunately, he doesn’t give out any code showing that. So I took some time and tried to implement this kind of scrolling myself. I believe I’ve been successful, at least it seems to work.
The endeavor was not that easy because you have to keep track of quite a few coordinates in pixels as well as in tile indices. The algorithm now basically works likes this:
- Scrolling is at first handled by setting
BG0_X0andBG0_Y0, i. e. moving around the view in the tilemap the DS already knows about. This is possible because only 32×24 tiles are shown at once and a tilemap can contain up to 64×64 tiles. - If a certain threshold of scrolled pixels is reached, the movement’s direction is determined and a certain number of rows (vertical movement) or columns (horizontal movement) of tiles is loaded into the DS’ memory map overwriting “old” tiles that lie in the other direction. This may get little difficult because the write operation may wrap around, e. g. if it would write over the right edge, it has to stop there and continue at left edge.
- Take care that the player cannot scroll too far so that he’d leave the map.
A screenshot:

The code works in DeSmuME and on the actual DS. Download the complete source code including a Makefile here. It works with devkitPro and libnds.
Following are a few interesting spots of the code.
Setting a specific tile in a 64×64 map is not straight forward because on the DS a 64×64 map consists of four 32×32 maps that lie after another in memory:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | void setTile(u16* memoryMap, int x, int y, const u16 tileId) { int n; // Wrap around: if(x < 0) x += 2 * _TILE_W; if(y < 0) y += 2 * _TILE_H; x %= 2 * _TILE_W; y %= 2 * _TILE_H; // Handle the 4 32x32 maps if(x >= _TILE_W && y >= _TILE_H) { n = 3; x -= _TILE_W; y -= _TILE_H; } else if(x >= _TILE_W) { n = 1; x -= _TILE_W; } else if(y >= _TILE_H) { n = 2; y -= _TILE_H; } else { n = 0; } memoryMap[n * _TILE_W * _TILE_H + x + y*_TILE_W] = tileId; } |
The next snippet is the core of the tilemap scrolling. It detects if loading of new tiles is necessary and, if it actually is, does so.
1 2 | void updateView(u16* to) { |
At first, the position in the background (the tilemap) is set. We don’t have to care about wrapping around because the hardware takes care of that.
1 2 | BG0_X0 = position_x; BG0_Y0 = position_y; |
We then check if loading of new tiles is necessary. This is done by comparing the covered distance with a threshold.
1 2 3 | // Horizontal movement: if(abs(position_x - position_x_last) >= THRESHOLD_X) { |
Next, we have to check in which direction the player has moved.
1 | int direction = position_x < position_x_last ? -1 : 1; |
If he has moved to the right, a few rows of tiles have to be appended to the right of the currently loaded tiles. This means that some “old” tiles are overwritten.
1 2 3 4 5 | if(direction == 1 && map_position_x + STEP + TILES_X <= MAP_WIDTH) { copyTiles(map_position_x + TILES_X, map_position_y, STEP, TILES_Y, to, last_x_update_index + 1, last_y_update_index + 1); map_position_x += direction * STEP; } |
Moving to the left is similar. The current set of tiles is then prepended by new rows of tiles and thus overwriting “old” tiles on the right.
The code is analogous for vertical movement.
Quite a few things are missing to make this code run, but they can be found in the download mentioned above.