gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > My brain's been driven into the ground. (and stamped on)

#54487 - Ultima2876 - Mon Sep 19, 2005 10:56 pm

Diagonal Scrolling - while loading tiles at the edges. Argh.

I think many of us have been there, and there's even an ancient topic about it.

I've been fiddling with this for a few days now, and can't get it right. Down and left/right scrolling works absolutely fine, but I'm having a strange problem with the diagonal aspect of the scrolling - it updates most of the VRAM map fine, except for a triangular section... and it only does this with maps of a different width to 32 tiles (although that's probably because I'm using a 256x256 VRAM map - which means it has the correct tiles there anyway). So, I have a 128x32 tile map, being read into my 32x32 VRAM map.

Code:
hofs_prev = *hoffset >> 3;
      vofs_prev = *voffset >> 3;
      scroll_speedpart += speed & 0xFF;      //deal with the fixed-point speed, and update the speed part (increment speed for the frame if the speed part overflows)
      speed = speed >> 8;
      speed += scroll_speedpart >> 8;
      scroll_speedpart = scroll_speedpart & 0xFF;
      if(speed > 8)
         {
            speed = 8;
         }
      if(direction == 0 || direction == 2 || direction == 4)   //(right scrolling)
         {
            *hoffset += speed;            //increase the offset by the speed
            if(hofs_prev != *hoffset >> 3)   //if the last frame's tile-hoffset was different, you need to update the tiles
               {
                  for(loop = 0; loop < 21; loop++)   //update the tiles at the edge of the screen
                     {
                        temp_vofs = bios_mod(((loop + (*voffset >> 3))), map_height);
                        ((u16*)map_vram)[(((loop + (*voffset >> 3)) & 0x1F) << 5) + *map_write_x] = ((u16*)map)[(map_width * temp_vofs) + *map_position_x];
                     }
                  *map_position_x += 1;
                  *map_write_x += 1;
                  *map_write_x = *map_write_x & 0x1F;
                  if (*map_position_x == map_width) { *map_position_x = 0; }
               }
            *BG_HOFS = *hoffset;         //update the H scroll register
         }
      else if(direction == 1 || direction == 3 || direction == 5)      //(left scrolling)
         {
            *hoffset -= speed;            //decrease the offset by the speed
            if(hofs_prev != *hoffset >> 3)   //if the last frame's tile-hoffset was different, you need to update the tiles
               {
                  if (*map_position_x < -1) { *map_position_x = map_width - 1; }
                  for(loop = 0; loop < 21; loop++)   //update the tiles at the edge of the screen
                     {
                        temp_vofs = bios_mod(((loop + (*voffset >> 3))), map_height);
                        ((u16*)map_vram)[(((loop + (*voffset >> 3)) & 0x1F) << 5) + *map_write_x] = ((u16*)map)[(map_width * temp_vofs) + *map_position_x];
                     }
                  *map_position_x -= 1;
                  *map_write_x -= 1;
                  *map_write_x = *map_write_x & 0x1F;
                  if (*map_position_x == -1) { *map_position_x = map_width - 1; }
               }
            *BG_HOFS = *hoffset;         //update the H scroll register
         }
      if(direction == 4 || direction == 5 || direction == 7)   //(down scrolling)
         {
            *voffset += speed;            //increase the offset by the speed
            if(vofs_prev != *voffset >> 3)   //if the last frame's tile-hoffset was different, you need to update the tiles
               {
                  for(loop = 0; loop < 32; loop++)   //update the tiles at the edge of the screen
                     {
                        temp_hofs = bios_mod(loop + hofs_prev, map_width);
                        ((u16*)map_vram)[(*map_write_y << 5) + ((loop + hofs_prev) & 0x1F)] = ((u16*)map)[(map_width * *map_position_y) + temp_hofs];
                     }
                  *map_position_y += 1;
                  *map_write_y += 1;
                  *map_write_y = *map_write_y & 0x1F;
                  if (*map_position_y == map_height) { *map_position_y = 0; }
               }
            *BG_VOFS = *voffset + bgv;
         }


There's my code. The bios mods are for making the maps wrap around the map_height and map_width - which can be of any size.

At first I suspected the problem was to do with incorrect implementation of the X offsetting in this line:

Code:
((u16*)map_vram)[(*map_write_y << 5) + ((loop + hofs_prev) & 0x1F)] = ((u16*)map)[(map_width * *map_position_y) + temp_hofs];


And to be honest I still do. However, my brain is hurting quite a lot and i can't figure it out.

Next up, screenshots.

http://img155.imageshack.us/img155/5968/terrag4je.png

That's what it kind of should look like (a mock up, really).

http://img155.imageshack.us/img155/6033/terrag20jw.png

Any help would be very much appreciated.

#54602 - Miked0801 - Tue Sep 20, 2005 7:13 pm

Welcome to edge scrolling hell. When you figure this out, you will join an elite group of programmers who have solved that nasty problem.

In general, I've found that the when the overlap square is not handled correctly, it's because you aren't completely calculation 1 direction before starting on another direction. Good luck!

#54614 - tepples - Tue Sep 20, 2005 9:42 pm

To handle a diagonal scroll properly, update the vertical edge only on those frames when you aren't updating the horizontal edge.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#54660 - gauauu - Wed Sep 21, 2005 11:07 am

Wow..that's a good idea. sounds easier than what I did...(although I can't remember how I finally solved the problem, to be honest)