Discussion about software development for the old-school Gameboys, ranging from the "Gray brick" to Gameboy Color
(Launched in 2008)
You are not logged in.
Hello. I recently started developing for GB using GBDK.
The game I'm writing requires a lot of blocks that can be pushed around. Due to the sprite limit, I got creative and used background tile data to display blocks. When you push them, I update the tile data in memory to simulate the movement by calling set_bkg_tiles() again.
This is working great on the emulator (BGB), but my question is, is this solution proper? Can tile data be changed while the display is on using an actual GB?
Thanks
Last edited by ek82 (2015-08-12 02:30:40)
Offline
Yes, a tile can be changed while the display is on while in vblank. The usual approach is to have a copy of the BG in WRAM, which is transferred in chunks inside the vblank interrupt service routine (ISR).
However, you can also just initialize the BG and have a queue memory structure of changes to perform. So in vblank, this queue is read and the changes are written to the BG in VRAM.
For instance, a memory structure might look like this:
struct bg_change {
uint8_t x,
uint8_t y,
uint8_t tile_no
}
struct bg_change bg_changes[5];
Initialize so that every x is 255, every y and tile_no are don't cares. Inside the vblank ISR, loop through the list and applies the changes:
uint8_t i; for (i = 0x00; i < ARRAY_SIZE(bg_changes); i++) { /* end of list */ if (bg_changes[i].x == 0xFFu) break; /* write to screen */ write_screen(bg_changes[i].x, bg_changes[i].y, bg_changes[i].tile_no); /* invalidate current entry, because it's done */ bg_changes[i].x = 0xFFu; }
I have seen this approach in games that don't update a whole lot of tiles on screen at once.
Your initial question: You can use bg tiles to do what you want. It's certainly a nice option.
Depending on the smoothness you require, it might be an option to do the following when a block is pushed:
-draw a sprite with the same tiles/color as the bg block right over the bg block
-erase the bg block
-animate the sprite moving to the new position as the block is being pushed
-draw a bg block under the sprite with same tiles/color
-erase sprite
cYa,
Tauwasser
Last edited by Tauwasser (2015-08-12 02:46:35)
Offline
Thanks for the reply.
[EDIT]
I went the vbl interrupt route.
void vblCallback(){ if(updateTileMap == TRUE){ updateTileMap = FALSE; /* update memory here */ } } .... then in init code disable_interrupts(); DISPLAY_OFF; /* set up interrupts */ add_VBL(vblCallback); .... other init stuff DISPLAY_ON; enable_interrupts(); set_interrupts(VBL_IFLAG); .... other init stuff
Thanks!
Last edited by ek82 (2015-08-12 03:45:30)
Offline
Should tile changes always be done on vblank interrupt? I call set_bkg_tiles all the time (for example, when printing text to the screen) and just do it on the fly. Is that bad? It seems to have worked so far.
Offline
Use the latest BGB and make sure "Emulate as in Reality" is checked in the Exceptions tab in the preferences menu. That way you'll know if you produce bad code.
As for set_bkg_tiles, it calls set_xy_btt, which checks if it is called in vblank. Thus, every few bytes, it will wait in a busy loop until the next vblank. This is very slow. If you develop for CGB consider HDMA. If you develop for DMG, consider putting your own routine inside the VBLANK ISR like I mentioned above. Drawing will be considerably faster that way.
cYa,
Tauwasser
Offline