It is currently Thu May 23, 2019 1:44 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 12 posts ] 
Author Message
PostPosted: Mon Dec 31, 2018 11:12 am 
Offline

Joined: Tue Aug 28, 2018 8:54 am
Posts: 143
Location: Edmonton, Canada
I'm working on 4 way scrolling right now. Working with X axis is nice and enjoyable experience, working with Y makes me cry in despair. I use 16-bit number for X where high 8-bit would be indicator of new nametable to load (or fill with $00 tile if not found). For Y, scroll must wrap at 240 otherwise I will have teared picture. So what I do is use scroll x/y (copies in RAM, that put in PPU at NMI) as lower 8 bits. So my 16-bit Y coordinate has to wrap at 240 for low byte as well.

I don't have division (I know I can use loop and substract 240 until value left is less or equal to 239), and having high byte to be level number, makes it easier to work with.

Problem arises when I need to compare what is the difference between camera coordinates, and loaded coordinates. If I scroll Y-1 and loaded Y - camera Y == 8, I load new row. At certain point I will have loaded Y=$XX00 and camera Y=$XXE8, and I want to get 8 as the result. I am not going to show any code, as all of my attempt have bugs and I'm still not very comfortable with assembler.

Does any one knows good approach to deal with this, or is there better way to deal with Y coordinate?


Last edited by yaros on Mon Dec 31, 2018 12:00 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Mon Dec 31, 2018 11:38 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7462
Location: Canada
For scrolling, you probably don't need to scroll fast enough to need more than just an increment at a time, something like this:
Code:
low_y += scroll_rate_y
if low_y >= 240
    low_y -= 240
    high_y += 1

...and something similar for subtracting.

If you need to do a big jump, you can change that "if" into some sort of "while", perhaps, but what I'm getting at is that is that for moving short distances you don't need to do generic division. You can just accomplish division as a repeated subtraction, probably with more efficiency than a more generic division routine.

If you occasionally need to do a big jump, probably it won't matter on that particular frame if you take a few extra cycles. Even then, a subtraction loop is probably OK. How tall are your levels? 4 screens? 16 screens? 1000 screens? If the problem is small scale, a small scale solution may be sufficient.

For things that aren't scrolling but somehow need to be mapped to a screen, you can probably just keep the "real" coordinate of the camera position, and do a subtraction from that to find its position on the current screen. (Or at most they'll be one or two screens off, adjacently.)


Top
 Profile  
 
PostPosted: Mon Dec 31, 2018 12:11 pm 
Offline

Joined: Tue Aug 28, 2018 8:54 am
Posts: 143
Location: Edmonton, Canada
I scroll 1px/frame and that is pretty much what I do and I will have at most 16x16 screens. Problem is not wrapping, but math after that. I want to know that we scrolled for 8 pixels, and 0-232!=8. But you are probably right, I should have an additional two variables to store scroll difference, and then use wrapped ones to find row to load.

I need to keep low byte wrapped, because if I have [0-255]:[0-240], high(scrollY) will be Y (+-1 for adjacent) for nametable (32 by 30) and low(scrollY)>>3 will be the row number to load from.


Top
 Profile  
 
PostPosted: Mon Dec 31, 2018 12:38 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21397
Location: NE Indiana, USA (NTSC)
Keeping separate variables for "top of valid portion of tilemap in VRAM space" and "top of valid portion of tilemap in world space" can help. When you scroll, add 8 to or subtract 8 from both, and wrap world space mod 256 and VRAM space mod 240. Every time you update the tilemap or set the hardware scroll position, use additions and subtractions to convert world space to VRAM space.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
PostPosted: Mon Dec 31, 2018 12:40 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7462
Location: Canada
yaros wrote:
I need to keep low byte wrapped, because if I have [0-255]:[0-240], high(scrollY) will be Y (+-1 for adjacent) for nametable (32 by 30) and low(scrollY)>>3 will be the row number to load from.

What I was suggesting is to keep both at once for your camera. A "world" coordinate to subtract from everything else, and the wrapped "screen" coordinate for mapping to the screen.


Edit: tepples made the same suggestion while I was typing.


Top
 Profile  
 
PostPosted: Mon Dec 31, 2018 12:59 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11348
Location: Rio de Janeiro - Brazil
The trick is to not to use the same value to calculate the row number to load from and the one to write to. Instead, use 2 separate scroll values, one relative to the level map (wraps normally at 256), and the other relative to the name tables (wraps at 240). Just update them in sync (always add/subtract the same amounts to both) and handle the special wrapping accordingly.

When you need to do operations relative to the level map, such as loading rows/columns or keeping the camera from going past the edges of the level, use the scroll that's relative to the map. When you need to do operations relative to the screen, such as calculating the target NT address for rows/columns or setting the PPU scroll, use the scroll that's relative to the name tables.

During initialization, the separate scroll values don't even need to be aligned to each other in any particular way when it comes to map rows. That is, there's no need to divide the normal scroll by 240 to find the initial value of the special scroll to find out what it'd be both started at 0 and scrolled down. The row where the special scroll starts makes literally no difference, since both scrolls wrap around independently from each other. Only the "pixel" part of the scroll values must match. For example, say that your metatiles are 16x16 pixels, and the initial vertical scroll is 1317. The remainder of that by 16 is 5, so you can simply initialize the special scroll to 5, but everything would work just as well if it were 21, 37, 53, and so on (increments of 16 pixels).

EDIT: Basically what the guys above said.


Top
 Profile  
 
PostPosted: Mon Dec 31, 2018 2:49 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21397
Location: NE Indiana, USA (NTSC)
The only restriction on the scroll position in VRAM space and world space is that their difference has to be a multiple of 16. Allowing them to become unaligned recently bit me.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
PostPosted: Mon Dec 31, 2018 3:14 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11348
Location: Rio de Janeiro - Brazil
Yeah, I may not have worded it very well when I said that "the pixel part must match", but that's what I meant. They need to be pixel aligned within the specific metatile they're in, but the NT space coordinate can point to any metatile row at the beginning.


Top
 Profile  
 
PostPosted: Mon Dec 31, 2018 5:56 pm 
Offline

Joined: Tue Aug 28, 2018 8:54 am
Posts: 143
Location: Edmonton, Canada
Thank you all. I made it working now.

Edit: smaller gif


Attachments:
scroll2.gif
scroll2.gif [ 847 KiB | Viewed 2446 times ]
Top
 Profile  
 
PostPosted: Tue Jan 01, 2019 2:13 am 
Offline

Joined: Tue Oct 06, 2015 10:16 am
Posts: 938
I keep expecting the Skifree monster to show up in that gif, lol.


Top
 Profile  
 
PostPosted: Wed Jan 02, 2019 8:28 am 
Offline
Formerly ~J-@D!~
User avatar

Joined: Sun Mar 12, 2006 12:36 am
Posts: 488
Location: Rive nord de Montréal
Happy New Year everyone!
tepples wrote:
The only restriction on the scroll position in VRAM space and world space is that their difference has to be a multiple of 16. Allowing them to become unaligned recently bit me.

Care to say what kind of issue it causes? I'm curious, because I can't figure out the problem.

_________________
((λ (x) (x x)) (λ (x) (x x)))


Top
 Profile  
 
PostPosted: Wed Jan 02, 2019 8:31 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21397
Location: NE Indiana, USA (NTSC)
Once the lower 4 bits of the VRAM and world space coordinates become misaligned, the attribute grid no longer lines up, and parts of your background start having the wrong palette.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 6 guests


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 post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group