ams-hackers / gbforth

👾 A Forth-based Game Boy development kit
https://gbforth.org
MIT License
121 stars 23 forks source link

Provide a library to handle tiled graphics #325

Open euhmeuh opened 4 years ago

euhmeuh commented 4 years ago

I'm trying to make a top down strategy game using gbForth, and wonder how to easily render tiled maps on the screen.

For now, I'm using the term.fs library, but it feels clunky and unpractical to consider graphics as text lines. The machine tends to become slow as I try to render more lines of tiles to the screen (I currently prepare the map in RAM before sending it to type, which explains the performance loss).

I'm considering writing a library, something like tilemap.fs, to ease the creation and rendering of tilemaps.

I'm opening this issue here to gather thoughts and directions on how to do that.

Plans

  1. Define the 32x32 map using a word like map::
map: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
map: 0 3 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0
map: 3 2 3 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0
map: 0 3 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0
map: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
map: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 0 0 0 0 0 0 0 0 0 0 0
map: 0 0 0 0 0 0 0 0 4 0 4 0 4 0 0 0 0 0 0 6 6 0 0 0 0 0 0 0 0 0 0 0
map: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
\ ... 32 times
  1. Define masks of a specific tile:
( this would render a map using tiles 4 and 5 )
mask: 4 %00000000 %00001110 %00000000 %00000001
mask: 5 %01100000 %00111110 %00000000 %00000001
mask: 5 %01100000 %00011000 %00000000 %00000011
mask: 4 %00000000 %00000000 %00001111 %00000111
\ ... 32 times
  1. Copy/extract a map to VRAM using map!video or mask!video.
tkers commented 4 years ago

Interesting :) just to understand a bit better what you’re looking for: Are you talking about a static (background) tilemap? Also, what would mask: do in your example (if map: is already used to define the map)?

euhmeuh commented 4 years ago

Yes, I'm talking about background maps. The gameboy has a 32x32 tilemap that you can scroll (using rSCX and rSCY).

map: would create map data using the official 1-byte-per-tile format of the machine, while mask: would be used has a way to compress that data on the ROM in case you only need one type of tile, by using 1-bit-per-tile (thus allowing to save 8 times more maps in the same space).

A concrete example would be:

I have 2 different types of tiles: Grass and Water I want to generate a random map using layers of those two tiles. I'll create a first mask with patches of grass:

create GRASS-LAYER
mask: GRASS %00011000 %00000001 %10000000 %00000000
mask: GRASS %00111100 %00001111 %11100000 %00000000
mask: GRASS %00011100 %00000111 %11000001 %11000000
mask: GRASS %00000000 %00000000 %00000111 %10000000

Then I'll create some water streams:

create WATER-LAYER
mask: WATER %00000000 %00000000 %00000000 %00000000
mask: WATER %00000111 %11100000 %00000011 %11110000
mask: WATER %11111000 %00011000 %00111100 %00001000
mask: WATER %00000000 %00000111 %11000000 %00000111

Then I can load both of them on the real map using mask!video:

GRASS-LAYER mask!video 
WATER-LAYER mask!video

I would get a final result looking like this:

...ww..........ww...............
..www~~~~~~.wwwwwww...~~~~~~....
~~~~~w.....~~wwwww~~~~.www..~...
.............~~~~~...wwww....~~~
euhmeuh commented 4 years ago

Maybe we could also leave the tile identity to runtime:

create MASK01
mask: %00000000 %00000000 %00000000 %00000000
mask: %00000111 %11100000 %00000011 %11110000
mask: %11111000 %00011000 %00111100 %00001000
mask: %00000000 %00000111 %11000000 %00000111

: load-map
  MASK00 GRASS mask!video
  MASK01 WATER mask!video
;

So that you can create a lot of masks and reuse them with different tiles.

euhmeuh commented 4 years ago

But maybe I'll leave the mask thing out, and just provide a way to load maps. It seems the mask system is too tied to my game logic.

I'll put up a pull request soon.

tkers commented 4 years ago

I’d probably agree on that. While I understand the use case for it in your situation, it doesn’t seem to be a very general need.

That being said, looking forward to your contribution (and game!) :)