Wednesday, January 23, 2008

What's Next?

Some have asked for the source, so I will clean it up and some how get a link on this blog for you to grab it, or just email it to those that have asked. I'll will try to get it up before Friday.

Before, I do the object placing in the world, scrolling, and removing/restoring object when visible, I will work on determining where I am in my defined tile map world. I will move a sprite around in my world, and find out the tile entry it is on. By knowing this, I can then define tiles in my world that are, passable, setting boundaries in my tile maps, and thus the beginnings of a simple tile level editor.

I will once again set a time frame for myself for figuring this out. For the scrolling, I gave myself 3 weeks and got it done in 2 weeks (actual time worked on it was approx. 40 hours).

Till next time...

Tuesday, January 22, 2008

Find It Here

Just adding some keywords for search engines to help those looking for a Nintendo DS Tile Scroll Algorithm, with smooth scrolling.

I think that covers it. :)

Monday, January 21, 2008

"Keep Scrollin', scrollin', scrollin'..."

"Now I know ya'll be lovin' this right here...R.O.D. is right here. People in the house with there laptops in the air..."

Okay...whew...I was gettin' jiggy...oh, they don't say that anymore...showing my age. :)

Anyway, the tile, scroll engine is done. Well, not the engine, but the code that does all the tile, world scrolling is "oppperrratttiooonaaal." I'll clean it up and make it into a generic engine. Anyway, I know some of you are itching to see how to scroll. As, I mentioned previously I'll will post here some hand drawings to explain my scheme, and also will post the code. So, here it is...






Sheesh...the images loaded in look like crap but, if you can see the one above A shows the image of the background map divided into 4 regions I've been explaining in my previous posts. B, shows the 32x32 maps that will be loaded into those regions. I guess, I'll just get to the code, and have to figure out another way to get the diagrams up and in.

What I did to test my scheme was to make some 8x8 tiles filled with different colors. I then created test maps from those tiles, thus I have 32x32 tile maps of solid colors. This way when I scroll I can see if my test maps are loading and scrolling properly. So, my world that I'm scrolling over looks like a colorful patch quilt, but it is a good way to test.

Here's that code...

// black tile
const int nColor_Black = 0;
u8 blackTile[64]=
{
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};

// red tile
const int nColor_Red = 1;
u8 redTile[64]=
{
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1
};

// green tile
const int nColor_Green = 2;
u8 greenTile[64]=
{
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2
};

// blue tile
const int nColor_Blue = 3;
u8 blueTile[64]=
{
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3
};

// yellow tile
const int nColor_Yellow = 4;
u8 yellowTile[64]=
{
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4
};

// white tile
const int nColor_White = 5;
u8 whiteTile[64]=
{
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5
};

The above are the tiles I created for testing, but in a game one of these tiles would represent some, small graphic element.

Here are the maps...

// file map1 with black tiles
u16 nWorldMap1[] =
{
0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 4
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 5
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 6
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 7
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 8
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 9
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 10
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 11
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 12
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 13
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 14
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 15
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 16
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 17
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 18
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 19
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 21
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 22
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 23
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 24
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 25
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 26
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 27
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 28
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 29
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 30
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 31
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 32
};

// black maps
u16 *nWorldMap7, *nWorldMap13, *nWorldMap19;
nWorldMap7 = nWorldMap13 = nWorldMap19 = nWorldMap1;

// file with red tiles
u16 nWorldMap2[] =
{
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 2
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 3
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 4
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 5
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 6
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 7
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 8
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 9
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 10
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 11
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 12
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 13
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 14
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 15
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 16
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 17
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 18
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 19
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 20
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 21
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 22
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 23
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 24
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 25
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 26
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 27
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 28
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 29
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 30
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 31
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 32
};

u16 *nWorldMap8, *nWorldMap14, *nWorldMap20;
nWorldMap8 = nWorldMap14 = nWorldMap20 = nWorldMap2;

// fill map with green tiles
u16 nWorldMap3[] =
{
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 1
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 2
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 3
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 4
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 5
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 6
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 7
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 8
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 9
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 10
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 11
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 12
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 13
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 14
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 15
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 16
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 17
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 18
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 19
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 20
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 21
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 22
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 23
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 24
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 25
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 26
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 27
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 28
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 29
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 30
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 31
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 32
};

u16 *nWorldMap9, *nWorldMap15;
nWorldMap9= nWorldMap15 = nWorldMap3;

u16 nWorldMap4[] =
{
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 1
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 2
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 3
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 4
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 5
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 6
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 7
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 8
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 9
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 10
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 11
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 12
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 13
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 14
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 15
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 16
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 17
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 18
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 19
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 20
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 21
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 22
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 23
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 24
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 25
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 26
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 27
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 28
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 29
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 30
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 31
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 32
};

u16 *nWorldMap10, *nWorldMap16;
nWorldMap10 = nWorldMap16 = nWorldMap4;

// fill map with yellow tiles
u16 nWorldMap5[] =
{
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 1
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 2
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 3
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 4
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 5
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 6
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 7
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 8
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 9
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 10
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 11
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 12
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 13
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 14
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 15
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 16
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 17
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 18
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 19
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 20
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 21
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 22
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 23
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 24
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 25
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 26
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 27
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 28
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 29
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 30
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 31
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 32
};

u16 *nWorldMap11, *nWorldMap17;
nWorldMap11 = nWorldMap17 = nWorldMap5;

// fill map with white tiles
u16 nWorldMap6[] =
{
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 1
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 2
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 3
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 4
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 5
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 6
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 7
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 8
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 9
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 10
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 11
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 12
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 13
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 14
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 15
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 16
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 17
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 18
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 19
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 20
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 21
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 22
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 23
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 24
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 25
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 26
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 27
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 28
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 29
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 30
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 31
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, // 32
};

u16 *nWorldMap12, *nWorldMap18;
nWorldMap12 = nWorldMap18 = nWorldMap6;

You see the maps are 32x32 entries with the tile images in them, remember I'm doing solid patterns so that testing the tile scrolling is easily visible. Again, in a real game the different entries in the map would make up different tiles that could also be rotated or flipped, to make up a picture, landscape, etc... Note, that after I made one map of a solid color, I created pointers to other maps and assigned a map to them. This way, I saved time and memory not making duplicate maps filled with the same colors.

Next, is the setup code to set the background mode, tiles, palette,etc...

int main(void)
{
// enable interrupts
irqInit();
irqEnable(IRQ_VBLANK);

// set video mode and map vram to the background
videoSetMode(MODE_0_2D | DISPLAY_BG0_ACTIVE |
DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); // display sprite active, in tile, and bitmap mode

//enable vram and map it to the right places
vramSetMainBanks(VRAM_A_MAIN_SPRITE, //A and B maped consecutivly as sprite memory
VRAM_B_MAIN_SPRITE, //this gives us 256KB which is the max
VRAM_C_MAIN_BG_0x06000000, //map C to background memory
VRAM_D_LCD); //not using D


// set the map regions
u16* mapRegion0 = (u16*)BG_MAP_RAM(0);
u16* mapRegion1 = (u16*)BG_MAP_RAM(1);
u16* mapRegion2 = (u16*)BG_MAP_RAM(2);
u16* mapRegion3 = (u16*)BG_MAP_RAM(3);

u8* tileMemory = (u8*) BG_TILE_RAM(1);

// tell the DS where we are putting everything and set the 256 color mode
// and that we are using a 32x32 tile map
BG0_CR = BG_64x64 | BG_COLOR_256 | BG_MAP_BASE(0) | BG_TILE_BASE(1);

// load our palette...
//pallette entry 0 is black by default
BG_PALETTE[1] = RGB15(31,0,0); // red
BG_PALETTE[2] = RGB15(0,31,0); // green
BG_PALETTE[3] = RGB15(0, 0, 31); // blue
BG_PALETTE[4] = RGB15(31, 31, 0); // yellow
BG_PALETTE[5] = RGB15(31, 31, 31); // white

// copy the tiles into tile memory one after the other
swiCopy(blackTile, tileMemory, 32);
swiCopy(redTile, tileMemory + sizeof(blackTile), 32);
swiCopy(greenTile, tileMemory + sizeof(blackTile)*2, 32);
swiCopy(blueTile, tileMemory + sizeof(blackTile)*3, 32);
swiCopy(yellowTile, tileMemory + sizeof(blackTile)*4, 32);
swiCopy(whiteTile, tileMemory + sizeof(blackTile)*5, 32);

Remember, I said that my test world is 5x4, 32x32 maps and the background map is divided into 2x2, 32x32 regions, 0,1,2,&3. The table below is how the region is laid out for each row and column. Thus, if the scroll engine determines that it is on map 15 = WorldMaps[14], plugging that into nMapToRegion tells us which region map 15 belongs, i.e., region = nMapToRegion[15-1]; I subtract one since map1 is at entry zero. To avoid all that offset, subtraction, just number the maps starting at zero. I'll make that change in my final engine.


Here's the code setting up the arrays, and variables used to do the region bounds checks...

int WorldMaps[] = {
1, 2, 3, 4, 5,
6, 7, 8, 9, 10,
11, 12, 13, 14, 15,
16, 17, 18, 19, 20,
};

int nMapToRegion[] = {
0, 1, 0, 1, 0,
2, 3, 2, 3, 2,
0, 1, 0, 1, 0,
2, 3, 2, 3, 2,
};

int nMap = 0;
int nRegion = 0;
int nRowT = 0;
int nRowB = 0;
int nColL = 0;
int nColR = 0;

int nWorldPos_rx = 255; // 32 * 8 - 1
int nWorldPos_lx = 0;
int nWorldPos_ty = 0;
int nWorldPos_by = 191; // 24 * 8 - 1

int nScroll_x = 0;
int nScroll_y = 0;

int held; // used for keypad inputs

I created lookup tables to easily grab the maps and regions...

std::vector vRegionLookup;
std::vector vMapLookup;

// set the regions in lookup table
vRegionLookup.push_back(mapRegion0);
vRegionLookup.push_back(mapRegion1);
vRegionLookup.push_back(mapRegion2);
vRegionLookup.push_back(mapRegion3);

// push the maps to lookup table
vMapLookup.push_back(nWorldMap1);
vMapLookup.push_back(nWorldMap2);
vMapLookup.push_back(nWorldMap3);
vMapLookup.push_back(nWorldMap4);
vMapLookup.push_back(nWorldMap5);
vMapLookup.push_back(nWorldMap6);
vMapLookup.push_back(nWorldMap7);
vMapLookup.push_back(nWorldMap8);
vMapLookup.push_back(nWorldMap9);
vMapLookup.push_back(nWorldMap10);
vMapLookup.push_back(nWorldMap11);
vMapLookup.push_back(nWorldMap12);
vMapLookup.push_back(nWorldMap13);
vMapLookup.push_back(nWorldMap14);
vMapLookup.push_back(nWorldMap15);
vMapLookup.push_back(nWorldMap16);
vMapLookup.push_back(nWorldMap17);
vMapLookup.push_back(nWorldMap18);
vMapLookup.push_back(nWorldMap19);
vMapLookup.push_back(nWorldMap20);

Note, the lookup table for the World Maps is done this way only for testing and convience, in a real game you won't be able to load your whole game universe if it has a big play area. You will have to devise a scheme to read in the maps based on game levels, world size, etc...but, this gives you an idea.

Also, here are some global constants I used as well...

const int nMapEntries_x = 5;
const int nMapEntries_y = 4;
const int nMapSize = 1024;
const int nRegionSize = 256; // 32 * 8
const int nScreen_Xdim = 31*8; // ds screen width
const int nScreen_Ydim = 23*8; // ds screen height
const int nWorldSize_x = 1279; // nMapEntries_x * 32 * 8 - 1;
const int nWorldSize_y = 1023; // nMapEntries_y * 32 * 8 - 1

And, what you have been waiting to see, the scroll code...

bool bHorzBoundsHit = false;
bool bVertBoundsHit = false;

while(1)
{
// get the keys
scanKeys();
held= keysHeld();

// adjust scroll
if(held & KEY_LEFT)
{
nScroll_x--;
nWorldPos_rx--;
nWorldPos_lx--;
}

if(held & KEY_RIGHT)
{
nScroll_x++;
nWorldPos_rx++;
nWorldPos_lx++;
}

if(held & KEY_UP)
{
nScroll_y--;
nWorldPos_ty--;
nWorldPos_by--;
}


if(held & KEY_DOWN)
{
nScroll_y++;
nWorldPos_by++;
nWorldPos_ty++;
}

// reset bounds hit flags
bHorzBoundsHit = false;
bVertBoundsHit = false;

// adjust coords...not an infinite world
if(nWorldPos_lx <= 0)
{
bHorzBoundsHit = true;
nWorldPos_lx = 0;
nWorldPos_rx = nScreen_Xdim;
nScroll_x = 0;
}

if(nWorldPos_rx >= nWorldSize_x)
{
bHorzBoundsHit = true;
nWorldPos_rx = nWorldSize_x;
nWorldPos_lx = nWorldPos_rx - nScreen_Xdim;
nScroll_x = nWorldPos_rx - nScreen_Xdim - 8;
}

if(nWorldPos_ty <= 0)
{
bVertBoundsHit = true;
nWorldPos_ty = 0;
nWorldPos_by = nScreen_Ydim;
nScroll_y = 0;
}

if(nWorldPos_by >= nWorldSize_y)
{
bVertBoundsHit = true;
nWorldPos_ty = nWorldSize_y - nScreen_Ydim;
nWorldPos_by = nWorldSize_y;
nScroll_y = nWorldSize_y - nScreen_Ydim - 8;

}

//
// determine boundary hits
//

// right region border hit
if((nWorldPos_rx % nRegionSize == 0) && !bHorzBoundsHit)
{
// determine if we have split rows
nRowT = nWorldPos_ty / nRegionSize;
nRowB = nWorldPos_by / nRegionSize;

if(nRowT != nRowB)
{
//
// split rows
//

// determine the map we're in
nMap = nRowT * nMapEntries_x + (nWorldPos_rx / nRegionSize);

// what region is this
nRegion = nMapToRegion[nMap];

// move the proper map into the proper region
swiCopy(vMapLookup[nMap], vRegionLookup[nRegion], nMapSize);

// determine the map we're in
nMap = nRowB * nMapEntries_x + (nWorldPos_rx / nRegionSize);

// what region is this
nRegion = nMapToRegion[nMap];

// move the proper map into the proper region
swiCopy(vMapLookup[nMap], vRegionLookup[nRegion], nMapSize);
}

else
{
// rowt == rowb (same row)

// determine the map we're in
nMap = nRowT * nMapEntries_x + (nWorldPos_rx / nRegionSize);

// what region is this
nRegion = nMapToRegion[nMap];

// move the proper map into the proper region
swiCopy(vMapLookup[nMap], vRegionLookup[nRegion], nMapSize);
}
}

// left region border hit
if((nWorldPos_lx % nRegionSize == 0) && !bHorzBoundsHit)
{
// determine if we have split rows
nRowT = nWorldPos_ty / nRegionSize;
nRowB = nWorldPos_by / nRegionSize;

if(nRowT != nRowB)
{
//
// split rows
//

// determine the map we're in
nMap = nRowT * nMapEntries_x + (nWorldPos_lx / nRegionSize);

// get the previous region (one before us)
nRegion = nMapToRegion[nMap-1];

// move the previous map into the proper region
swiCopy(vMapLookup[nMap-1], vRegionLookup[nRegion], nMapSize);

// determine the map we're in
nMap = nRowB * nMapEntries_x + (nWorldPos_lx / nRegionSize);

// get the previous region
nRegion = nMapToRegion[nMap-1];

// move the previous map into the proper region
swiCopy(vMapLookup[nMap-1], vRegionLookup[nRegion], nMapSize);
}

else
{
// rowt == rowb (same row)

// determine the map we're in
nMap = nRowT * nMapEntries_x + (nWorldPos_lx / nRegionSize);

// get the previous region (one before us)
nRegion = nMapToRegion[nMap-1];

// move the previous map into the proper region
swiCopy(vMapLookup[nMap-1], vRegionLookup[nRegion], nMapSize);
}
}

// top region border hit
if((nWorldPos_ty % nRegionSize == 0) && !bVertBoundsHit)
{
// determine if we have split columns
nColL = nWorldPos_lx / nRegionSize;
nColR = nWorldPos_rx / nRegionSize;

// find the row we're on
nRowT = nWorldPos_ty / nRegionSize;

if(nColL != nColR)
{
//
// split columns
//

// determine the map we're in
nMap = nRowT * nMapEntries_x + (nWorldPos_lx / nRegionSize) - nMapEntries_x;

// what region is this
nRegion = nMapToRegion[nMap];

// move the proper map into the proper region
swiCopy(vMapLookup[nMap], vRegionLookup[nRegion], nMapSize);

// determine the map we're in
nMap = nRowT * nMapEntries_x + (nWorldPos_rx / nRegionSize) - nMapEntries_x;

// what region is this
nRegion = nMapToRegion[nMap];

// move the proper map into the proper region
swiCopy(vMapLookup[nMap], vRegionLookup[nRegion], nMapSize);
}

else
{
// colL == colR (same columns)

// determine the map we're in
nMap = nRowT * nMapEntries_x + (nWorldPos_rx / nRegionSize) - nMapEntries_x;

// what region is this
nRegion = nMapToRegion[nMap];

// move the proper map into the proper region
swiCopy(vMapLookup[nMap], vRegionLookup[nRegion], nMapSize);
}
}

// bottom region border hit
if((nWorldPos_by % nRegionSize == 0) && !bVertBoundsHit)
{
// determine if we have split columns
nColL = nWorldPos_lx / nRegionSize;
nColR = nWorldPos_rx / nRegionSize;

// find the row we're on
nRowB = nWorldPos_by / nRegionSize;

if(nColL != nColR)
{
//
// split columns
//

// determine the map we're in
nMap = nRowB * nMapEntries_x + (nWorldPos_lx / nRegionSize);

// what region is this
nRegion = nMapToRegion[nMap];

// move the proper map into the proper region
swiCopy(vMapLookup[nMap], vRegionLookup[nRegion], nMapSize);

// determine the map we're in
nMap = nRowB * nMapEntries_x + (nWorldPos_rx / nRegionSize);

// what region is this
nRegion = nMapToRegion[nMap];

// move the proper map into the proper region
swiCopy(vMapLookup[nMap], vRegionLookup[nRegion], nMapSize);
}

else
{
// colL == colR (same column)

// determine the map we're in
nMap = nRowB * nMapEntries_x + (nWorldPos_rx / nRegionSize);

// what region is this
nRegion = nMapToRegion[nMap];

// move the proper map into the proper region
swiCopy(vMapLookup[nMap], vRegionLookup[nRegion], nMapSize);
}
}

swiWaitForVBlank();

// set the scroll registers (scroll background)
BG0_X0 = nScroll_x;
BG0_Y0 = nScroll_y;
}


That's it! You can now scroll anywhere in your world, up, down, left, right, and diagonal. Changing the test hard coded limits I have, you can make your world any size you like and scroll.

I treated the DS screen to have the coordinates, LX,TY (left x, top y) for the upper, left hand corner, and RX,BY (right x, bottom y) for the lower, right hand corner. When scrolling you might be hovering over two tiles and scrolling vertical or horizantally, that is why I test for split rows, and columns.

I will clean some things up in my test code and make a generic C++ class, tile, scroll engine. I'll next, test dropping objects in my world at arbitrary locations and see if I can scroll around, leave and comeback and they are still where I left them. Of course, they won't actually stay by themselves, I'll have to write the code to make them behave.

If anyone would like a copy of the source, to help them get started, shoot me an email or post here and I'll get a link up or email you a copy. I don't know who's reading or interested, so that would be a good barometer.

In the mean time..."keep scrollin', scrollin', scrollin'!"

Friday, January 18, 2008

"In the midnight hour..."

"she cried more, more, more
with a rebel yell.."


Oh...we're on...broadcasting...

Hey there!

Just coming to you with a midnight update. I tried my scheme out on the DS just for a vertical, down scroll. I just wanted to see if what I was thinking was correct and whoohooo, it is. Hmmmn...it's not going to be a piece cake coding the DS without the source in the debugger, but I guess I'll have to manage, I don't have $1K to plunk down for the source level debugger for NO$GBA, but if anyone wants to, help a brother out, I'll be glad to put your donations to valuable DS programming use. However, I do love the fact that the NO$GBA debugger allows me to see all the memory areas of the DS, live and in living color. So, I guess I'll manage and will learn the arm7/9 assembly language too. Note: I am coding in C/C++, but the debugger only shows assembly code.

Anyway, the scheme works! There were some minor adjustments to my calculations, like the RegionSize should be 32*8, and not 32, since we're dealing with screen, pixel coordinates, not tile sizes.

I will try and code up the rest this weekend and get back to you with the...yes, yes, diagrams, and the code to do it.

"Owwww...in the midnight hour babe...

Wednesday, January 16, 2008

Errata

In my posting yesterday, the calculation that determines that map you are in should have taken into account the row, you are scrolling over in the WorldMap. The row can be determined from your vertical scroll and a calculation to determine that.

So, the code should look like...

// determine the map we're in
nMap = nRow * nMapEntries_x + (nWorldPos_rx / nRegionSize + 1);

Where, nRow is going to be calculated from the vertical scroll. When, its all done I will post it.

Oh, just wanted to give a shot out to one of my co-workers, he works with me on the project we do for our day jobs, he's part-time, still in college. His name is Steve Taylor, this guy is already internet famous, with the indy game he released, 'Plasma Pong.' Atari got upset and made him pull his site down, since he used the name, 'Pong,' because there can be no infringement of two paddles hitting a ball across the screen. Atari wasn't the first to do that or patent that.

If you want to see the game, go to youtube, search for 'plasma pong,' it is very cool. Steve uses fluid dynamics in real time in the game. We've talked about the math intensive calculations he had to do for it. He's shown me a demo of one of his other ideas using soft-body (rag doll) physics.

As a side note, here's some 6 degrees of separation for you. I use to work for Nolan Bushnell the original founder of Atari, and creator of Pong. I worked at PlayNet, where Nolan was part-owner.

So Atari get off Steve's back and, "let me see that Pong! That Pong, pa-pa-pa-Pong!" (sing it to the beat of what's that singer's name, is he even still recording, you know, the Thong song dude).

Tuesday, January 15, 2008

Haven't Forgotten

Hi folks!

No, I haven't forgotten about the scroll algorithm, nor has it been too challenging for me. I've been crunching time and code for my day job (security virtual machine app). So, tonight has been my first night since my previous posting to actually work on my idea. So far, so good.

What I discovered staring at the tiles on my bathroom wall, was that since the DS background is 64x64 tiles, I can divide that area up into 4 regions of 32x32 tiles,

0 1
2 3

With 0 = 32x32, 1 = 32x32, 2 = 32x32, and 3 = 32x32.

Thus, if I make my game, tile maps on 32x32 boundaries, when I hit a boundary limit on scrolling, I can simply blast a whole map into the region that is out of view, but will be coming into view. In order to blast the proper map to the proper region, I've come up with a scheme. As, I also stated in my previous posting, I highly doubt if this is an original thought here, but I haven't seen any game world scrolling code anywhere on the internet, and I looked around to see. Post to me, let me know if this is a common approach, or if there is an easier, faster, more elegant method.

The scheme...

1) Define my world size, that is, how big of an area I wish to be able to scroll around. For this example I've picked 1280x1024 pixels. Remember, the tile size that I'm going to use is 8x8 pixels. So, doing the math (ahhh...if you don't like math, then stop now, game programming isn't going to be your cup of tea...well, you can do it, if you don't like it, but know that you will be doing LOTS of it, all the time)...

1280 pixels / 8 (1 tile) = 160 pixels / 32 pixels (region size) = 5
1024 pixels / 8 (1 tile) = 128 pixels / 32 pixels (region size) = 4

Thus, my world map will consist of an array 5x4 of world tiles.

World Map (tile entries)
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20

2) Remember, I said I was going to divide the DS background into 4, 32x32 regions,
0 1
2 3

I will keep a table that correlates (I wanted to say, 'maps,' but didn't want to be too confusing...oh but, you said it anyway!) World Map to the background region it should be copied to.

MapToRegion
0 1 0 1 0
2 3 2 3 2
0 1 0 1 0
2 3 2 3 2

There's a pattern there and thus, you can easily derive a formula to find the region to copy to, when you know the map you wish to copy, but I think a look up table might be faster...who knows, get it working first and then you can do all the size vs speed trade offs.

So, looking at my World Map table if I were in tile map 14, I would just have to plug that entry into my MapToRegion table and I find that the region, tile map 14 should be copied to is, 1. Why/how? Because the 14th entry in the MapToRegion table is equal to 1. If I chose, tile map 7, then the region would be 3.

I know, it still may not be clear yet, I will continue describing my approach. The DS visible screen size is 32x24 tiles (32x8 = 256, 24x8 = 192 pixels). If I were to take that screen and place it at the beginning of my World Map, "that's a complete dramatization, you can't really do that." I know, but imagine that if that whole 5x4 area were laid out on a table, like a map, and you had a spy glass, that could see only 32x24 tiles at a time, if the spy glass started on tile 1, you would see all of 1 in the 'x' direction and 3/4 of it in the 'y' direction. Huh? Seeing 3/4 in the 'y' direction? Remember, a tile is 32x32, and the spy glass (screen) is 32x24, so 24/32 = .75 = 3/4...ahh, repetition is the essence of pedagogy.

We have our 5x4 map, and our spy glass, but lets say that our table isn't big enough to hold the complete map laid out in all its 5x4 glory. We've got a teeny, tiny, table that can only hold a map of 2x2. Does the tiny 2x2 table remind you of anything? "Correcto mundo, check out the big brain on...," ahhh...what's your name?
That's right, the DS background, divided into our 4 background regions...

0 1
2 3

So, since our table can only hold 2x2 tiles, I can fold the map up into quarters, and eights, and...NOT! What if, I just cut each tile out and place them separately on the floor, when I need to see a section I can pick it up and move it to the table. In essence, this is what you are doing when working with the DS and scrolling around your world. The floor is the map area, the table is the background area, and the spy glass is the vram. You have limited space so you must manage it all.

From the World Map, I move 1 into region 0, 2 into region 1, 6 into region 2, and 7 into region 3. Thus, looking at my table I have...

1 2
6 7

The spy glass can currently see only tile 1. Now, if I start to move the spy glass across the map to the right, changing the 'x' coordinates, but keeping the 'y' the same, we are doing a simple horizontal scroll to the right, when I scroll 1 pixel right, the right border of the spy glass is now, gone past our 32 boundary and into the other region which is tile 2. I'm now just seeing a sliver of tile 2. However, if I continue to scroll right I see more of tile 2, and less of tile 1. When, I get to the right border of tile 2, meaning my spy glass is seeing completely tile 2, if I were to continue to scroll right, over the boundary, what the DS does is loop, so I would see tile 1 again. You can't do to much with a game world that size, actually you can, you just won't be scrolling...anyway, continuing with my scheme, when I detect a boundary crossing, I pick up from the floor the next tile, and put it in the proper region on the table.

How do I know which tile, and which region? "I wish someone would tell him, so I could go to sleep!"

By doing a little math. Since the World Map is 5x4 in size, that means, if you look back at the math above, my world is
1280x1024 pixels, when the map is completely unfurled. When, I scroll the spy glass if I keep track of the pixel count, adding when I scroll to the right, and subtracting when I scroll left, I can determine when I have hit boundaries evenly divisible by 32, that means, the division is a whole number, no remainders.

This algorithm is only for scrolling to right, and down, just to give you a jist, a taste, wet your whistle..."GET ON WITH IT!"

const int nMapEntries_x = 5;
const int nRegionSize = 32;

int nMapToRegion[] = {
0, 1, 0, 1, 0,
2, 3, 2, 3, 2,
0, 1, 0, 1, 0,
2, 3, 2, 3, 2,
};

int nMap = 0;
int nRegion = 0;

// determine right coord boundary hit
if(nWorldPos_rx % nRegionSize == 0)
{
// determine the map we're in
nMap = nWorldPos_rx / nRegionSize + 1;

// what region is this
nRegion = nMapToRegion[nMap-1];
}

// determine bottom coord boundary hit
if(nWorldPos_by % nRegionSize == 0)
{
// determine the map we're in
nMap = nWorldPos_by / nRegionSize * nMapEntries_x + 1;

// what region is this
nRegion = nMapToRegion[nMap-1];
}

Try it out on paper...you will see, you can easily determine which map and region. And, determining left and up scroll is similar.

Next time...

I will explain the algorithm for calculating the nMap in case some don't get it.
I also promised last blog posting to have scanned in diagrams for those that understand more easily with drawings, so I will scan in some drawings this weekend and post. In the mean time, I will code up my scheme and see if it works.

Till next time...Peace out! Can we go to sleep now!

Tuesday, January 8, 2008

Late Breaking News...

*TO MUCH INFO FOLLOWS*

Sitting in the bathroom, looking at the tiles on my bathroom wall an idea came to me on how to do the tiling algorithm. I've done an initial test on graph paper and it seems to work and seems to be less computationally intensive then my original idea, and also seems like it may be faster as well.

Since I haven't seen any other examples online of background/tile scrolling, I don't know if this approach is one that is already used. In all things I do, I never believe that I am the only one with the idea. The universe is vast and mysterious and I personally believe that ideas float about and some of us, antennae pick up certain signals, then most ignore, some act, and a few finish. If it is a world changing idea, like Calculus, Relativity, or chemically made soft cookies, then the number of few finishing becomes very minuscule. So, the ratio of ideas to finish is, BIG IDEA, VERY FEW WILL PRODUCE...medium ideas, handful will produce...very general ideas, good number will copy. :)

Anyway, just wanted to break in with the late breaking update, that I might be onto something with my scroll algorithm and faster than I thought. We'll see...I will try it out and then post to blog, along with the drawing and explanation I promised from my last post.

This has been an "ahhhh haaa," announcement.

"...tile please"

Night one of figuring out the background/tile scroll algorithm...I spent a few hours re-reading how the DS stores and handles background maps and tried some things, placing tiles in different background map sizes and filing different BG_MAP_RAM regions. I spied the activities with the NO$GBA debugger. I could see what was actually happening to the VRAM (video ram) and determined what I will initially try as my background tile/scroll algorithm.

I will put the DS in BG_64x64 mode, this will set the tile mode of the DS to be 64x64 tiles wide. The DS screen size is 32x24 tiles wides (256x192 pixels). So, that means I can load an image that is 512x512 pixels into the background, and if the screens left,top origin is 0,0...I'll be able to scroll 2 screen widths right before hitting the edge of my image.

Okay, all those pixels and tiles talk and 32x24, 64x64, etc...might be a little confusing, but it really isn't. The DS screen size is 32x24 tiles. I'll be using 8x8 pixel tiles. So, 32x8 = 256 pixels, and 24x8 = 192 pixels. If I set a background map size of 64x64 tiles, that is 64x8 = 512 pixels, by 512 pixels.



The above isn't close to scale, but should give you and idea of what I'm trying to describe. Imagine the bigger box as the background map, the smaller one is the screen. You see the screen can scroll a little bit before getting to the horizontal, and vertical edges. When the screen does hit those edges the screen just loops back around. Therefore, if the background image is US flag, and we start the screen in the top left corner on the stars and do a horizontal scroll, when we get to the right edge and go a pixel over the border we will begin to see the beginning of the stars again.

This would make for a very monotonous game if we continued to loop on the background, a perpetual, ground hog effect, or is it an infinite regression? I digress...so the idea behind the background/tile scrolling is when the screen hits the border, we load the unseen areas of the background (if we are on the right edge, then we load the left edge with new and different tile data), changing parts of the original image as we merrily scroll about.

Note: Next posting I will draw this, scan in, and paste to blog what I'm trying to describe. I'm a visual learner, and I suspect a lot of other folks are too.

I will stop here, because I realize that what I need to do is draw this all out by hand to show you, "Show them! You mean show yourself!" how this will work. A picture is worth 1000 words, they say. Who is the "they?"

How Are You Doing It?

I forgot to mention the tools needed to get this "homebrew," project up and running. Again, those familiar with DS homebrewing already know this, these initial postings aren't for you. However, perhaps *when* I get my tiling/scrolling engine up and running some may be interested, because I've noticed that quite a few get stuck at that point in their quest to do games on the DS, and thus stick to static screen games.

Anyway, since I don't have 8-10K to plunk down for an official development kit, and if I did I would have to be a licensed developer with Nintendo to acquire one, I am relying on the diligent hackers that have already provided tools to do development on the DS.

Here's what I'm using and how much it costs...

DevkitPro's DevkitARM / FREE - Is a tool chain based on the gnu compiler with additional scripts, makefiles and libraries to aid compiling and building C/C++ code for the ARM (Advance Risc Machine) 32-bit embedded processor. (I'll have to do another posting explaining the DS hardware, it uses two ARM processors (ARM7 and ARM9)).

Visual Studio 2005 / (Already own it, so say its FREE, but you can download Visual Express freely and use it) - I develop the code using MSVC 2005, only using the IDE (intergrated development enviornment) and intellisense to write the code quickly since I am already familiar with IDE. DevkitARM has a script that you can hook into MSVC that allows you to build GNU C/C++ from it. Currently there is no way to debug the DS from MSVC, since mimicking the DS on the PC means you need to have an emulator that behaves like it is the DS hardware. Which leads to the next tool...

NO$GBA / $15 - This is an emulator/debugger by Martin Korth, one can compile/build DS and take the executable and load it into Korth's emulator/debugger and see DS code run on their PC. The $15 version of the debugger gives you everything you need to debug for the DS, except source code (c/c++), you see the ARM7/9 machine instructions. The source level debugger costs $1750. You do get to set breakpoints, watch variables, see all the hardware registers the DS has that you have to control to do things like hardware scroll, sprite movements, sound, touchpad, etc..., code, data, stack windows, I/O, and VRAM windows, background maps and palette windows, a cornucopia of stuff. :)

*check out these screen shots of the emulator/debugger*
http://nocash.emubase.de/gbapics.htm

GBATools Level Mapper and Sprite Grabber / FREE - Allows you to construct levels from tiles and build sprites. It has occurred to me that again some folks who may be reading my blog may not know what a *sprite* is...it is the animated character (space ship, pacman, missles, etc...) you see in 2D games that is moving around on your screen.

The above tools and cost is $15 to be able to create DS games without even owning a DS, just run everything on your PC with an emulator. However, you want to be able to take your creation and show it off so you will need...

Nintendo DS / (Anywhere from $99 - $150, depending on where you buy it) - Even if you quit homebrewing you still have a neat little game system to play on.

Storage devices which the DS can access and tools to instruct the DS to run your game, I haven't actually tried out these yet so can't report on them, I'll just list them...

GBAMP (Gameboy Advanced Movie Player) available from Lik-Sang.com / $25 plus shipping) and uses Compact Flash giving you unlimited storage.

XPORT from http://www.charmedlabs.com / $140 - $200


Taken from the Novoto's NDS tutorial...
The other tool you need is one which tricks the DS into running your game even though it is not an official DS game. The Passme type devices are quite common.


There's also a technique that uses the DS's Wifi capability that allows you to download your DS executable from your computer directly to the DS. I'll be trying this out in months and will get back to you on how that is done.

What else is needed...

Perseverance / cost: sweat and tears

Imagination / cost: priceless


Finally, you may have noticed that a few of the tools have "GBA" (Gameboy Advance) in their titles, that's because these tools were first created for the GBA and have been expanded to work on the DS.

I am working on the tiling engine, I have given myself a 3 week deadline to get it done...ahh...yes, 3 weeks, remember I do have a day job, and work on this stuff in the little free time I have. "Well, stop talkin' about it, and be about it!" OKAY! OKAY! *My conscience loves to give me a hard time*

Monday, January 7, 2008

Where I Am

Since I started blogging yesterday, doesn't mean that it was my first day with the DS. No, I've been reading up and trying little samples to learn how to control the dual screens, key pads, sprites, backgrounds, sound, IPC (inter process communications), and background scrolling.

I'm not going to write another tutorial here on how to do all that, plenty of info on the web for all that. Some folks following this blog may be real technocrats when it comes to games and consoles, and some others may be greener then Kermit the Frog's butt (insert my family members...they're just curious about what I'm doing). I'll try to explain things in a middle ground. If anyone out there happens to stumble across this blog ("My name is Rod Haxton and I will be broadcasting on this frequency..." ahhh...okay, had an "I Am Legend," moment) and wants more detail info, I will try to give it to them.

So, some basic info about the DS is that it can do both 2D and 3D. Currently, I'm focusing on the 2D because the style of game I'm thinking of doing is 2D and thus the major thing I have to get going first is a "tiling," engine. What is a "tiling," engine?

Tiles are an economical way of storing and displaying the bitmap images on the DS. The DS screen sizes are 256 x 192 pixels. The memory to store an image on the screen is 256x256 bits. Yes the pixel equals the bit. Thus, if I were to scroll the screen over the background, in one byte shift left or right (horizontal scroll), I would already have scrolled over the border of the image, and if were to do a vertical scroll down, I would be only 8 bytes (64 bits/pixels) away from scrolling over the bottom border (256 pixels - 192 pixels = 64 pixels / 8 bits = 8 bytes)

Fortunately, the DS has 64 background storage areas split into 2, 32 sections of graphic character base and character map base.



So, in the Graphics Base area one stores the background data (tiles). In the Map Base area one stores the tile offsets that make up the picture we want to display. I know for those unfamiliar this still isn't clear, hold on..The graphics base area is commonly filed with 16x16 (can be other sizes as well) postage stamp size pics. These individual pics are shoved into the Graphics (character) base. The Map Base area tells the DS 2D renderer how to arrange those pics (tiles) into a screen picture.

The following image example and text (italicized) is pulled from the DevScene NDS tutorial...


Below is all the graphics used to construct the entire overworld of the original Zelda.




You may recognize these little 16x16 chunks as pieces of the Zelda world and perhaps you could imagine that in order to describe the look of the overworld all one would have to do is store which tile goes where. For instance the following familiar scene could be represented by an array of tile numbers.




short map[] = {
64,64,64,64,64,64,64,06,06,64,64,64,64,64,64,64,
64,64,64,64,07,64,62,06,06,64,64,64,64,64,64,64,
64,64,64,62,06,06,06,06,06,64,64,64,64,64,64,64,
64,64,62,06,06,06,06,06,06,64,64,64,64,64,64,64,
64,62,06,06,06,06,06,06,06,63,64,64,64,64,64,64,
06,06,06,06,06,06,06,06,06,06,06,06,06,06,06,06,
64,67,06,06,06,06,06,06,06,06,06,06,06,06,64,64,
64,64,06,06,06,06,06,06,06,06,06,06,06,06,64,64,
64,64,06,06,06,06,06,06,06,06,06,06,06,06,64,64,
64,64,66,66,66,66,66,66,66,66,66,66,66,66,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64
};

Thus, the image with all the different tiles scrambled about is the Graphics Base data. The array of shorts is the Map Base data. If you look closely at the array of shorts you see that the number 64 represents the grass bushes in the image above.

Through code I would instruct the DS which area of Graphics, and Map Base data to address to paint my image on the screen. The "tiling," engine, needs to keep track of Map Base data and where on the screen correlates in the array, and when have I crossed boundaries and then need to index into another map array to keep the images on the screen seamlessly flowing (smooth scrolling both horizontally and vertically). The engine has to know where graphic maps that make up the world are stored in memory, where the tiles that describe how to be displayed are stored, where the screen is currently in relation to the world (screen to world coordinate translations) and when to pull new tiles into the map base memory area.

When I first got into game programming this was my first task to figure out, and imagine, I didn't have blogs, internet, or anything like that to figure it out. Luckily, I did have Ray (I forget Ray's last name). We worked for a company that did things, lets say, on the cheap. So, we had one manual for the GameBoy, and one development system, again for the GameBoy, Ray joined the company a month before me and so wisely he chose the documented and developer friendly system. However, I was doing Sega GameGear. No manual, no dev system, just a card that I could plug into the GameGear and slap an eprom chip onto it. Talk about flying blind, I had to flash the screen to let me know yes or no, but then with all those blinks happening I couldn't tell if it was one or two blinks, and what was I asking.

So, trying to write a complex algorithm (oh did I mention, in Z80 assembly) without a debugger, I wasn't going to get my tile scrolling algorithm to work within the two week period I was given. Ray saw me sweating and came to the rescue. He figured it out on his system, and gave me the code. Of course, I had to tweak somethings here and there to get to run on the GameGear. Fortunately, after much bitching and moaning on my part, the owner spent a few dollars and cobbled together a system that would allow me to debug the Z80 code...not the official dev kit, but hell of a lot better than flashing screens.

Therefore, the "tiling," engine is the major thing to figure out. Everything else from here in the 2D world is gravy.

Off to tile!

Sunday, January 6, 2008

Ahhh...yes, I've decided to blog.

Today...tonight, marks my first blog posting. I will use this blog to muse about my Nintendo DS Home Brewing. YAHB! (Yet Another Homebrew Blog!)

Mainly, I'm blogging so as to keep my ass in gear. Since, by day, I'm hard at work on my bosses project (programming a security, virtual machine application), at night I want to keep my creative, game programming cravings fed.

I worked in the game industry previously for Borta Inc., PlayNet, Kesmai, and Aeon.

So, I decided that I would pick up the DS and start programming it. Long, long, time ago...I worked on the Sega GameGear, 'Urban Strike,' game. I literally, got *bitched* out of an official credit, however I did the main ground work on the game, but later was plucked to lead up the Byron Priess, Screen Saver Companion Disks (90210, Fraiser, Melrose Place, etc...) and made sure that I did get credit...lesson learned.

Anyway, the architecture of the Sega GameGear and the Nintendo Gameboy were somewhat similar. A few years back I picked up the GameBoy Advance and did a bit more hacking on it. So, now I'm picking up the DS and this time I plan to actually, not have a bunch of little demos, but to actually make a game (at least 2 full levels, with music, HUD, etc...). What that game will be, is still floating around in my mind and in a composition notebook. Ideas are floating around, but I want to first test some things out.

So, that's what this blog will cover mainly. I am a movie buff, and have scripted a few screenplays, and even made a movie that was shown in 2 film festivals, and wrote a script for a 48 Hour Film Festival, so every now and then you may find a quote from a movie, or me blabbing about a movie.

Till then let the DSing begin!

-Rod