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 everyone!
I've just discovered ZGB, and I cannot overstate how wonderful it is!
I've set up the work environment (took me a while), I've read and completed the tutorial (very helpful, thanks a lot Zalo for writing it). Now I'm slowing trying to learn the in & out of this engine (and gbdk) to try to fulfill a childhood dream: create a game for the GameBoy !
Here is a capture of my current "test / learning how to make a game". I've been able to make a moving player and enemy thanks to the tutorial, and I've managed to add the ability to shoot bullets to the player :
Despite the wonderful resources available here, I must confess that I have a "noob" question I'm unable to answer. When the bullet hit the enemy, I would like to transform the enemy into a permanent obstacle (much like placing a grave of the enemy on the background map).
I thought that the best way would be to simply replace the current "background tile" where the enemy died, and set it to tile "0x01" instead of "0x00". So that way it would look like a "wall", and also respond to background collisions.
However, I'm clueless about how to do this.
I've thought of modify the "map" loaded by InitScroll, but it's a "const" (and making it a variable break the compiler). I guess there must be a way to modify just one tile of the background (maybe with set_bkg_tile), but I couldn't figure how.
Does anyone have a hint or idea that could help me?
Thanks a lot for your help.
Last edited by drludos (2017-05-11 22:15:18)
Offline
Hi, drludos, I'm gald you like the engine
I am afraid dynamically changing the background is not posible yet. It is one of the things I have on the pending list but it requires several changes:
- right now collisions are checked against the map on the rom (this is stored as const because that memory belongs to the cartdrigge itself and cannot be modified) so even if you change the bg on screen (using set_bkg_tiles) there will be no collisions at all
- using scroll will be even harder since I'll have to find a way to keep changed tiles, otherwise when moving the screen modified tiles will be back to normal
- the function GetTileReplacement can be used for this purpose, but still I think I need to change how collisions sprite-background works
these are just some hints if someone want to try and make this changes, but in the meantime I would recommend not doing games that require changes in the background
Offline
Zalo, have you thought about loading the BG in RAM? You would need to update the tile in RAM and VRAM, and you are limited to kinda small maps, but maybe it's good enough.
Or, if you don't want that, you could say something like in the documentation: "this can only be used for animations that disappear when the tile leaves the screen, so don't use it for permanent changes or for changes that modify the collisions of the map".
Offline
Hi Zalo,
Thanks a lot for your reply and your help!
It seems for now I won't be able to make such a game as long as it uses a map stored in the rom, as a const. Just to be sure, did you have to make it a const because the Gameboy RAM is too tiny to load scrolling map exceeding 32*32 tiles?
(I've read somewhere that's it's the maximum size of the background when you don't use dynamic loading)
In fact, my first intent was to make such game without scrolling, so I'll have a couple more question if that's ok for you:
- Is it possible to "disable" the scrolling in game?
I noticed that, if I don't set any sprite as the "scroll_target", it stay one the initial screen, while still handling the collisions (which is great). But I guess that under the hood, the engine is still try to "scroll" the screen each time I call a "translate sprite" function. I order to save some CPU power, is there any way to "skip" the whole "scrolling" routines in a simple way?
- I've noticed that, on the DMG, the game start to lag when there is only 3-4 sprites moving at the same time. I guess that it's mainly due to the use of 8x16 sprites that are more costly to move than 8x8 ones.
As I plan to use mainly 8x8 sprites (bullets, enemies, etc. Only the player will be 16x16), do you think the engine would run faster with 8x8 sprites instead of 8x16 ones where only the 8x8 top part is actually used?
(I configured them as 8x8, but by reviewing your code, it seems that they are still 8x16 for the Gameboy, as you can't have both 8x8 and 8x16 at the same time)
Thanks again for your help, and for making such a wonderful engine in the first place!
I'm quite amazed how easy some complex task are possible with ZGB (such as DMG/CGB games making, moving sprites, scrolling huge maps, collision handling, sound and music, bank switching...)
Offline
I'll start this post saying that I know nothing at ZGB.
drludos wrote:
Hi Zalo,
Thanks a lot for your reply and your help!
It seems for now I won't be able to make such a game as long as it uses a map stored in the rom, as a const. Just to be sure, did you have to make it a const because the Gameboy RAM is too tiny to load scrolling map exceeding 32*32 tiles?
(I've read somewhere that's it's the maximum size of the background when you don't use dynamic loading)
The GB has two tile maps of 32x32 tiles. So, without updating it, you can only have 32x32 tiles in two sets, period.
However, it's possible to dynamically re-write the map as the camera scrolls.
In your case, it's irrelevant but now you know it's possible.
If you want to dynamically adjust collision, you may want to turn your "moving" sprites into "static" ones. When the player tries to move, if he intersects a static sprite, he doesn't move. Which is more or less updating the collision.
- I've noticed that, on the DMG, the game start to lag when there is only 3-4 sprites moving at the same time. I guess that it's mainly due to the use of 8x16 sprites that are more costly to move than 8x8 ones.
As I plan to use mainly 8x8 sprites (bullets, enemies, etc. Only the player will be 16x16), do you think the engine would run faster with 8x8 sprites instead of 8x16 ones where only the 8x8 top part is actually used?
(I configured them as 8x8, but by reviewing your code, it seems that they are still 8x16 for the Gameboy, as you can't have both 8x8 and 8x16 at the same time)
You are correct in thinking 8x8 and 8x16 sprites can't be used at the same time, except with some limitations and clever manipulation.
Anyways, moving 8x8 or 8x16 sprites has the same cost.
Sprites are just entries in a table, and you tell the GB whether they are 8x8 or 8x16 (globally! There isn't a switch per sprite). So moving a sprite is just changing an entry in the table, no matter what size it is.
The lag may be caused by the sprite's interactions, or different stuff. It's up to Zal0 to tell.
Offline
drludos wrote:
I thought that the best way would be to simply replace the current "background tile" where the enemy died, and set it to tile "0x01" instead of "0x00". So that way it would look like a "wall", and also respond to background collisions.
Does anyone have a hint or idea that could help me?
Thanks a lot for your help.
I also tried to dynamicaly change the bkg tiles and collisions...
You can do it!, but only for a few static items on the map, for example doors.
Tomorrow i'll upload some code , just a clue, you have to use a different bkg tile for every editable object, and you have to edit the collision arrays (scroll_collisions[tile] and scroll_collisions_down[tile];
Offline
AntonioND wrote:
Zalo, have you thought about loading the BG in RAM? You would need to update the tile in RAM and VRAM, and you are limited to kinda small maps, but maybe it's good enough.
Yes, actually that should work... if you copy the map data to the RAM (and then load that copy using InitScroll) and change it, collisions should work. You need to update both the copied map and the bakground (using set_bkg_data), but yeah for small maps (32x32 is 1024 bytes and that should fit into memory) it should work
drludos wrote:
It seems for now I won't be able to make such a game as long as it uses a map stored in the rom, as a const. Just to be sure, did you have to make it a const because the Gameboy RAM is too tiny to load scrolling map exceeding 32*32 tiles?
Maps need to be declared as const so they are stored in ROM memory because for the kind of games I have done, they don't fit into RAM. One of them might fit, but ZGB was thought for games using several screens. Also if you are going to change them bear in mind that change is going to persist throught several executions if you don't keep a copy of the original
drludos wrote:
- Is it possible to "disable" the scrolling in game?
I noticed that, if I don't set any sprite as the "scroll_target", it stay one the initial screen, while still handling the collisions (which is great). But I guess that under the hood, the engine is still try to "scroll" the screen each time I call a "translate sprite" function. I order to save some CPU power, is there any way to "skip" the whole "scrolling" routines in a simple way?
You'll have to modify some code in the main loop (vbl_update in main.c) and still all sprites will calculate their coordinates based on the scroll position for example (in SpriteManagerUpdate on SpriteManager.c) that should be removed too...
ISSOtm wrote:
Sprites are just entries in a table, and you tell the GB whether they are 8x8 or 8x16 (globally! There isn't a switch per sprite). So moving a sprite is just changing an entry in the table, no matter what size it is.
The lag may be caused by the sprite's interactions, or different stuff. It's up to Zal0 to tell.
I'm afraid the lag is caused because of the use of gbdk. This is one of the main disadvantages of using C instead of asm and specially with a compiler as bad as gbdk which forces me to do lots of workarounds that I'm sure are having a big impact on the performance. Until someone finally adds support to banks on gbdk-n there isn't too much we can do
Offline
Well drludos, this is what you can do about editing map collisions right now, I'll use the example of doors.
First you create a door tile, and place it at tile 3 in GBTD.
Then you set some tiles to be solid, also set 3 to be solid.
const UINT8 collision_tiles[] = {1,2,3,....};
You have to declare the collision array in your file, because that array is declared in scroll.c.
extern UINT8 scroll_collisions[];
Now for example, you want the door to open when something happens, so, you can create another tile data containing an oppened door and:
if(something == 1) { scroll_collisions[3] =0; set_bkg_data(3, 1,open_door_tile); }
Scroll_collisions contains a "1" for every solid tile you set. If you store a "0" at position 3, the third tile will not be solid any more.
scroll_collisions is in RAM and set_bkg_data changes the tile in VRAM, so this change works on big maps, and it is permanent as long as you don't load another map, evenif you scroll very far.
You can use this to edit many tiles, until you reach the tile positions used for fonts (if you load fonts).
But, if the tile is used at several positions in the bkg map, this code will edit all of them.
If you optimize your bkg to use very few tiles, you could have about 150 editable tiles in a big map.
So for example, a mario game could break and change collision, of around 30 big brick blocks (made of 4 tiles) in a certain level map.
In your game, the enemy only could be converted to a solid tile, at certain positions of the bkg with this coding.
Hope this helps.
Last edited by Mills (2017-05-23 05:17:09)
Offline
Woaw, thanks a lot everyone for your detailed answers!
I'll try your approach Mills to make "backround tiles" move from collidable to non-collidable, while at the same time trying to define the map as a variable in RAM as Zalo suggests to be able to modify not only the tile, but also the map itself during gameplay .
Thanks again everyone for being so helpful, I'll try this and I'll post my progress here!
Offline
drludos wrote:
Woaw, thanks a lot everyone for your detailed answers!
I'll try your approach Mills to make "backround tiles" move from collidable to non-collidable, while at the same time trying to define the map as a variable in RAM as Zalo suggests to be able to modify not only the tile, but also the map itself during gameplay .
Thanks again everyone for being so helpful, I'll try this and I'll post my progress here!
I once calculated how big a map could be to fit in ram, but i lost that code. Anyway I think you can fit decent maps in ram, maybe games like mario store the map in parts and load to ram just the part mario is in.
Offline
If you take Pokémon, for example, they store the map in 4x4 tile squares, and all of these squares are copied to WRAM at map loading.
Slight quirk : this is only true for the currently loaded map, so the maps next to it are actually read from ROM.
But if you have different rooms (ŕ la Undertale, for example) that's not a problem.
Last edited by ISSOtm (2017-05-24 17:21:04)
Offline
Zalo wrote:
I'm afraid the lag is caused because of the use of gbdk. This is one of the main disadvantages of using C instead of asm and specially with a compiler as bad as gbdk which forces me to do lots of workarounds that I'm sure are having a big impact on the performance. Until someone finally adds support to banks on gbdk-n there isn't too much we can do
Can you explain this a bit further? Not to derail the OP's thread.
Offline
kikiwunder wrote:
Zalo wrote:
I'm afraid the lag is caused because of the use of gbdk. This is one of the main disadvantages of using C instead of asm and specially with a compiler as bad as gbdk which forces me to do lots of workarounds that I'm sure are having a big impact on the performance. Until someone finally adds support to banks on gbdk-n there isn't too much we can do
Can you explain this a bit further? Not to derail the OP's thread.
Quick explanation : C can't be ran by anything. Instead it's a kind of "intermediate stage", which is ' 'translated' ' (compiled) into something that can actually work (assembly).
The translation process can produce varying results (ranging from "lion" to "animal standing on four legs found in hot and dry environments which is sometimes called the king of the animals"), and gbdk tends to produce the latter, which of course is slower than if you just wrote "lion" yourself.
Solution #1 is to change translators (but here it's NOT possible)
Solution #2 is for you to learn English... but of course it defeats the whole purpose of ZGB
Offline
I meant more specifically about the lack of banking support. Recent versions of sdcc (3.6.1 is what I'm using) generate much better code than before and you can get around a lot more of the speed issues with inlining or using __naked__ functions.
Offline
AFAIK, gbdk-n is an unrelated project that aims at fixing what's bad in gbdk. And it doesn't have banking support yet.
Offline
Ahh found the github issue:
https://github.com/andreasjhkarlsson/gbdk-n/issues/5
Good to know; gives me a heads up before I hit that.
Offline
I did some quick tests with gbdk-n and it fixes all the issues pointed on my blog. I am sure the new version of sdcc fixes a lot more. That will allow me amongst other things to use 8bit vars in lots of places instead of 16bit vars because of lots of bugs in the current version. That will speed up things a lot
Also if anyone is interested I'll be happy to move some core parts of ZGB to asm (gbdk asm beacuse it will still need C code). There are still a lot of room for improvements here
Offline
I'd be curious to see (with a recent sdcc) how different the assembly would be vs hand-tuned. Shame z80-sdcc isn't on godbolt.
Offline
Zalo wrote:
I did some quick tests with gbdk-n and it fixes all the issues pointed on my blog. I am sure the new version of sdcc fixes a lot more. That will allow me amongst other things to use 8bit vars in lots of places instead of 16bit vars because of lots of bugs in the current version. That will speed up things a lot
Also if anyone is interested I'll be happy to move some core parts of ZGB to asm (gbdk asm beacuse it will still need C code). There are still a lot of room for improvements here
Wait, the engine is compiled in C ?
I'd be interested in porting to ASM, I've proven myself to be a pro at dirty ASM optimization lately :p But only if you agree ^^'
Offline
ISSOtm wrote:
Zalo wrote:
I did some quick tests with gbdk-n and it fixes all the issues pointed on my blog. I am sure the new version of sdcc fixes a lot more. That will allow me amongst other things to use 8bit vars in lots of places instead of 16bit vars because of lots of bugs in the current version. That will speed up things a lot
Also if anyone is interested I'll be happy to move some core parts of ZGB to asm (gbdk asm beacuse it will still need C code). There are still a lot of room for improvements hereWait, the engine is compiled in C ?
I'd be interested in porting to ASM, I've proven myself to be a pro at dirty ASM optimization lately :p But only if you agree ^^'
That would be cool!. I tried to write a new "set_bkg_tile" function in asm, to avoid the gbdk function, and it did not work well my asm coding skills are nearlly 0%.
I posted the function at the first page of the main ZGB thread.
Last edited by Mills (2017-06-11 11:44:13)
Offline
ISSOtm wrote:
I'd be interested in porting to ASM, I've proven myself to be a pro at dirty ASM optimization lately :p But only if you agree ^^'
If everything works exactly as it is right now I'll be happy to merge it. And if you continue giving support after the first iteration
Offline
HI,
Did you ever get set_bkg_tile to work ? Everytime I try it displays a currupted looking tile.
Hopefully you could help me with this please ?
thanks
Offline