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.
Hi,
I've recently picked up GBDK + C to have a go at coding some quick original GB games. I've been cutting my teeth with my first simple game, it's been many many years since coding pure C! So getting back in to the swing of things.
Already got stuck in, have background and sprites working, including a large background map scrolling smoothly which is great.
I now want to introduce a HUD to my game, which I 'think' I need to use the Window tiles layer for. I can't find any decent resource around using the Window. I've tried to hunt down resources around this and i either hit dead links or brick walls. Most examples are in ASM. I've looked at the galaxy.c example, but can't see how the window works with just a top layer.
I'm assuming I should be displaying my game like this:
Background - scrolling background scene tiles
Window - HUD, 1 row of tiles at the top of the screen displaying score + lives
Sprites - movable objects in the scene, player, enemies, bullets, effects, etc...
Every time i turn on the Window layer, it hides the background tiles. Also the tiles I set aren't the ones I'm expecting to be set.
Does anyone know of any good C examples or tutorials around this area?
Any help or advice would be massively appreciated!
Thanks,
Retro Rich
Offline
RetroRich wrote:
Every time i turn on the Window layer, it hides the background tiles.
Thanks,
Retro Rich
I remember hearing that you need to move the window slightly off the screen for it to not obscure the screen completely. That's all I remember about the Window functionality, and I had the same thing happen before when enabling the Window layer. I haven't tried moving the window yet though.
RetroRich wrote:
Also the tiles I set aren't the ones I'm expecting to be set.
By that, do you mean the background map has the wrong tiles, or the tiles themselves having the wrong appearance?
Offline
The window is not a layer in the sense that SNES and more modern console have BG layers. There's no transparency to the BG layer, and it always starts drawing the top left corner of the map selected for the window, at position (WX,WY). What's happening internally in the graphics processor is that when it's drawing line WY and reaches pixel WX, it switches the BG rendering circuit to draw from the window map source. Simply setting both WY and WX to 0 will just cover the whole screen as you discovered. Try setting them to some position in the middle of the screen as a test.
Because of how it's drawn, the window is excellent for placing a HUD on the bottom or right side of the screen. If you want a HUD at the top of the screen, you have to change some LCD parameters at the scanline where you want the HUD to stop. You could either use the window and disable the window at that line, or just use the BG and change SCX, SCY and the map source at that line. You could do this using an interrupt, but I'm not sure how viable that is using C because of the tight timing and the interrupt overhead in GBDK compared to asm.
Online
nitro2k01 wrote:
There's no transparency to the BG layer, and it always starts drawing the top left corner of the map selected for the window, at position (WX,WY). What's happening internally in the graphics processor is that when it's drawing line WY and reaches pixel WX, it switches the BG rendering circuit to draw from the window map source. Simply setting both WY and WX to 0 will just cover the whole screen as you discovered.
The window not being transparent is why I will most likely not use the window in my game. If you need a transparent HUD you need to use sprites (unless there is something that I don't know about the Game Boy's hardware).
Offline
Tag365 wrote:
The window not being transparent is why I will most likely not use the window in my game. If you need a transparent HUD you need to use sprites (unless there is something that I don't know about the Game Boy's hardware).
The problem you may run into is the 10 sprite per line limit. If you exceed that, any excessive sprites will simply be hidden. Depending on what you want to have in your HUD, that may be too limiting. Besides, for a DMG game, it may be a good idea to actually have a solid background for legibility considering the LCD lag.
Online
nitro2k01 wrote:
Tag365 wrote:
The window not being transparent is why I will most likely not use the window in my game. If you need a transparent HUD you need to use sprites (unless there is something that I don't know about the Game Boy's hardware).
The problem you may run into is the 10 sprite per line limit. If you exceed that, any excessive sprites will simply be hidden. Depending on what you want to have in your HUD, that may be too limiting.
If the HUD is small then sprites may be useful for building the HUD.
nitro2k01 wrote:
Besides, for a DMG game, it may be a good idea to actually have a solid background for legibility considering the LCD lag.
Explain why do you think that could be a good idea.
Offline
Ah ha! Thank you both Tag365 and nitro2k01, you've given me a couple of things to try out now.
To clarify, on my window layer, the tiles showing on the window, aren't the ones I've asked to display. e.g. i'm setting tile id 53 but it's show tile id 33 ( i made those tile id's up for the example).
I'll have a play this evening and let you know how I get on. Thanks again for the pointers!
Offline
RetroRich wrote:
To clarify, on my window layer, the tiles showing on the window, aren't the ones I've asked to display. e.g. i'm setting tile id 53 but it's show tile id 33 ( i made those tile id's up for the example).
You could erroneously be using the tileset as the fifth argument when calling the set_win_tiles function. Make sure you use the map and not the tileset for that function.
Offline
Tag365 wrote:
Explain why do you think that could be a good idea.
To get higher contrast between HUD elements and the background. Of course, the HUD design comes into play as well.
Online
Yeah rychan, thought I'd give you a rest, wouldn't have got this far without you tho! Thank you!
Window layer:
So I thought I'd be cheeky, move my HUD to the button row of the window layer, then scroll the window with a negative value to over hang the top of the screen... if only it were that easy. In fact any negative y value just hides the window all together.
I was able to move the HUD to the bottom of the screen with ease, but really would love to have it on the top row.
Started to look at interrupts, I've not used them with GBDK before, couldn't find a clear example trying to achieve what I want to achieve, surprising as I thought it would be a common thing needed? So I hashed together some basic code to try and turn off the window layer when the SCY is a certain value. However, when i add to the LCD interrupt, performance drops massively (I mean with an empty function, just activating the interrupt). I wonder if it just can't be done with C as the timing is all off? Something i have to jump in to ASM for?
Anyone know of an example that does what I'm trying to achieve?
I could use sprites, but don't want to use them up ideally, but maybe it is the way to go?
Offline
RetroRich wrote:
However, when i add to the LCD interrupt, performance drops massively (I mean with an empty function, just activating the interrupt). I wonder if it just can't be done with C as the timing is all off? Something i have to jump in to ASM for?
I don't know if there's a "correct" way of doing this in GBDK, but you need to select the appropriate interrupt source(s) you want to use by setting bits 3-6 in the STAT register. You probably have HBlank and/or OAM interrupt enabled, which causes 160 or more interrupts to be triggered on every screen refresh. For your use, you should only set bit 6, "LYC=LY Coincidence Interrupt". This triggers and interrupt only on the scanline selected by the LYC register. Your procedure then would be to set up the display to show the HUD in VBlank, then set up the regular game display to be shown in the LCD interrupt.
Online
RetroRich wrote:
Window layer:
So I thought I'd be cheeky, move my HUD to the button row of the window layer, then scroll the window with a negative value to over hang the top of the screen... if only it were that easy. In fact any negative y value just hides the window all together.
Reason for that is that argument can only be an 8-bit unsigned integer. It can't be a negative number less than zero since the number is unsigned, thus you can't move it to the top of the screen easily.
RetroRich wrote:
I was able to move the HUD to the bottom of the screen with ease, but really would love to have it on the top row.
Started to look at interrupts, I've not used them with GBDK before, couldn't find a clear example trying to achieve what I want to achieve, surprising as I thought it would be a common thing needed? So I hashed together some basic code to try and turn off the window layer when the SCY is a certain value. However, when i add to the LCD interrupt, performance drops massively (I mean with an empty function, just activating the interrupt). I wonder if it just can't be done with C as the timing is all off? Something i have to jump in to ASM for?
Anyone know of an example that does what I'm trying to achieve?
Try searching for something on the internet.
RetroRich wrote:
I could use sprites, but don't want to use them up ideally, but maybe it is the way to go?
I would only use sprites if I wanted a transparent HUD. Sprites have a transparency trick, in that pixels set to the first color (of four possible colors in a tile) will become transparent.
As explained earlier, you have a limit on how many sprites that can be shown on the same line, where if more than ten sprites are on the same row only the first ten on the row will be shown. Something that he didn't tell you about is that it is somewhat difficult to have more than 40 sprites shown in the same frame, but I don't know about that.
Offline
I NOW HAVE IT WORKING! - background scrolling + sprites + top tile line of window displayed only.
Thanks again for all your help, with some additional documentation sent through from rychan, I've managed to get somewhere. I'll probably write up a blog post at some point, in the mean time, here's my current code:
void main() { STAT_REG = 0x45; LYC_REG = 0x08; // Fire LCD Interupt on the 8th scan line disable_interrupts(); OBP0_REG = 0x1B; //change sprite palette SHOW_WIN; SHOW_SPRITES; SHOW_BKG; add_LCD(interruptLCD); enable_interrupts(); set_interrupts(VBL_IFLAG | LCD_IFLAG); gameState = INTRO; while (true){ SHOW_WIN; updateMain(); wait_vbl_done(); } } void interruptLCD() { HIDE_WIN; }
Have to admit, I understand the higher level and have tried to extract bits of code that I thought was needed combined with some registers I think need to be set.
Performance seems to be OK too, although if I'm doing things unnecessarily or could be done more efficiently, please let me know.
Thanks again!!
Offline