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.
So I started using GBDK a few days ago and I wanted to add a simple frame at the bottom of the screen for when text is being shown to the player. However although the frame is loaded into memory, when I use "set_win_tiles", it only draws the first sprite for the frame and it draws it everywhere apart from the xy coordinates specified. Please can someone explain how to fix this?
Offline
Source code here:
#include <gb/gb.h> #include <stdio.h> #include <stdlib.h> #include <gb/console.h> #include "smile.c" #include "frown.c" #include "box.c" void main () { HIDE_WIN; set_win_data(0,12,Bbox); set_win_tiles(1,12,1,1,Bbox); SPRITES_8x8; set_sprite_data(0, 8, smile); set_sprite_tile(0, 0); move_sprite(0, 55, 75); set_sprite_tile(1, 1); move_sprite(1, 55, 75+8); set_sprite_tile(2,2); move_sprite(2,55+8,75); set_sprite_tile(3,3); move_sprite(3,55+8,75+8); set_sprite_data(8,8,frown); set_sprite_tile(4,8); move_sprite(4,95,75); set_sprite_tile(5,9); move_sprite(5,95,75+8); set_sprite_tile(6,10); move_sprite(6,95+8,75); set_sprite_tile(7,11); move_sprite(7,95+8,75+8); SHOW_SPRITES; SHOW_WIN; while(1) { if(joypad()==J_A || joypad()==J_B) { set_sprite_tile(2,6); set_sprite_tile(3,7); set_sprite_tile(4,12); set_sprite_tile(5,13); set_sprite_tile(6,14); set_sprite_tile(7,15); delay(500); set_sprite_tile(2,2); set_sprite_tile(3,3); set_sprite_tile(4,8); set_sprite_tile(5,9); set_sprite_tile(6,10); set_sprite_tile(7,11); delay(500); } if(joypad()==J_START) { HIDE_WIN; } } }
Offline
This is what is shown on the screen on launch:
And this is the first part of the window that it is drawing:
Offline
There are 2 problems.
1 - For sprites, color 0 is transparent, not white. You should modify the register that holds the palette and set light grey to white or something like that.
2 - Probably the first tile you are loading to VRAM is that corner. I imagine that the background is filled with 0s at startup, so it uses that tile everywhere.
If you are using bgb to test the rom, press Esc, then F5. That should help find the cause of the problem.
Offline
I changed the set_win_data to be "set_win_data(1,12,Bbox);" instead of "set_win_data(0,12,Bbox);", which fixed the error of the screen being full of the tile. I ran the new code on the emulator I was using before (VisualBoyAdvance) but now it doesn't draw any of the tiles on the window. I also ran the code in bgb but there it draws all the tiles for the window on the background and they can only be seen when the window is hidden. I know that the tiles for the background and for the window are stored in the same place, but why does it draw the tiles on the background if I haven't used the command to do that?
Offline
This is the new source code :
#include <gb/gb.h> #include <stdio.h> #include <stdlib.h> #include <gb/console.h> #include "smile.c" #include "frown.c" #include "box.c" void main () { HIDE_WIN; HIDE_BKG; set_win_data(1,12,Bbox); set_win_tiles(2,2,1,1,1); SPRITES_8x8; set_sprite_data(0, 8, smile); set_sprite_tile(0, 0); move_sprite(0, 55, 75); set_sprite_tile(1, 1); move_sprite(1, 55, 75+8); set_sprite_tile(2,2); move_sprite(2,55+8,75); set_sprite_tile(3,3); move_sprite(3,55+8,75+8); set_sprite_data(8,8,frown); set_sprite_tile(4,8); move_sprite(4,95,75); set_sprite_tile(5,9); move_sprite(5,95,75+8); set_sprite_tile(6,10); move_sprite(6,95+8,75); set_sprite_tile(7,11); move_sprite(7,95+8,75+8); SHOW_SPRITES; SHOW_BKG; SHOW_WIN; while(1) { if(joypad()==J_A || joypad()==J_B) { set_sprite_tile(2,6); set_sprite_tile(3,7); set_sprite_tile(4,12); set_sprite_tile(5,13); set_sprite_tile(6,14); set_sprite_tile(7,15); delay(500); set_sprite_tile(2,2); set_sprite_tile(3,3); set_sprite_tile(4,8); set_sprite_tile(5,9); set_sprite_tile(6,10); set_sprite_tile(7,11); delay(500); } if(joypad()==J_START) { HIDE_WIN; } if(joypad()==J_SELECT) { HIDE_BKG; } } }
And this is what bgb shows when I hide the window.
As you can see, it draws the tiles on the background instead of the window. Please can someone explain to me why it does this?
Offline
The BG and the window share the maps. http://bgb.bircd.org/pandocs.htm#lcdcontrolregister
You need to select the one you want for each one of them.
Offline
I used "LCDC_REG &= 0xBFU;" to set the 6th bit to 0 and this means that the tiles show by default, but aren't set as the window and are still set as the background. I also tried the opposite of "LCDC_REG |= 0x40U" but this still drew it on the background.
Offline
I changed some things with my code so that each tile is loaded into memory individually, and when drawing the tiles it draws them on the window layer. However even though each tile is loaded in from a specific array, when I try to get it to draw anything that isn't the first tile it either just draws the first tile, a background tile that is loaded in or won't draw anything. It's frameTLE0, frameTLE2, frameTLE3 and frameTLE4 that won't draw anything and frameTLE5 and frameTLE7 that use the background tile. I don't understand why it is doing this.
Source code:
#include <gb/gb.h> #include <stdio.h> #include <stdlib.h> #include <gb/console.h> #include "smile.c" #include "frown.c" #include "box.c" #include "back1.c" #include "frame.h" #include "frame.c" void main () { HIDE_WIN; HIDE_BKG; set_bkg_data(1,1,back1); SWITCH_ROM_MBC1(frameBank); set_win_data(128,1,frameTLE0); set_win_data(129,1,frameTLE1); set_win_data(130,1,frameTLE2); set_win_data(131,1,frameTLE3); set_win_data(132,1,frameTLE4); set_win_data(133,1,frameTLE5); set_win_data(134,1,frameTLE6); set_win_data(135,1,frameTLE7); SWITCH_ROM_MBC1(frameBank); set_win_tiles(0,0,1,1,frameTLE0); set_win_tiles(0,1,1,1,frameTLE1); set_win_tiles(0,2,1,1,frameTLE2); set_win_tiles(0,3,1,1,frameTLE3); set_win_tiles(0,4,1,1,frameTLE4); set_win_tiles(0,5,1,1,frameTLE5); set_win_tiles(0,6,1,1,frameTLE6); set_win_tiles(0,7,1,1,frameTLE7); SPRITES_8x8; set_sprite_data(0, 8, smile); set_sprite_tile(0, 0); move_sprite(0, 55, 75); set_sprite_tile(1, 1); move_sprite(1, 55, 75+8); set_sprite_tile(2,2); move_sprite(2,55+8,75); set_sprite_tile(3,3); move_sprite(3,55+8,75+8); set_sprite_data(8,8,frown); set_sprite_tile(4,8); move_sprite(4,95,75); set_sprite_tile(5,9); move_sprite(5,95,75+8); set_sprite_tile(6,10); move_sprite(6,95+8,75); set_sprite_tile(7,11); move_sprite(7,95+8,75+8); SHOW_SPRITES; SHOW_BKG; SHOW_WIN; while(1) { if(joypad()==J_A || joypad()==J_B) { set_sprite_tile(2,6); set_sprite_tile(3,7); set_sprite_tile(4,12); set_sprite_tile(5,13); set_sprite_tile(6,14); set_sprite_tile(7,15); delay(500); set_sprite_tile(2,2); set_sprite_tile(3,3); set_sprite_tile(4,8); set_sprite_tile(5,9); set_sprite_tile(6,10); set_sprite_tile(7,11); delay(500); } if(joypad()==J_START) { HIDE_WIN; } if(joypad()==J_SELECT) { HIDE_BKG; } } }
Here is what it draws:
Offline
And here are frame.h and frame.c
frame.h
/* FRAME.H Include File. Info: Form : Each tile separate. Format : Gameboy 4 color. Compression : None. Counter : None. Tile size : 8 x 8 Tiles : 0 to 7 Palette colors : None. SGB Palette : None. CGB Palette : None. Convert to metatiles : No. This file was generated by GBTD v2.2 */ /* Bank of tiles. */ #define frameBank 0 extern unsigned char frameTLE0[]; extern unsigned char frameTLE1[]; extern unsigned char frameTLE2[]; extern unsigned char frameTLE3[]; extern unsigned char frameTLE4[]; extern unsigned char frameTLE5[]; extern unsigned char frameTLE6[]; extern unsigned char frameTLE7[]; /* End of FRAME.H */
frame.c
/* FRAME.C Tile Source File. Info: Form : Each tile separate. Format : Gameboy 4 color. Compression : None. Counter : None. Tile size : 8 x 8 Tiles : 0 to 7 Palette colors : None. SGB Palette : None. CGB Palette : None. Convert to metatiles : No. This file was generated by GBTD v2.2 */ unsigned char frameTLE0[] = { 0xFF,0xFF,0x80,0xFF,0x80,0xC0,0x80,0xC0, 0x80,0xC0,0x80,0xC0,0x80,0xC0,0x80,0xC0 }; unsigned char frameTLE1[] = { 0x80,0xC0,0x80,0xC0,0x80,0xC0,0x80,0xC0, 0x80,0xC0,0x80,0xC0,0x80,0xFF,0xFF,0xFF }; unsigned char frameTLE2[] = { 0xFF,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; unsigned char frameTLE3[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF }; unsigned char frameTLE4[] = { 0xFF,0xFF,0x01,0xFF,0x01,0x03,0x01,0x03, 0x01,0x03,0x01,0x03,0x01,0x03,0x01,0x03 }; unsigned char frameTLE5[] = { 0x01,0x03,0x01,0x03,0x01,0x03,0x01,0x03, 0x01,0x03,0x01,0x03,0x01,0xFF,0xFF,0xFF }; unsigned char frameTLE6[] = { 0x80,0xC0,0x80,0xC0,0x80,0xC0,0x80,0xC0, 0x80,0xC0,0x80,0xC0,0x80,0xC0,0x80,0xC0 }; unsigned char frameTLE7[] = { 0x01,0x03,0x01,0x03,0x01,0x03,0x01,0x03, 0x01,0x03,0x01,0x03,0x01,0x03,0x01,0x03 }; /* End of FRAME.C */
Offline
I think your usage of set_win_tiles is incorrect. The last argument should be an array of the tile index data.
Something like:
unsigned char frameColumn[] { // Assuming your tile indices are mapped to 1-7. 1, 2, 3, 4, 5, 6, 7 } // Set all 7 tiles in a single column, starting at position 0,0 set_win_tiles(0,0,1,7,frameColumn);
Offline
When I try to use the "unsigned char frameColumn[] = {0,1,2,3,4,5,6,7}", my program won't compile and gives an error saying "parse error: token -> 'unsigned' ; column 16". Also when I try and do "set_win_tiles(0,0,1,8,frameColumn);" it gives the error, "error *** Undefined identifier 'frameColumn'". Is there something that I am missing here? I have the tiles loaded into memory as frameTLE0-frameTLE7. Does it need to be done differently? I don't understand why it won't work.
Offline
Can you post your updated code? The array should be declared the same way as your frameTLEX definitions. So it shouldn't be giving you a parse error. Maybe double check that you have a semicolon after the declaration.
I am not sure how much you know about how the window/bg tiles work. Here is a quick description, hope it helps clear things up.
When dealing with the tile data you are managing two buffers. You have the tile data where your 8x8 pixel tile data is stored which you populate using the set_win_data. Then you have the screen buffer which is the 32x32 byte buffer where each byte maps to a tile by index in the tile data buffer these are updated using set_win_tiles.
So to draw a tile you load your tiles with set_win_data then call set_win_tiles using the index values you assigned them in set_win_data (first argument in this case).
Offline
Here is the main file:
#include <gb/gb.h> #include <stdio.h> #include <stdlib.h> #include <gb/console.h> #include "smile.c" #include "frown.c" #include "box.c" #include "back1.c" #include "frame.h" #include "frame.c" void main () { HIDE_WIN; HIDE_BKG; set_bkg_data(1,1,back1); set_win_data(128,8,frameTLE0); set_win_data(129,1,frameTLE1); set_win_data(130,1,frameTLE2); set_win_data(131,1,frameTLE3); set_win_data(132,1,frameTLE4); set_win_data(133,1,frameTLE5); set_win_data(134,1,frameTLE6); set_win_data(135,1,frameTLE7); unsigned char frameColumn[] = {0,1,2,3,4,5,6,7}; set_win_tiles(0,0,1,8,frameColumn); SPRITES_8x8; set_sprite_data(0, 8, smile); set_sprite_tile(0, 0); move_sprite(0, 55, 75); set_sprite_tile(1, 1); move_sprite(1, 55, 75+8); set_sprite_tile(2,2); move_sprite(2,55+8,75); set_sprite_tile(3,3); move_sprite(3,55+8,75+8); set_sprite_data(8,8,frown); set_sprite_tile(4,8); move_sprite(4,95,75); set_sprite_tile(5,9); move_sprite(5,95,75+8); set_sprite_tile(6,10); move_sprite(6,95+8,75); set_sprite_tile(7,11); move_sprite(7,95+8,75+8); SHOW_SPRITES; SHOW_BKG; SHOW_WIN; while(1) { if(joypad()==J_A || joypad()==J_B) { set_sprite_tile(2,6); set_sprite_tile(3,7); set_sprite_tile(4,12); set_sprite_tile(5,13); set_sprite_tile(6,14); set_sprite_tile(7,15); delay(500); set_sprite_tile(2,2); set_sprite_tile(3,3); set_sprite_tile(4,8); set_sprite_tile(5,9); set_sprite_tile(6,10); set_sprite_tile(7,11); delay(500); } if(joypad()==J_START) { HIDE_WIN; } if(joypad()==J_SELECT) { HIDE_BKG; } } }
And here is frame.c:
/* FRAME.C Tile Source File. Info: Form : Each tile separate. Format : Gameboy 4 color. Compression : None. Counter : None. Tile size : 8 x 8 Tiles : 0 to 7 Palette colors : None. SGB Palette : None. CGB Palette : None. Convert to metatiles : No. This file was generated by GBTD v2.2 */ unsigned char frameTLE0[] = { 0xFF,0xFF,0x80,0xFF,0x80,0xC0,0x80,0xC0, 0x80,0xC0,0x80,0xC0,0x80,0xC0,0x80,0xC0 }; unsigned char frameTLE1[] = { 0x80,0xC0,0x80,0xC0,0x80,0xC0,0x80,0xC0, 0x80,0xC0,0x80,0xC0,0x80,0xFF,0xFF,0xFF }; unsigned char frameTLE2[] = { 0xFF,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; unsigned char frameTLE3[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF }; unsigned char frameTLE4[] = { 0xFF,0xFF,0x01,0xFF,0x01,0x03,0x01,0x03, 0x01,0x03,0x01,0x03,0x01,0x03,0x01,0x03 }; unsigned char frameTLE5[] = { 0x01,0x03,0x01,0x03,0x01,0x03,0x01,0x03, 0x01,0x03,0x01,0x03,0x01,0xFF,0xFF,0xFF }; unsigned char frameTLE6[] = { 0x80,0xC0,0x80,0xC0,0x80,0xC0,0x80,0xC0, 0x80,0xC0,0x80,0xC0,0x80,0xC0,0x80,0xC0 }; unsigned char frameTLE7[] = { 0x01,0x03,0x01,0x03,0x01,0x03,0x01,0x03, 0x01,0x03,0x01,0x03,0x01,0x03,0x01,0x03 }; /* End of FRAME.C */
Offline
I also tried putting replacing 0-7 in frameColumn with frameTLE0-frameTLE7 but that didn't work either. It produced the same error.
Offline
C doesn't like variables declared in the middle of a scope. Try moving it to the start of the scope. You might also try making it global. I think there are serious performance concerns creating large arrays on the stack.
Offline
It finally works! Thank you for your help, I can finally get back to working on the rest of this project!
Offline