Omnimaga

Calculator Community => TI Calculators => Axe => Topic started by: MRide on July 28, 2010, 12:17:03 pm

Title: Tilemap scrolling
Post by: MRide on July 28, 2010, 12:17:03 pm
Thanks to SirCmpwn and nemo, I was able to write a tilemap display routine.  I then added scrolling by one tile at a time (as opposed to one pixel.)
Here is the code:

Code: [Select]
:.ATILMAP
:[11111111111111111111→GDB1
:[10001000000000000001
:[10000100000000000001
:[10000001000000000001
:[10000000001000000001
:[10001000000000000001
:[10000010000000000001
:[10000000000000000001
:[10010000000000000001
:[10100000000000000001
:[10000000000000000101
:[11111111111111111111
:[55AA55AA55AA55AA→Pic1
:[FFFFFFFFFFFFFFFF
:0→S→D→U
:ClrDraw
:sub(DS)
:Repeat getKey(15)
:If D<40 and getKey(1)
:20+D→U
:End
:If D≠0 and getKey(4)
:D-20→U
:End
:S+(S<4 and getKey(3))-(S≠0 and getKey(2))→T
:If D≠U or (S≠T)
:U→D
:T→S
:ClrDraw
:End
:sub(DS)
:End
:Return
:Lbl DS
:For(Y,0,7)
:For(X,0,11)
:{Y*10+X+GDB1+D+S}→A
:Pt-On(X*16,Y*8,A/16*8+Pic1
:Pt-On(X*16+8,Y*8,A^16*8+Pic1
:End
:End
:DispGraph

For some reason, it skips two tiles at a time.  So far, I have been unable to figure out why this is.
Title: Re: Tilemap scrolling
Post by: nemo on July 28, 2010, 03:44:10 pm
by changing
Code: [Select]
:If D<40 and getKey(1)
:20+D→U
:End
:If D≠0 and getKey(4)
:D-20→U
:End

to
Code: [Select]
:If D<40 and getKey(1)
:10+D→U
:End
:If D≠0 and getKey(4)
:D-10→U
:End

the code now scrolls vertically by 1. since the tilemap is half-byte compressed and there are 20 tiles per row of the map, that means there are 10 bytes in each row. so you only need to add 10 to scroll to the next row.

as for horizontal scrolling, that's a bit more challenging and may require changing the way you draw the tilemap. here's some modified code:
Code: [Select]
:.ATILMAP
:[11111111111111111111→GDB1      .Data Map size is 20 tiles (half-bytes aka nibbles) wide by 12 tiles high.
:[10001000000000000001           .The height of the displayed map is 8 tiles. this means the maximum
:[10000100000000000001           . vertical offset is 4 tiles. since each row is 20 tiles, the maximum vertical offset is 80.
:[10000001000000000001           . the width of the displayed map is 12 tiles. this means the maximum horizontal offset is
:[10000000001000000001           . 8 tiles.
:[10001000000000000001
:[10000010000000000001
:[10000000000000000001
:[10010000000000000001
:[10100000000000000001
:[10000000000000000101
:[11111111111111111111
:[55AA55AA55AA55AA→Pic1
:[FFFFFFFFFFFFFFFF
:0→S→D                       .OFFSETS - S = horizontal scroll, D= vertical scroll
:ClrDraw
:Repeat getKey(15)
:If D<80 and getKey(1)       .80 is the maximum vertical offset
:20+D→D:End
:If D≠0 and getKey(4)         .0 is the minimum vertical offset, naturally.
:D-20→D
:End
:S<8 and getKey(3)-(S≠0 and getKey(2))+S→S     .8 is the maximum horizontal offset
:For(Y,0,7
:For(X,0,11
:Pt-Off(X*8,Y*8,sub(GN,Y*20+X+D+S)*8+Pic1     .Y*20+X+D+S is a nibble in the tilemap
:End:End
:DispGraph
:End
:Lbl GN
:{r1/2+GDB1}→T                 .Divide the nibble by two to find the correct byte in the tilemap
If r1^2                        .If the byte in the tilemap isn't divisible by two
T^16:Else                      .Return the low nibble of the byte. Else
T/16:End                       .Return the high nibble of the byte.



Title: Re: Tilemap scrolling
Post by: MRide on July 28, 2010, 11:37:01 pm
Thanks.
Also, how would you implement 3 lvl grayscale tiles?  Say, instead of just black tiles, I wanted all gray tiles.
Title: Re: Tilemap scrolling
Post by: nemo on July 28, 2010, 11:40:12 pm
not sure, but i think you'd just change DispGraph to DispGraphr and have Pt-Off() be Pt-Off()r
Title: Re: Tilemap scrolling
Post by: MRide on July 28, 2010, 11:43:56 pm
That just creates a flashy screen.  Wouldn't would need a separate drawing command if you want only the solid black tiles turned gray?
Title: Re: Tilemap scrolling
Post by: nemo on July 28, 2010, 11:47:32 pm
hmm.. i'm not very good with grayscale, but yes you're correct. you need two drawing commands. one that draws to the buffer, and one to the back-buffer. however, if you only want the black squares to be gray then you need to store the result of the sub(GN) call into a variable, and use an If conditional
Title: Re: Tilemap scrolling
Post by: MRide on July 28, 2010, 11:55:38 pm
So you would need to draw the patterned tile to both buffers, and the solid tile to just the back buffer?

EDIT: Well, it starts out looking good (if a bit flickery), but when I try to move, it messes up.

EDIT 2: Would this be a sort of upside down ninja'd?
Title: Re: Tilemap scrolling
Post by: nemo on July 29, 2010, 12:01:26 am
yes. i seem to have it working except when you try to scroll, it starts flickering :/

edit: i found it out, though i'd like to see you get it on your own so i'm not going to post code (but i will later if you want me to)
Title: Re: Tilemap scrolling
Post by: DJ Omnimaga on July 29, 2010, 03:33:44 am
By the way I worked on a tilemapper for a while, but sadly, I couldn't figure out how to change a tile in it. It was for a map editor, by the way. There might be other help available in the topic there (although it's old): http://ourl.ca/5988

I don't recommend my code because it was buggy, but hopefully the advices Quigibo posted might be helpful. At first my tilemap scrolled every 2 tile horizontally but he helped me make it scroll every tile
Title: Re: Tilemap scrolling
Post by: MRide on July 29, 2010, 01:26:38 pm
Well, I fixed one problem.  Now the gray stays the whole time, but instead of being solid gray, it appears to have the checkerboard pattern behind it.

EDIT: Hmm...Well, If store the result of the call to GN in W, then W is either 0 or 1.  If its zero, then I want to write to the buffer, and I always write to the back-buffer.  However, it seems that the patterned tile is being written to the buffer over the whole tilemap.

EDIT 2: I have come to these possibilities:
            1) The GN call does not return 0 or 1 as I had supposed, therefore, the If conditional is always true, and always draws the patterned tile to the buffer
            2) The above statement is false, because the drawing command inside the if conditional wouldn't just draw the patterned tile,  and after looking at the code, GN does return 0 or 1.
            3) If #2 is true, then there shouldn't be anything wrong with that section of the code, and I messed up somewhere else.
Title: Re: Tilemap scrolling
Post by: nemo on July 29, 2010, 04:32:42 pm
the subroutine GN definitely returns a 0 or a 1, based on the tile in the tilemap. could you post some code? and yes, the way grayscale is made is turning pixels on and off very quickly. so when you do DispGraphr, you actually turn on a checkerboard pattern on the backbuffer, and then the next time you call it the checkerboard pattern is shifted, making the appearance of gray. you probably see the checkerboard because the screen is not updating quickly enough. you could put an If getKey(0) around the part where you draw the tilemap to remedy this.
Title: Re: Tilemap scrolling
Post by: Quigibo on July 29, 2010, 11:14:14 pm
GN does not explicitly return 1 or 0, it returns the half byte tile 0-F (0-15 in decimal).  Although personally, I don't like that routine since there is no X and Y its usage is confusing.

If you want a solid gameboy gray, you have to turn interrupts off for the entire code and you also need to make sure to adjust the pause time in between each DispGraph to the perfect amount.  It will take some tuning since every display is different unfortunately.  For me, I have a TI-84 Plus K-0108H and my perfect gray setting is this:

Code: [Select]
:FnOff
:Repeat getkey(15)
:
:Pause 7           ;Long pause
:For(A,0,15):End   ;Fine tuning
:
:DispGraphr
:End

By perfect, I mean like a gameboy, not even one of those slowly scanning lines that moves diagonally from one side to the other, I mean literal gray.  The pause times will of course have to be different depending on how much other code you have in your loop.
Title: Re: Tilemap scrolling
Post by: Runer112 on July 29, 2010, 11:40:22 pm
GN does not explicitly return 1 or 0, it returns the half byte tile 0-F (0-15 in decimal).  Although personally, I don't like that routine since there is no X and Y its usage is confusing.

If you want a solid gameboy gray, you have to turn interrupts off for the entire code and you also need to make sure to adjust the pause time in between each DispGraph to the perfect amount.  It will take some tuning since every display is different unfortunately.  For me, I have a TI-84 Plus K-0108H and my perfect gray setting is this:

Code: [Select]
:FnOff
:Repeat getkey(15)
:
:Pause 7           ;Long pause
:For(A,0,15):End   ;Fine tuning
:
:DispGraphr
:End

By perfect, I mean like a gameboy, not even one of those slowly scanning lines that moves diagonally from one side to the other, I mean literal gray.  The pause times will of course have to be different depending on how much other code you have in your loop.

Why do interrupts have to be off for good-looking grays?
Title: Re: Tilemap scrolling
Post by: nemo on July 30, 2010, 12:20:19 am
as a minor clarification, sub GN *does* return a 1 or a 0, since only 1's and 0's are in the tilemap.
Title: Re: Tilemap scrolling
Post by: DJ Omnimaga on July 30, 2010, 02:54:48 am
One thing a programmer could do is allow the user to change the Pause delay in an option menu by a certain range. Not too low nor too high, to keep the game speed from changing way too much, depending of the setting. It might allow the game to look good on most models. Desolate did that (although it only let you choose between 4 settings)
Title: Re: Tilemap scrolling
Post by: MRide on July 30, 2010, 04:03:02 pm
the subroutine GN definitely returns a 0 or a 1, based on the tile in the tilemap. could you post some code? and yes, the way grayscale is made is turning pixels on and off very quickly. so when you do DispGraphr, you actually turn on a checkerboard pattern on the backbuffer, and then the next time you call it the checkerboard pattern is shifted, making the appearance of gray. you probably see the checkerboard because the screen is not updating quickly enough. you could put an If getKey(0) around the part where you draw the tilemap to remedy this.

Won't this ruin the grayscale when you try to move, though?
Title: Re: Tilemap scrolling
Post by: nemo on July 30, 2010, 04:34:45 pm
for a frame,  yes. quigibo already gave a better fix with the pause command.
Title: Re: Tilemap scrolling
Post by: MRide on July 30, 2010, 06:07:59 pm
GN does not explicitly return 1 or 0, it returns the half byte tile 0-F (0-15 in decimal).  Although personally, I don't like that routine since there is no X and Y its usage is confusing.

If you want a solid gameboy gray, you have to turn interrupts off for the entire code and you also need to make sure to adjust the pause time in between each DispGraph to the perfect amount.  It will take some tuning since every display is different unfortunately.  For me, I have a TI-84 Plus K-0108H and my perfect gray setting is this:

Code: [Select]
:FnOff
:Repeat getkey(15)
:
:Pause 7           ;Long pause
:For(A,0,15):End   ;Fine tuning
:
:DispGraphr
:End

By perfect, I mean like a gameboy, not even one of those slowly scanning lines that moves diagonally from one side to the other, I mean literal gray.  The pause times will of course have to be different depending on how much other code you have in your loop.

Hmm... If I use this without the If getKey(0), then it doesn't update fast enough.
Here is the code:
Code: [Select]
:.ATILMAP
:[11111111111111111111→GDB1
:[10001000000000000001
:[10000100000000000001
:[10000001000000000001
:[10000000001000000001
:[10001000000000000001
:[10000010000000000001
:[10000000000000000001
:[10010000000000000001
:[10100000000000000001
:[10000000000000000101
:[11111111111111111111
:[55AA55AA55AA55AA→Pic1
:[FFFFFFFFFFFFFFFF
:0→S→D
:ClrDraw
:ClrDrawr
:Shade(48)
:FnOff
:Repeat getKey(15)
:If D<80 and getKey(1)
:20+D→D
:End
:If D≠0 and getKey(4)
:D-20→D
:End
:S<8 and getKey(3)-(S≠0 and getKey(2))+S→S
:Pause 7
:sub(DS)
:DispGraphr
:End
:Return
:.Drawing sub
:Lbl DS
:ClrDraw
:ClrDrawr
:For(Y,0,7)
:For(X,0,11)
:sub(GN,Y*20+X+D+S)→W
:!If W
:Pt-Off(X*8,Y*8,sub(GN,Y*20+X+D+S)*8+Pic1)
:End
:Pt-Off(X*8,Y*8,sub(GN,Y*20+X+D+S)*8+Pic1)r
:End
:End
:.Extraction
:Lbl GN
:{r1/2+GDB1}→A
:If r1^2
:A^16:Else
:A/16:End
Title: Re: Tilemap scrolling
Post by: Quigibo on July 30, 2010, 06:31:09 pm
You don't need that pause 7 there anymore.  That was only there originally because I didn't have enough pause in the example I gave.  Your drawing routine plus everything else in the loop already has a huge pause, probably longer than a pause 7 so you don't need that extra pausing since its just slowing it down.
Title: Re: Tilemap scrolling
Post by: MRide on July 30, 2010, 07:50:30 pm
Even if I remove the Pause 7, It still updates too slowly.  Is there a way to speed it up?
Title: Re: Tilemap scrolling
Post by: Quigibo on July 30, 2010, 07:57:19 pm
You can put your sub(DS) in full speed mode.  Just add a :Full to the start of that subroutine and a :Normal at the end of it.  By the way, I just noticed you don't have a return at the end of it so its falling through to the next subroutine and returning after that.
Title: Re: Tilemap scrolling
Post by: MRide on July 30, 2010, 09:10:22 pm
Thanks.  would it be any faster to put the getkey tests inside one if statement. and put the rest of the repeat loop (except the DispGraphr) in Full Mode?
Title: Re: Tilemap scrolling
Post by: Quigibo on July 30, 2010, 09:23:25 pm
The getkey's have to be in Normal speed otherwise they sometimes don't register the correct keys.  Your DS routine is taking up 99% of the CPU anyway so the other stuff is a negligible speed difference.  Don't forget, Full speed is not available for the regular TI-83+ which would still run at Normal speed after that command.  So your program won't be the same quality with that calculator.