• Print

Author Topic: Tilemap drawing sub  (Read 506 times)

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Tilemap drawing sub
« on: February 26, 2013, 10:41:07 AM »
EDIT (March 02): Here is a great immediate-mode tile renderer. It only renders what is on screen, and it is super easy to use. It comes with a collision function. Thanks to everyone who offered suggestions and help.

Original message:

Hey, guys. A couple days ago, I reached an important realization about old 2D games, especially Nintendo games. They all use a grid-based tile system. So, I figured that since QB64-GL hasn't reached a stage where it supports fullscreen, GLSL, or any other nice graphical features, the best way to go about writing 2D games would be with tiles. So, to save myself and others the trouble of writing their own tile engines from scratch, I tried to make an immediate-mode tile renderer in one subroutine. It works by taking two source image files: one for the tilemap, and one for the tileset. It would use the pixel just below each tileset tile in a horizontal row as the color to represent that tile on the tilemap, so when it reads the tilemap it lines it up.

Unfortunately, it doesn't work quite right. First of all, nothing actually shows up on the screen when bit comes to blit. Secondly, the alignment of the tiles on screen seems to snap to a grid, which obviously is bad. I'm trying to make it so people can paste a tilemap to the screen like an image. Any help would be much appreciated.

Thank you.

Code: [Select]
'I declare this work to be public domain.

SCREEN _NEWIMAGE(640, 480, 32)

tmap& = _NEWIMAGE(2, 2)
_DEST tmap&

PRESET (0, 0), _RGB(0, 0, 0)
PRESET (1, 0), _RGB(255, 0, 0)
PRESET (0, 1), _RGB(0, 0, 255)
PRESET (1, 1), _RGB(0, 255, 0)

tset& = _NEWIMAGE(128, 33)
_DEST tset&

PRESET (0, 32), _RGB(0, 0, 0)
CIRCLE (16, 16), 5, _RGB(255, 255, 255)

PRESET (32, 32), _RGB(255, 0, 0)
CIRCLE (48, 16), 5, _RGB(255, 0, 0)

PRESET (64, 32), _RGB(0, 0, 255)
CIRCLE (80, 16), 5, _RGB(0, 0, 255)

PRESET (96, 32), _RGB(0, 255, 0)
CIRCLE (112, 16), 5, _RGB(0, 255, 0)

_DEST 0

DO
    drawtiles 50, 50, tmap&, tset&, 32, 32
    _DISPLAY
LOOP
SYSTEM

SUB drawtiles (posx%, posy%, tilemap&, tileset&, tilewidth%, tileheight%)
mapwidth% = _WIDTH(tilemap&)
mapheight% = _HEIGHT(tilemap&)

tilesnum% = _WIDTH(tileset&) / tilewidth%

oldsource& = _SOURCE

blocksx1% = posx% / tilewidth% - 1
IF blocksx1% < 0 THEN blocksx1% = 0
IF blocksx1% > mapwidth% - 1 THEN blocksx1% = mapwidth% - 1

blocksx2% = (posx% + _WIDTH(_DEST)) / tilewidth%
IF blocksx2% < 0 THEN blocksx2% = 0
IF blocksx2% > mapwidth% - 1 THEN blocksx2% = mapwidth% - 1

blocksy1% = posy% / tileheight% - 1
IF blocksy1% < 0 THEN blocksy1% = 0
IF blocksy1% > mapheight% - 1 THEN blocksy1% = mapheight% - 1

blocksy2% = (posy% + _HEIGHT(_DEST)) / tileheight%
IF blocksy2% < 0 THEN blocksy2% = 0
IF blocksy2% > mapheight% - 1 THEN blocksy2% = mapheight% - 1

FOR y% = blocksy1% TO blocksy2%
    FOR x% = blocksx1% TO blocksx2%
        _SOURCE tilemap&
        c& = POINT(x%, y%)
        'Offset of tiles on screen might not be right (snapped to a grid?)
        _SOURCE tileset&
        FOR i% = 1 TO tilesnum%
            IF c& = POINT((i% - 1) * tilewidth%, tileheight%) THEN EXIT FOR
        NEXT i%
        '_PUTIMAGE (x% * tilewidth%, y% * tileheight%), tileset&, , ((i% - 1) * tilewidth%, 0)-(i% * tilewidth% - 1, tileheight% - 1)
        ofx% = 1
        ofy% = 1
        LINE (x% * tilewidth% + ofx%, y% * tileheight% + ofy%)-((x% + 1) * tilewidth% + ofx%, (y% + 1) * tileheight% + ofy%), _RGB(0, 255, 0), BF
    NEXT x%
NEXT y%

_SOURCE oldsource&
END SUB
« Last Edit: March 02, 2013, 04:04:30 AM by fluffrabbit »

OlDosLover

  • Hero Member
  • *****
  • Posts: 3859
  • OlDosLover
    • Email
Re: Tilemap drawing sub (HELP?)
« Reply #1 on: February 26, 2013, 11:38:46 AM »
Hi all,
    I've run your code and it doesn't work as expected. I carnt make head nor tails out of the idea behind your code so i  dont know if the code is doing what is expected and where. Only thing i can suggest is to hard code another version of the sub instead of using variables use actual numbers hard coded and see how that works. Sorry i carnt be more help.
OlDosLover.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #2 on: February 26, 2013, 11:56:19 AM »
Quote from: OlDosLover on February 26, 2013, 11:38:46 AM
Hi all,
    I've run your code and it doesn't work as expected. I carnt make head nor tails out of the idea behind your code so i  dont know if the code is doing what is expected and where. Only thing i can suggest is to hard code another version of the sub instead of using variables use actual numbers hard coded and see how that works. Sorry i carnt be more help.
OlDosLover.


Picture if you will a 128x33 pixel tileset. If you've used RPG Maker, you know what this is. In it are 4 32x32 tiles and 1 pixel row of padding at the bottom. Another image, the tilemap, is a 2x2 pixel bitmap. This tiny thing represents 4 different tiles, in the end making a 64x64 image. The drawtiles function is optimized to only render what tiles are on the screen, for speed reasons. For each of the tiles on the screen, it reads the pixel color and tries to determine which tile to put there. What I should be seeing is 4 circles of different colors offset from position 50,50. Notice these two lines:

Code: [Select]
        ofx% = 1
        ofy% = 1

The "1" is a placeholder value that should be changed to whatever the offset is on that axis for the tiles on the screen. The other main problem is that no tiles are actually drawn, which is why I have replaced the _PUTIMAGE command with a green box temporarily. The other other main problem is that only one green box appears, with a size of 32x32, when in fact there should be 4 times the green box.

Does this help you understand better?

OlDosLover

  • Hero Member
  • *****
  • Posts: 3859
  • OlDosLover
    • Email
Re: Tilemap drawing sub (HELP?)
« Reply #3 on: February 26, 2013, 12:12:16 PM »
Hi all,
    The concept is becoming clearer. I've never used RPG maker. Its 6 AM here and im tired.
OlDosLover.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #4 on: February 26, 2013, 12:15:10 PM »
Quote from: OlDosLover on February 26, 2013, 12:12:16 PM
Hi all,
    The concept is becoming clearer. I've never used RPG maker. Its 6 AM here and im tired.
OlDosLover.

Basically, what I am trying to make is a sub that draws a composite image to the screen. It takes tiles from one image and lines them up according to another image.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #5 on: February 26, 2013, 06:24:01 PM »
bump

TerryRitchie

  • Hero Member
  • *****
  • Posts: 2264
  • FORMAT C:\ /Q /U /AUTOTEST (How to repair Win8)
    • Email
Re: Tilemap drawing sub (HELP?)
« Reply #6 on: February 26, 2013, 07:26:36 PM »
Download my sprite library.  It does pretty much what you're looking for.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #7 on: February 26, 2013, 08:20:04 PM »
Quote from: TerryRitchie on February 26, 2013, 07:26:36 PM
Download my sprite library.  It does pretty much what you're looking for.

Your sprite library is too complicated and bulky for what I'm trying to do. I knew that you would come into this thread sooner or later, but sorry, NO.

I've made tile-based games before, but never in immediate mode like this. That's what makes this special. Somebody please tell me what the hell is going on.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #8 on: February 26, 2013, 11:31:04 PM »
bump

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #9 on: February 27, 2013, 12:48:52 AM »
bump

OlDosLover

  • Hero Member
  • *****
  • Posts: 3859
  • OlDosLover
    • Email
Re: Tilemap drawing sub (HELP?)
« Reply #10 on: February 27, 2013, 01:17:09 AM »
Hi all,
    I carnt get the point in the for next to align with established numbers.
Code: [Select]
'I declare this work to be public domain.

SCREEN _NEWIMAGE(640, 480, 32)

tmap& = _NEWIMAGE(2, 2)
_DEST tmap&

PRESET (0, 0), _RGB(0, 0, 0)
PRESET (1, 0), _RGB(255, 0, 0)
PRESET (0, 1), _RGB(0, 0, 255)
PRESET (1, 1), _RGB(0, 255, 0)
_SOURCE tmap&
aa& = -16777216
bb& = -65536
cc& = -16776961
dd& = -16711936

z1& = POINT(0, 0)
z2& = POINT(1, 0)
z3& = POINT(0, 1)
z4& = POINT(1, 1)
z5~& = POINT(0, 0)
z6~& = POINT(1, 0)
z7~& = POINT(0, 1)
z8~& = POINT(1, 1)

_DEST 0
PRINT z1&
PRINT z2&
PRINT z3&
PRINT z4&
PRINT
PRINT z5~&
PRINT z6~&
PRINT z7~&
PRINT z8~&
PRINT "Press a jey to continue"
dummy$ = INPUT$(1)

tset& = _NEWIMAGE(128, 33)
_DEST tset&

PRESET (0, 32), _RGB(0, 0, 0)
CIRCLE (16, 16), 5, _RGB(255, 255, 255)

PRESET (32, 32), _RGB(255, 0, 0)
CIRCLE (48, 16), 5, _RGB(255, 0, 0)

PRESET (64, 32), _RGB(0, 0, 255)
CIRCLE (80, 16), 5, _RGB(0, 0, 255)

PRESET (96, 32), _RGB(0, 255, 0)
CIRCLE (112, 16), 5, _RGB(0, 255, 0)


_DEST 0

DO
  drawtiles 50, 50, tmap&, tset&, 32, 32
  _DISPLAY
LOOP
SYSTEM

SUB drawtiles (posx%, posy%, tilemap&, tileset&, tilewidth%, tileheight%)
mapwidth% = _WIDTH(tilemap&)
mapheight% = _HEIGHT(tilemap&)

tilesnum% = _WIDTH(tileset&) / tilewidth%

oldsource& = _SOURCE

blocksx1% = posx% / tilewidth% - 1
IF blocksx1% < 0 THEN blocksx1% = 0
IF blocksx1% > mapwidth% - 1 THEN blocksx1% = mapwidth% - 1

blocksx2% = (posx% + _WIDTH(_DEST)) / tilewidth%
IF blocksx2% < 0 THEN blocksx2% = 0
IF blocksx2% > mapwidth% - 1 THEN blocksx2% = mapwidth% - 1

blocksy1% = posy% / tileheight% - 1
IF blocksy1% < 0 THEN blocksy1% = 0
IF blocksy1% > mapheight% - 1 THEN blocksy1% = mapheight% - 1

blocksy2% = (posy% + _HEIGHT(_DEST)) / tileheight%
IF blocksy2% < 0 THEN blocksy2% = 0
IF blocksy2% > mapheight% - 1 THEN blocksy2% = mapheight% - 1

FOR y% = blocksy1% TO blocksy2%
  FOR x% = blocksx1% TO blocksx2%
    _SOURCE tilemap&
    c& = POINT(x%, y%)
    IF c& = z1& THEN SOUND 600, 1
    IF c& = z2& THEN SOUND 800, 1
    IF c& = z3& THEN SOUND 1000, 1
    IF c& = z4& THEN SOUND 1200, 1
    _DELAY 1
    'Offset of tiles on screen might not be right (snapped to a grid?)
    _SOURCE tileset&
    FOR i% = 1 TO tilesnum%
      IF c~& = POINT((i% - 1) * tilewidth%, tileheight%) THEN EXIT FOR
    NEXT i%
    '_PUTIMAGE (x% * tilewidth%, y% * tileheight%), tileset&, , ((i% - 1) * tilewidth%, 0)-(i% * tilewidth% - 1, tileheight% - 1)
    ofx% = 1
    ofy% = 1
    LINE (x% * tilewidth% + ofx%, y% * tileheight% + ofy%)-((x% + 1) * tilewidth% + ofx%, (y% + 1) * tileheight% + ofy%), _RGB(0, 255, 0), BF
  NEXT x%
NEXT y%

_SOURCE oldsource&
END SUB
OlDosLover.

OlDosLover

  • Hero Member
  • *****
  • Posts: 3859
  • OlDosLover
    • Email
Re: Tilemap drawing sub (HELP?)
« Reply #11 on: February 27, 2013, 01:27:50 AM »
Hi all,
    This illustrates it better.
Code: [Select]
'I declare this work to be public domain.

SCREEN _NEWIMAGE(640, 480, 32)

tmap& = _NEWIMAGE(2, 2)
_DEST tmap&

PRESET (0, 0), _RGB(0, 0, 0)
PRESET (1, 0), _RGB(255, 0, 0)
PRESET (0, 1), _RGB(0, 0, 255)
PRESET (1, 1), _RGB(0, 255, 0)
_SOURCE tmap&
aa& = -16777216
bb& = -65536
cc& = -16776961
dd& = -16711936

z1& = POINT(0, 0)
z2& = POINT(1, 0)
z3& = POINT(0, 1)
z4& = POINT(1, 1)
z5~& = POINT(0, 0)
z6~& = POINT(1, 0)
z7~& = POINT(0, 1)
z8~& = POINT(1, 1)

_DEST 0
PRINT z1&
PRINT z2&
PRINT z3&
PRINT z4&
PRINT
PRINT z5~&
PRINT z6~&
PRINT z7~&
PRINT z8~&
PRINT "Press a jey to continue"
dummy$ = INPUT$(1)

tset& = _NEWIMAGE(128, 33)
_DEST tset&

PRESET (0, 32), _RGB(0, 0, 0)
CIRCLE (16, 16), 5, _RGB(255, 255, 255)

PRESET (32, 32), _RGB(255, 0, 0)
CIRCLE (48, 16), 5, _RGB(255, 0, 0)

PRESET (64, 32), _RGB(0, 0, 255)
CIRCLE (80, 16), 5, _RGB(0, 0, 255)

PRESET (96, 32), _RGB(0, 255, 0)
CIRCLE (112, 16), 5, _RGB(0, 255, 0)


_DEST 0

DO
  drawtiles 50, 50, tmap&, tset&, 32, 32
  _DISPLAY
LOOP
SYSTEM

SUB drawtiles (posx%, posy%, tilemap&, tileset&, tilewidth%, tileheight%)
mapwidth% = _WIDTH(tilemap&)
mapheight% = _HEIGHT(tilemap&)

tilesnum% = _WIDTH(tileset&) / tilewidth%

oldsource& = _SOURCE

blocksx1% = posx% / tilewidth% - 1
IF blocksx1% < 0 THEN blocksx1% = 0
IF blocksx1% > mapwidth% - 1 THEN blocksx1% = mapwidth% - 1

blocksx2% = (posx% + _WIDTH(_DEST)) / tilewidth%
IF blocksx2% < 0 THEN blocksx2% = 0
IF blocksx2% > mapwidth% - 1 THEN blocksx2% = mapwidth% - 1

blocksy1% = posy% / tileheight% - 1
IF blocksy1% < 0 THEN blocksy1% = 0
IF blocksy1% > mapheight% - 1 THEN blocksy1% = mapheight% - 1

blocksy2% = (posy% + _HEIGHT(_DEST)) / tileheight%
IF blocksy2% < 0 THEN blocksy2% = 0
IF blocksy2% > mapheight% - 1 THEN blocksy2% = mapheight% - 1

FOR y% = blocksy1% TO blocksy2%
  FOR x% = blocksx1% TO blocksx2%
    _SOURCE tilemap&
    c& = POINT(x%, y%)
    PRINT c&
    IF c& = z1& THEN SOUND 600, 1
    IF c& = z2& THEN SOUND 800, 1
    IF c& = z3& THEN SOUND 1000, 1
    IF c& = z4& THEN SOUND 1200, 1
    cc~& = POINT(x%, y%)
    IF cc~& = z5& THEN SOUND 1400, 1
    IF cc~& = z6& THEN SOUND 1500, 1
    IF cc~& = z7& THEN SOUND 1600, 1
    IF cc~& = z8& THEN SOUND 1700, 1

    _DELAY 1
    'Offset of tiles on screen might not be right (snapped to a grid?)
    _SOURCE tileset&
    FOR i% = 1 TO tilesnum%
      IF c~& = POINT((i% - 1) * tilewidth%, tileheight%) THEN EXIT FOR
    NEXT i%
    '_PUTIMAGE (x% * tilewidth%, y% * tileheight%), tileset&, , ((i% - 1) * tilewidth%, 0)-(i% * tilewidth% - 1, tileheight% - 1)
    ofx% = 1
    ofy% = 1
    'LINE (x% * tilewidth% + ofx%, y% * tileheight% + ofy%)-((x% + 1) * tilewidth% + ofx%, (y% + 1) * tileheight% + ofy%), _RGB(0, 255, 0), BF
  NEXT x%
NEXT y%

_SOURCE oldsource&
END SUB
OlDosLover.

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #12 on: February 27, 2013, 01:42:55 AM »
@OlDosLover-

I'm sorry, but that code fails to enlighten me. I see a bunch of numbers. Those numbers could either be colors or memory pointers, because they're really big. I don't get it. I just want my sub to do what I say it does.

OlDosLover

  • Hero Member
  • *****
  • Posts: 3859
  • OlDosLover
    • Email
Re: Tilemap drawing sub (HELP?)
« Reply #13 on: February 27, 2013, 01:51:25 AM »
Hi all,
   
Quote
I'm sorry, but that code fails to enlighten me. I see a bunch of numbers. Those numbers could either be colors or memory pointers, because they're really big. I don't get it.
Thats exactly how i felt reading your code. Because im not privy to what's in your mind it very difficult to imagine whats spose to be happening at each step.

Code: [Select]
FOR y% = blocksy1% TO blocksy2%
  FOR x% = blocksx1% TO blocksx2%
    _SOURCE tilemap&
Inside these loops it comes to a comparison by a value obtained by point. None of the colors seem to be detected as the same!
OlDosLover,

fluffrabbit

  • Sr. Member
  • ****
  • Posts: 393
Re: Tilemap drawing sub (HELP?)
« Reply #14 on: February 27, 2013, 03:37:13 AM »
Quote from: OlDosLover on February 27, 2013, 01:51:25 AM
Hi all,
   
Quote
I'm sorry, but that code fails to enlighten me. I see a bunch of numbers. Those numbers could either be colors or memory pointers, because they're really big. I don't get it.
Thats exactly how i felt reading your code. Because im not privy to what's in your mind it very difficult to imagine whats spose to be happening at each step.

Code: [Select]
FOR y% = blocksy1% TO blocksy2%
  FOR x% = blocksx1% TO blocksx2%
    _SOURCE tilemap&
Inside these loops it comes to a comparison by a value obtained by point. None of the colors seem to be detected as the same!
OlDosLover,

As the old saying goes, it's harder to read code than to write it.

What it's supposed to be doing is going from the least x tile pos to the most x tile pos and likewise on the y axis. Each tile/pixel on the map, it scans through the other image to find the right tile segment for that tile, so if it's blue it looks for the blue one. If it's green it looks for the green one.

  • Print