Let's explain here the basics of tilemapping in Axe. Note that this is not only applicable in Axe, since the concept can be explained without any code.

So, what is tilemapping ? It's a programming technique consisting in easily displaying a linear world all over the screen, while making it easily editable and interactive.

The basic format for sprites in Axe is 8*8 bit-encoded. The TI-8x+ screen is 96*64, so it's easy to divide it into subsets of 8*8 images, a tilemap (this tilemap will be 12*8, since 12*8 = 96 and 8*8 = 64. So you'll can put 12 tiles from left to right, and 8 tiles from top to bottom).

For now, let's write a loop to go all over the 12*8 cells of the screen :

Code:
:For(Y,0,7)
:For(X,0,11)
:.tilemapping here
:End
:End

Now that we know how to go all over the screen, let's fill it with black squares using this method :

Code:
:Repeat getKey(15)
:For(Y,0,7)
:For(X,0,11)
:Pt-On(X*8,Y*8,[FFFFFFFFFFFFFFFF])
:End
:End
:DispGraph
:End

Remember that one "tile" is a 8*8 image, so you have to multiply the X and Y coordinates of each tile by 8. Doing this, you just covered your screen with 8*8 black squares. You can also try something that looks better, for example some grass :

Code:
:Pt-On(X*8,Y*8,[0040202201110808])




You know that the point of tilemapping is to easily display a world out of a map and some sprites. Let's write those, shall we ?

First of all, the dimensions of our map. For now, we will restrain ourselves to maps that have the exact dimension of the screen, thus 12*8. Before writing the map, we have to create the tiles, because maps are made out of tiles, and not the contrary. So let's say that we have a grass tile, and 4 tiles that together make a house.


Code:
:[0040202201110808]→Pic1  // grass
:[0107196181818181]       // top-left of a house
:[80E0988681818181]       // top-right
:[818698E09E929692]       // bottom-left
:[8161190771517101]       // bottom-right


Now, let's write our map. A map is a two dimensional array made of tile numbers. Seeing how we arranged and ordered our tiles above, grass is number 0, top-left house is number 1, and so on until number 4 (bottom-right house). Note that the house is made of 4 tiles, so we must put those tiles in the right order on the map.


Code:
:[000000000000]→GDB1MAP
:[000000000000]
:[000000000000]
:[000001200000]
:[000003400000]
:[000000000000]
:[000000000000]
:[000000000000]


Now, we must go through each tile of the map (each character, because we choose to represent our map with one half of a byte for each tile, a nibble). To interact with nibbles instead of bytes, we use the nib{ command [math][→][3] : since there are twice as many nibbles as bytes (since a nibble is half a byte), all values that you expect to be in bytes must be doubled . Again, we use two nested For loops :


Code:
:For(Y,0,7)
:For(X,0,11)
:nib{Y*6+GDB1MAP*2+X}→Z      // with this, we have the tile situated at (X, Y) in Z ; since the map is 12 nibbles long we have to multiply Y by 12 (6 then 2) to go to the next line.
:Pt-On(X*8,Y*8,Z*8+Pic1)   // don't forget that a 8*8 bit-encoded image takes 8 bytes in memory
:End
:End


And here's the result of such code, with the tiles and map written above :



Now, you can try to display maps bigger than the screen with the arrow keys : all you have to do is to go through all tiles of the screen, and display the correct images in it.

Hope it helped Smile

EDIT : typo fixed in the last code sample
I seem to be unable to display it properly? Or i've done something wrong that I can't find..


Code:

:[0040202201110808]→Pic1
:[0107196181818181]
:[80E0988681818181]
:[818698E09E929692]
:[8161190771517101]
:
:[000000000000]→GDB1MAP
:[000000000000]
:[000000000000]
:[000001200000]
:[000003400000]
:[000000000000]
:[000000000000]
:[000000000000]
:
:repeat getKey(15)
:For(Y,0,7)
:For(X,0,11)
:nib{Y*6+GDB1MAP*2+X}→Z
:Pt-On(X*8,Y*8,Z*8+GDB1MAP)
:End
:End
:DispGraphClrDraw
:End
Looks like matrefeytntias made a small but critical code copying error in the rendering code. He used GDB1MAP as the sprite base pointer in the line Pt-On(X*8,Y*8,Z*8+GDB1MAP). This should really be Pt-On(X*8,Y*8,Z*8+Pic1).
Oh yeah Runer112 is right. I spotted that error when I wrote the code to take the screenshot, but I forgot to correct it in the tutorial. It's done now.
As my post yesterday was somehow not posted??
Anyways, I was wondering how I would check the space that the player is on, or is going, and return the value of that space that the player is on, on the tilemap, as a variable. (To stop the player from going places he shouldn't. Or to start an event, enter a door, etc,..)
Use the same line that is in the For loops to retrieve the active tile :
Code:
nib{Y*6+GDB1MAP*2+X}

or more generally :

nib{Y*width_of_the_map_in_bytes+pointer_to_the_map*2+X}
I'm curious how, if I were to NOT snap my character to a grid, and allow him to move freely, one pixel at a time.. How I would check the space that the character is standing on, or whatever space is adjacent to the character, seeing as though since that character can't move freely, it wouldn't be as easy as *8.
How would I go about that?
given i dont know much about axe, ill just throw you theory:

find out how many pixels each tile is in its width and length, then figure out how many you can fit lengthwise (<-->). figure height to prevent this little snippet of math from going off the LCD:


Code:

"widthmax"(Y-1)+X"

where widthmax is the number of tiles a single screen can hold lengthwise. this should give you a position for where a sprite is. for a freemoving sprite, all you need is to use X and Y for position and another X and Y (me using S and T, as they are right above X and Y) for offset. im not sure how much like this Axe can do, but thats my advice.

also, for maps that go off of the screen, just modify the code so that "widthmax" is the amount of tiles lengthwise that is in a map.
Using X, Y, S and T (or name them like you want) as LuxenD said should work. You can also notice that if A and B are the coordinates or the player pixel-wise (not tile-wise, I mean the player is on the pixel at (A,B)), then you have A=X*8+S and B=Y*8+T (where 8 is the width of a tile).
So instead of using 4 variables, you can use two and get the four numbers you need with a division and a modulo.
This is where I end up asking the same question.. :<

How would this look in code? / Can you give me examples..?
What I use to do to is to have a character moving pixel by pixel whose coordinates are (X,Y). I can retrieve the tile he is on with
Code:
nib{Y/8*MapWidth+MapPtr*2+(X/8)}
since a tile is 8*8 pixels.
Okay, time to type out the code!

Code:

.TESTING

//Initialization

32->S->T

[111111111111]->GDB1
[100000000001]
[100000000001]
[100000000001]
[111111000111]
[100000001111]
[100000011111]
[111111111111]

[0000000000000000]->Pic1
[FFFFFFFFFFFFFFFFFF]

//Loop

Repeat getKey(15)

For(Y,0,7)
For(x,0,11)
nib{Y*6+GDB1*2+X}->Z
Pt-On(X*8,Y*8,Z*8+Pic1)
End
End

Pt-On(S,T,[FFFFFFFFFFFFFFFF]

//Store the player coords to different variables for later

S->N
T->O

S-getKey(2)+getKey(3)->S
T-getKey(4)+getKey(1)->T

nib{T/8*12+GDB1*2+(S/8)}->U

//If the player is touching a space with the GDB1 value of 1, place him back where he used to be

If U=1
N->S
O->T
End

DispGraphClrDraw

End


Which doesn't work, sadly.. :<

Code:
nib{T/8*12+GDB1*2+(S/8)}->U
Remember your code uses nibbles, not bytes. So you must multiply T by 6, not 12, since nibbles are halves of bytes Wink

Also, remember that for now you only check one corner of your sprite. To perform accurate collision detection, you'd like to check all four.
I was thinking of using a For loop to do that, but is there a shorter way?
I don't think so. I don't really remember how I did collision checking though ; I guess I used a For loop to check the 4 corners.
I guess this is my brain not working..


Code:

For(A,0,7)
For(B,0,11)
nib{T+B/8*6+GDB1*2+(S+A/8)}->U

If U=1
N->S
O->T
End

End
End


But I can't see of a way to do it, and this definitely doesn't work :<
You don't have to bother check each pixel of your sprite, but only the 4 corners. One way to do it is this one :
Code:
:For(A,0,3)
:nib{A^2*7+T/8*6+GDB1*2+(A/2*7+S/8)}→U
:
:If U
:N→S
:O→T
:4→A      // also stop the For loop
:End
:End

What it will do is check in this order the pixels (S,T), (S+7,T), (S,T+7), (S+7,T+7), and if any of these pixels are on an 1 tile, the character gets back to where it was and the loop stops.
So now i've learned scrolling! Very Happy
Simply adding onto the amount of X or Y in the display of the map can solve that, and I know how to manipulate the numbers..
But another problem stemmed:

When I do the movement code, (Seeing that my map is 24x8), I only want the map to move left and right, which works, but my character is registered incorrectly..

Where I move my character doesn't register on where my character REALLY is, and it acts weird.

How would I move the map with my character, and accurately keep it centered around him, or only scroll on certain points..?
What you can do is do a test and only scroll the map if your character is at the center of the screen.

Also, don't forget to involve your scrolling variables into the tiles collision.
matrefeytontias wrote:
What you can do is do a test and only scroll the map if your character is at the center of the screen.

Also, don't forget to involve your scrolling variables into the tiles collision.


That's what I had meant to ask x.x
How would I test the collision with the scrolling included? & How to check when the screen needs to scroll?
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 2
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement