Reading from PPU for background collision

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Reading from PPU for background collision

Post by rainwarrior »

It has a few names, but the term I'm used to for this type of data structure is "ring buffer".
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: Reading from PPU for background collision

Post by DRW »

dougeff wrote:Your game (DRW) has auto-scrolling. So, load if scroll multiple of 8 makes sense here. Any game where scroll can shift 2 pixels in 1 frame might miss a load.
In this case, you of course have to do a slightly different check.
For example
if ((NewScollingPosition & 7) < (OldScrollingPosition & 7))
or something like that.
na_th_an wrote:As a hint for future games, you can avoid having to shift the entire array if you use a circular array with a moving, "virtual" first index.
Yeah, I thought about that. But having to calculate the index offset for every time the x position of any character is checked (which is quite a bit for various collision checks and the x position is an integer instead of just a byte) would have been more problematic and would have wasted more ROM space (and therefore more CPU time) than simply shifiting a 34 byte array every eight frames. (I even did this shift in Assembly for maximum speed.)
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
na_th_an
Posts: 558
Joined: Mon May 27, 2013 9:40 am

Re: Reading from PPU for background collision

Post by na_th_an »

rainwarrior wrote:It has a few names, but the term I'm used to for this type of data structure is "ring buffer".
Thanks for the info. I just translated literrally from Spanish :)
DRW wrote:Yeah, I thought about that. But having to calculate the index offset for every time the x position of any character is checked (which is quite a bit for various collision checks and the x position is an integer instead of just a byte) would have been more problematic and would have wasted more ROM space (and therefore more CPU time) than simply shifiting a 34 byte array every eight frames. (I even did this shift in Assembly for maximum speed.)
Yeah, I understand. It really depends on the size of your buffer.
Celius
Posts: 2158
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Re: Reading from PPU for background collision

Post by Celius »

The circular buffer concept is really quite easy to work with, especially in projects that only scroll horizontally or vertically. For me, the trick was to dedicate 2 pages of RAM to house a 2-screen rolling window of collision data (I store it in $600-$7FF). The data is formatted so that every 16 bytes represents a column of 16x16 pixel metatiles in the window. No matter what direction the camera is scrolling, determining where to "dump" newly revealed columns of tiles is extremely easy. You just take the in-level X coordinate of the camera boundary (the left boundary for scrolling left, right for scrolling right), AND it with $01F0, and add $0600. So if the camera scrolls so that the right boundary is at pixel $1BC1, which reveals a new column of metatiles, that column of metatiles would be dumped at (($1BC1 AND $01F0) + $0600) = $07C0.

Collision detection is just a step beyond this logic. After calculating the address of the column of tiles with the X coordinate, you divide the Y coordinate by 16 and use this as and use this as an index to that starting address.

Code: Select all

;XHigh/XLow/YLow represent a set of in-game X/Y coordinates. X is 16-bit, Y is 8-bit due to no vertical scrolling.

lda XHigh
and #$01
clc
adc #$06
sta TempAddH

lda XLow
and #$F0
sta TempAddL

lda YLow
lsr a
lsr a
lsr a
lsr a
tay

lda (TempAddL),y   ;Your tile type
na_th_an
Posts: 558
Joined: Mon May 27, 2013 9:40 am

Re: Reading from PPU for background collision

Post by na_th_an »

Exactly what I do. For 1 way scrollers, I usually have a 16x16 buffer (specially vertical games), and a two-screener for 2-way scrollers (left-right, mostly). Calculating where to write to the buffer is trival and collision detection is really easy this way.
Celius
Posts: 2158
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Re: Reading from PPU for background collision

Post by Celius »

The main thing I like about it is that it just works by itself without a lot of "special case" intervention. The only issue I ran into was if I sized my rolling window to be exactly 2 screens, I saw bad things happen when changing directions. Since both the left and right boundary of the window are exactly 2 screens apart, the address of where to dump new columns in the circular buffer is exactly the same for both directions. If the left bound is at pixel $1BC2, the right bound is at pixel $1DC2, which both evaluate to start at $7C0 in the circular buffer. Long story short, I would run into issues where it would skip updating values in the buffer that needed to change, if the scrolling direction changed. You could easily end up with corrupt collision data.

The easiest solution for me was to shrink my rolling window so that it's a little smaller than the width of the buffer. I just shrunk it down to like 480 pixels instead of 512.
Post Reply