Home Games Projects Blog Contact Private
Network

Archive for the ‘ds’ Category

My Rather Comprehensive NDS Homebrew Link List

Development Tools/Libs

Tutorials

Misc

Emulators

Cool Demos

Almost A Jump’n'Run

Building on the tilemap scrolling code I described in a previous post, I’ve almost created a jump’n'run game. It features a tilemap, two backgrounds and a sprite as a movable character.


You could almost call it a \"jump\'n\'run\"

You could almost call it a jump'n'run


What you see in the screenshot is the sprite (strange blue thingy), the tiles (green and brown), a background that moves (clouds at the top) and normally you’d also see another, not moving, greenish background, but that got somehow lost in Desmume’s emulation. The movement of the character is actually working as is the collision detection with the tilemap. Thus it’s possible to jump and move around without falling through the floor or running through obstacles.

The collision detection is rather basic. I just compute the sprite’s coordinates as tile indices and then check if it’s impossible to move into the tiles that whould be entered due to the current movement vector.

The map is loaded using the EFS library (forum thread at gbadev) which makes it very easy to read data that is actually appended to the .nds ROM. I first used libfat (blog post on using it on the DS and in an emulator), which is as easy as EFS, but has the disadvantage of not being able to provide a self-contained ROM file.

Take care if you want to use the EFS patcher v1.0 in Linux. It’s possible to compile the normal efs.c in Linux, but the library then doesn’t work on the DS hardware. There is a “EFS Patcher Universal (with OSX binary)” download on the library’s homepage which compiles in Linux and produces a working library for the DS hardware.

To create the map I’ve used Tiled which is a generic tilemap editor written in Java. I wrote a custom map exporter so that I could easily read the map on the DS.

I don’t post the code because it’s really ugly at the moment, but hey, it’s working! :)

Nintendo Sues Distributors Of R4

Gamasutra has two interesting pieces of news on Nintendo.

According to the first one, Nintendo is suing the distributors of the R4 Revolution cartridge in Japan which allows to run software on the DS that is not licensed by Nintendo. They say it’s because of piracy, but such cartridges are also vital to homebrew development.

The other one says that Nintendo has improved its profits to $992 million in the first quarter of 2008. So, piracy can’t be that, can it?

Update: I just want to stress that I don’t support, do or glorify piracy in any way. It’s just that the DS wouldn’t be what it is without homebrew.

Update 2: According to this blog post, many sites selling the R4 are already down because they’re afraid of legal threats from Nintendo.

Update 3: Gizmondo reports:

The rush in demand [of R4s] has been amazing. These devices always sell well. But this weekend should be staggering, don’t you think?

Changed “producers” to “distributors” as I was obviously mistaken there.

Scrolling Tilemaps On The Nintendo DS

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:

  1. Scrolling is at first handled by setting BG0_X0 and BG0_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.
  2. 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.
  3. Take care that the player cannot scroll too far so that he’d leave the map.

A screenshot:

Scrolling Tilemap

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.