Author Topic: New Tilemapping Tutorial With Example  (Read 12326 times)

0 Members and 1 Guest are viewing this topic.

Offline yunhua98

  • You won't this read sentence right.
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2718
  • Rating: +214/-12
  • Go take a dive in the River Lethe.
    • View Profile
New Tilemapping Tutorial With Example
« on: March 11, 2011, 04:18:08 pm »
Note:  Anyone can put this tutorial on their website/blog/etc as long as they credit me and link it here.  You probably want to include the example programs as well.  ;)

First, Clarifications:
-Can be used for RPGs
-Harder to use for platformers, but probably doable
-Allows for 255 different types of tiles in one map (more than enough.   :P)
-Easy map switching
-Implemented smoothscrolling in example can be taken out.
-Easily convertible to Greyscale
-This isn't the best code, if you can optimize it go ahead, I just can't explain it well if its too optimized.  ;)
-I left out a couple of "0C"s in the data, I could leave out more, I know.  :P
-All example code is from the example program unless said otherwise.

Now, for the Tutorial:

Store your sprite data:

I find it easiest to store the Character sprites first.  Point the first one to Pic1 and let the rest be relative to that pointer.
After that, point the "ground tile" to Pic0.  This tile will be represented by "00" later in the data.  This tile is also the one you can always walk on.
The other tiles will also be relative to this pointer, increasing by 8 to get to the next tile.  This is more organized if you comment above each piece of data, saying what it is and what number it is.  Remember to count in Hex here.

Code: [Select]
:.CHARACTER
:.HEADFRONT
:[7E7E99A5A5423C42]→Pic1
:.BODYFRONT
:[81A5A5A5425A6666]
:[81A5A5A5425A6760]
:[81A5A5A5425AE606]
:
:.HEADRIGHT
:[3C7EF1C585423C42]
:.BODYRIGHT
:[4A4A45452624241C]
:[4A4A45452654B2EC]
:[4A4A45252624241C]
:
:.HEADLEFT
:[3C7E8FA3A1423C42]
:.BODYLEFT
:[5252A2A264242438]
:[5252A2A2642C4A76]
:[5252A2A464242438]
:
:.HEADBACK
:[7E7EB9B191423C42]
:.BODYBACK
:[81A5A5A5425A6666]
:[81A5A5A5425A6760]
:[81A5A5A5425AE606]
:
:
:.STORE YOUR SPRITE DATA FIRST, I'M ASSUMMING YOU WANT MONOCHROME SPRITES
:.EXAMPLE SPRITES
:.GROUND TILE,0 THIS IS THE NUMBER THAT WILL REPRESENT THE TILE
:[00A04000000A0400]→Pic0
:
:.TREE,1
:[186689A14A3C2442]
:
:.HOUSE,2,3,4,5,6,7,8,9,A SOME OBJECTS NEED MORE THAN ONE TILE, AND THE A IS 10 IN BASE 16
:[03060A1A2A6AAAAA]
:[FF00000000000000]
:[C060505854565555]
:[ABACABB4A8D2A5C2]
:[FF00FF000000007E]
:[D535D52D154BA543]
:[407F407F407F403F]
:[8181A1A1818181FF]
:[02FE02FE02FE02FC]
:
:.PATH,B
:[8181818181818181]
:
:.BLACK BOUDARIES,C
:[FFFFFFFFFFFFFFFF]

Next, keeping the number for each tile in mind, write them out and lay it out like a map, as in:

Code: [Select]
:.MAP DATA, REMBER THOSE NUMBERS? ADD 0's RIGHT BEFORE THEM, AND STORE THEM TO A POINTER
:[0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C]→GDB1
:[0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C]
:[0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C]
:[0C0C0C0C010101010101010101010101010101010C0C0C0C]
:[0C0C0C0C010000000000000000000000000000010C0C0C0C]
:[0C0C0C0C010000000000000000000000000000010C0C0C0C]
:[0C0C0C0C010000000000000000000000000000010C0C0C0C]
:[0C0C0C0C010000000203040000000000000000010C0C0C0C]
:[0C0C0C0C010000000506070000000000000000010C0C0C0C]
:[0C0C0C0C0100000008090A0000000000000000010C0C0C0C]
:[0C0C0C0C01000000000B000000000000000000010C0C0C0C]
:[0C0C0C0C01000000000B000000000000000000010C0C0C0C]
:[0C0C0C0C01000000000B000000000000000000010C0C0C0C]
:[0C0C0C0C010000000000000000000000000000010C0C0C0C]
:[0C0C0C0C010000000000000000000000000000010C0C0C0C]
:[0C0C0C0C010000000000000000000000000000010C0C0C0C]
:[0C0C0C0C010000000000000000000000000000010C0C0C0C]
:[0C0C0C0C010000000000000000000000000000010C0C0C0C]
:[0C0C0C0C010101010101010101010101010101010C0C0C0C]
:[0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C]
:[0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C]

Looking back, remember the "0C"s are boundaries, "01"s are trees, and "00"s are ground tile, etc.
Too keep it organized, I suggest entering the data for each row on a separate line.  Point the first one to GDB1, and let the rest be relative.
When you enter another map, point it to a different GDB, and when you switch maps, Copy a map to a temp pointer, such as GDB0, and just always use GDB0 when mapping.

<hr>

Movement engine:

Keep in mind that this engine is written such that your character stays in the same location on screen, and the map moves around him.


Zero the pointers you need to be 0 first
Code: [Select]
:.P AND Q ARE THE LOCATION OR THE TOP CORNER OF THE MAP DATA
:0→P→Q→V→H→I→J→θ→{r1}
The {r1} is the one in VARS>Y-VARS>Polar>r1, its the variable telling how much the character pointer should add to to display a sprite facing the direction your moving.
The P and Q are the "psuedo-coordinates" of the top corner of the screen on the map data.  We're basically pretending its an array.  So P=0 and Q=0 would correspond to the tile in the top left corner being a "0C" tile, or, a black one.  And the rest of the tiles shown on the screen will be relative to that.  Just look at the "array", and go down Q rows and go right P bytes, a byte being two digits.

V, H, I, and J are just variable to make sure each time you press a arrow key, you only go to a direction 8 pixels at a time, but with smooth scrolling.  The smooth scrolling will be better explained later on.

Code: [Select]
:Repeat getKey(15)
:
:Z→Y
:
:Q*24+P+126→Z
:
:.P+(getKey(3) and (({Z+1+GDB1}=0) or ({Z+1+GDB1}=11)))-(getKey(2) and (({Z-1+GDB1}=0) or ({Z-1+GDB1}=11)))→P
:
:.Q*24+P+101→Z
:.Q+(getKey(1) and (({Z+24+GDB1}=0) or ({Z+24+GDB1}=11)))-(getKey(4) and (({Z-24+GDB1}=0) or ({Z-24+GDB1}=11)))→Q
:
:If getKey(3) and (I=0) and (J=0) and (({Z+1+GDB1}=0) or ({Z+1+GDB1}=11))
:1→I
:32→{r1}
:End
:If getKey(2) and (I=0) and (J=0) and (({Z-1+GDB1}=0) or ({Z-1+GDB1}=11))
:0-1→I
:64→{r1}
:End
:If getKey(1) and (I=0) and (J=0) and (({Z+24+GDB1}=0) or ({Z+24+GDB1}=11))
:1→J
:0→{r1}
:End
:If getKey(4) and (I=0) and (J=0) and (({Z-24+GDB1}=0) or ({Z-24+GDB1}=11))
:0-1→J
:96→{r1}
:End
:
:If getKey(1) or (getKey(2)) or (getKey(3)) or (getKey(4)
:θ+1→θ
:Else
:0→θ
:End
:
:H+I+I→H
:V+J+J→V
:
:If H-8=0 or (H+8=0
:P+I→P
:0→H→I
:End
:If V-8=0 or (V+8=0
:Q+J→Q
:0→V→J
:End
:
:.If Y≠Z
:sub(MAP)
:.End
:
:Pt-Off(40,32,Pic1+8+(θ/4^2*8+8*(θ≠0))+{r1}
:Pt-Off(40,24,Pic1+{r1}
:
:DispGraph
:
:End

The parts that are commented out are for scrolling by 8 pixels at a time (i.e. not smooth scrolling)  Uncomment those and comment/delete the If clauses with getkey(1-4) in them.  (but not the one that involves storing things into theta)

Smooth Scrolling:
H and V are constantly being incremented by I and J respectively.  When you aren't moving, I and J are 0, when you move, I and J change to (-)1 depending where you're going.  When H or V equal 8, they get reset to 0 and 8 is added/subtracted to/from P or Q, depending on whether you went Horizontally or Vertically.

Collision detection:
Collision detection is a simple matter of finding out where you are on our "array" and checking whats above, below, and beside you.  to find the number of bytes you are away from GDB1, you would take Q, multiply it by you "array's" width, add P, and add 101, in this case, since that gets you from the top corner of the screen to the place where your body is.  Now, just check if {Z (the variable with your distance from GDB1) plus GDB1 +/- 1/[width of your array]}  To check to your left/right, +/- 1, to check above and below, +/- 24, in this case, that being the width of our "array."

<hr>
Map Drawing

You may have noticed the "sub(MAP)" in the above code, calling the subroutine "MAP."

The map routine is very simple.  Use the vars P and Q to find the distance from GDB1 to the top left corner of your screen, as shown in below source.  And then use two for loops to increment by 1 to find the next tile, until you reach 12 tiles, and then skip to the next line, and display 12 tiles, and display 8 rows of twelve tiles.

Code: [Select]
:Lbl MAP
:
:Q*24+P→Z
:
:ClrDraw
:For(B,0,9
:For(A,0,13
:Pt-On(A*8-8-H,B*8-8-V,{B*24+A+Z+GDB1}*8+Pic0
:End
:End

Attached below is a screenie of the Example program and the source/executable
« Last Edit: August 26, 2011, 11:06:56 pm by yunhua98 »

Spoiler For =====My Projects=====:
Minor setback due to code messing up.  On hold for Contest.
<hr>
On hold for Contest.


Spoiler For ===Staff Memberships===:






Have you seen any good news-worthy programs/events?  If so, PM me with an article to be included in the next issue of CGPN!
The Game is only a demo, the code that allows one to win hasn't been done.
To paraphrase Oedipus, Hamlet, Lear, and all those guys, "I wish I had known this some time ago."
Signature Last Updated: 12/26/11
<hr>

Offline Munchor

  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 6199
  • Rating: +295/-121
  • Code Recycler
    • View Profile
Re: New Tilemapping Tutorial With Example
« Reply #1 on: March 11, 2011, 04:20:02 pm »
I didn't read all of it yet, but this is awesome, just pure awesome, I'm gonna learn tilemapping now (which I never learnt).

Offline yunhua98

  • You won't this read sentence right.
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2718
  • Rating: +214/-12
  • Go take a dive in the River Lethe.
    • View Profile
Re: New Tilemapping Tutorial With Example
« Reply #2 on: March 11, 2011, 04:21:04 pm »
thanks, if its a bit unclear, just ask in this thread, and I'll elaborate and probably edit the first post to clarify.  ;)

Spoiler For =====My Projects=====:
Minor setback due to code messing up.  On hold for Contest.
<hr>
On hold for Contest.


Spoiler For ===Staff Memberships===:






Have you seen any good news-worthy programs/events?  If so, PM me with an article to be included in the next issue of CGPN!
The Game is only a demo, the code that allows one to win hasn't been done.
To paraphrase Oedipus, Hamlet, Lear, and all those guys, "I wish I had known this some time ago."
Signature Last Updated: 12/26/11
<hr>

Offline Munchor

  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 6199
  • Rating: +295/-121
  • Code Recycler
    • View Profile
Re: New Tilemapping Tutorial With Example
« Reply #3 on: March 11, 2011, 04:24:47 pm »
Code: [Select]
:.P+(getKey(3) and (({Z+1+GDB1}=0) or ({Z+1+GDB1}=11)))-(getKey(2) and (({Z-1+GDB1}=0) or ({Z-1+GDB1}=11)))→P
:
:.Q*24+P+101→Z
:.Q+(getKey(1) and (({Z+24+GDB1}=0) or ({Z+24+GDB1}=11)))-(getKey(4) and (({Z-24+GDB1}=0) or ({Z-24+GDB1}=11)))→Q
:

This is my first question, why are these as comments?

Also, what does Pt-Off does?

Code: [Select]
:Pt-Off(40,32,Pic1+8+(θ/4^2*8+8*(θ≠0))+{r1}
:Pt-Off(40,24,Pic1+{r1}

Like in here.

Offline yunhua98

  • You won't this read sentence right.
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2718
  • Rating: +214/-12
  • Go take a dive in the River Lethe.
    • View Profile
Re: New Tilemapping Tutorial With Example
« Reply #4 on: March 11, 2011, 04:30:11 pm »
Those are commented so you guys have an option.
Quote
The parts that are commented out are for scrolling by 8 pixels at a time (i.e. not smooth scrolling)  Uncomment those and comment/delete the If clauses with getkey(1-4) in them.  (but not the one that involves storing things into theta)

;)

Pt-Off is Pt-on, but it overwrites everyting behind it, so if you had
Code: [Select]
:Pt-on(0,0,[FFFFFFFFFFFFFFFF]
:Pt-off(0,0,[0000000000000000]
:Dispgraph
It would not show anything.

Spoiler For =====My Projects=====:
Minor setback due to code messing up.  On hold for Contest.
<hr>
On hold for Contest.


Spoiler For ===Staff Memberships===:






Have you seen any good news-worthy programs/events?  If so, PM me with an article to be included in the next issue of CGPN!
The Game is only a demo, the code that allows one to win hasn't been done.
To paraphrase Oedipus, Hamlet, Lear, and all those guys, "I wish I had known this some time ago."
Signature Last Updated: 12/26/11
<hr>

Offline Munchor

  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 6199
  • Rating: +295/-121
  • Code Recycler
    • View Profile
Re: New Tilemapping Tutorial With Example
« Reply #5 on: March 11, 2011, 04:32:00 pm »
1. /facepalm, read the text and the code;
2. Thanks much for the Pt-Off.

Offline DJ Omnimaga

  • Former TI programmer
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55833
  • Rating: +3151/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • DJ Omnimaga Music
Re: New Tilemapping Tutorial With Example
« Reply #6 on: March 12, 2011, 02:07:01 am »
Oh thanks for posting this. This might be useful if I eventually coded again. Could you maybe do one with half-bytes/nibbles tilemapping format?
In case you are wondering where I went, I left Omni back in 2015 to form CodeWalrus due to various reasons explained back then, but I stopped calc dev in 2016 and am now mostly active on the CW Discord server at https://discord.gg/cuZcfcF



Official Website |T-Shirt store | Reverbnation | Facebook | Youtube | Twitter | Spotify

Offline Darl181

  • «Yo buddy, you still alive?»
  • CoT Emeritus
  • LV12 Extreme Poster (Next: 5000)
  • *
  • Posts: 3408
  • Rating: +305/-13
  • VGhlIEdhbWU=
    • View Profile
    • darl181.webuda.com
Re: New Tilemapping Tutorial With Example
« Reply #7 on: March 12, 2011, 02:16:41 am »
Wow, this is cool ;D
Is there a way to make this work with height/width that varies in different levels (reading from an appvar stored row-by-row)?
Vy'o'us pleorsdti thl'e gjaemue

Offline aeTIos

  • Nonbinary computing specialist
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 3913
  • Rating: +184/-32
    • View Profile
    • wank.party
Re: New Tilemapping Tutorial With Example
« Reply #8 on: March 12, 2011, 10:10:26 am »
Nice tutorial Yunhua!

I have one thing you should probably mention, that is that you can also use 'Data(' to input maps, some people might find this more convenient.
I'm not a nerd but I pretend:

Offline ztrumpet

  • The Rarely Active One
  • CoT Emeritus
  • LV13 Extreme Addict (Next: 9001)
  • *
  • Posts: 5712
  • Rating: +364/-4
  • If you see this, send me a PM. Just for fun.
    • View Profile
Re: New Tilemapping Tutorial With Example
« Reply #9 on: March 12, 2011, 12:03:45 pm »
Wow, looks great.  Wonderful job, yunhua! ;D

Offline yunhua98

  • You won't this read sentence right.
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2718
  • Rating: +214/-12
  • Go take a dive in the River Lethe.
    • View Profile
Re: New Tilemapping Tutorial With Example
« Reply #10 on: March 12, 2011, 06:07:21 pm »
Thanks guys!  As for nibbles, I'm not very good with those yet, but I'll probably look in to those anyway.  But if I used nibbles, wouldn't I be limited to like 16 different tiles?  D:

Spoiler For =====My Projects=====:
Minor setback due to code messing up.  On hold for Contest.
<hr>
On hold for Contest.


Spoiler For ===Staff Memberships===:






Have you seen any good news-worthy programs/events?  If so, PM me with an article to be included in the next issue of CGPN!
The Game is only a demo, the code that allows one to win hasn't been done.
To paraphrase Oedipus, Hamlet, Lear, and all those guys, "I wish I had known this some time ago."
Signature Last Updated: 12/26/11
<hr>

Offline DJ Omnimaga

  • Former TI programmer
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55833
  • Rating: +3151/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • DJ Omnimaga Music
Re: New Tilemapping Tutorial With Example
« Reply #11 on: March 13, 2011, 04:38:23 am »
Indeed, but most dungeons won't require more than 16 anyway, so people could simply use tile palettes.
In case you are wondering where I went, I left Omni back in 2015 to form CodeWalrus due to various reasons explained back then, but I stopped calc dev in 2016 and am now mostly active on the CW Discord server at https://discord.gg/cuZcfcF



Official Website |T-Shirt store | Reverbnation | Facebook | Youtube | Twitter | Spotify

Offline Yeong

  • Not a bridge
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 3739
  • Rating: +278/-12
  • Survivor of Apocalypse
    • View Profile
Re: New Tilemapping Tutorial With Example
« Reply #12 on: March 17, 2011, 09:03:20 pm »
it says delete if clasuse made out of getkey(1)~getkey(4) except for theta one.
Which part exactly should I delete?  ???
just the if one itself?
Sig wipe!

Offline yunhua98

  • You won't this read sentence right.
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2718
  • Rating: +214/-12
  • Go take a dive in the River Lethe.
    • View Profile
Re: New Tilemapping Tutorial With Example
« Reply #13 on: March 18, 2011, 03:36:47 pm »
The ones where its like:
Code: [Select]
:If getkey(1) and [some other conditions]
:blah
:End
:If getkey(2) and [conditions]
:blah
:End
delete those, from getkey(1)-getkey(4), but don't deleted the one involving storing into theta.

Spoiler For =====My Projects=====:
Minor setback due to code messing up.  On hold for Contest.
<hr>
On hold for Contest.


Spoiler For ===Staff Memberships===:






Have you seen any good news-worthy programs/events?  If so, PM me with an article to be included in the next issue of CGPN!
The Game is only a demo, the code that allows one to win hasn't been done.
To paraphrase Oedipus, Hamlet, Lear, and all those guys, "I wish I had known this some time ago."
Signature Last Updated: 12/26/11
<hr>

Ashbad

  • Guest
Re: New Tilemapping Tutorial With Example
« Reply #14 on: March 18, 2011, 03:41:45 pm »


Code: [Select]
:Lbl MAP
:
:Q*24+P→Z
:
:ClrDraw
:For(A,0,139
:Pt-On(A^14*8-8-H,A/14*8-8-V,{A/14*24+(A^14)+Z+GDB1}*8+Pic0
:End
:End

'twas bored, so I made it run on a single loop.  I think it's actually smaller, but slower.  No idea.