It is currently Tue Sep 18, 2018 12:49 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: Wed May 02, 2018 9:19 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20552
Location: NE Indiana, USA (NTSC)
I'm trying to figure out how I can make different rows of tiles on the screen not only scroll at different rates but also efficiently update the tilemap at the particular seam corresponding to each row.

Currently I'm storing the background map in each level as 64x64-pixel metatiles, which are made of 32x32-pixel metatiles, which are made of 16x16-pixel metatiles, which are made of 8x8-pixel tiles. Each of the four layers of metatile storage can have no more than 256 unique tiles in one map.

Any row that does not scroll at the same rate as the playfield is a "background loop" row, which does not get updated in the tilemap during the scrolling process. Thus the map of a background loop is currently limited to 512x240 pixels, the size of the tilemap in vertical mirroring mode. The background loop gets its own set of 256 tiles in CHR RAM. But in order to make an NES game's graphical style competitive with that of PC-native pixel art games such as Shovel Knight, someone may want to change this to make the map used by some rows wider than 512 pixels, especially rows in the "foreground" that scroll twice as fast as the camera moves. I've attached a video of what the scrolling seam for such updates might look like, along with the Python program that generated the video.

Attachment:
vlcsnap.png
vlcsnap.png [ 71.93 KiB | Viewed 2450 times ]


Is there an efficient way to store the map that allows for efficient reading of a decently compressed map from ROM to produce a horizontally staggered nametable update? What other NES games use a staggered update seam in this fashion? Or is this uncharted territory, as if I were trying to demake Virtual Boy Wario Land on the NES?

Bonus question: If the terrain occasionally has to protrude above the vertical position of the split, such as making the ladder in the middle of this map taller, what's the best way to draw it? Should the scroll rate of the tile rows containing this bit of terrain temporarily change to the same scroll speed as the playfield while the bit of terrain is temporarily on screen?


Attachments:
src.zip [8.33 KiB]
Downloaded 74 times
seam.webm [476.16 KiB]
Downloaded 129 times
Top
 Profile  
 
PostPosted: Wed May 02, 2018 11:00 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6797
Location: Canada
The video is nice.

I don't think there would be any special technique that would make this more efficient than what I'd think of as the naive approach. My counter-question would be instead: is the naive approach not efficient enough?

I can't think of any NES examples of parallax where all but one layers aren't just simple loops. TBH I think doing that is a rather subtle gesture in most contexts, probably way too fussy a detail to remain in-scope for a commercial game. That said, if any game does it, I'd say it would be Bucky, but it seems highly probable to me all of its multi-split effects are loops.

One thing you could probably get away with when updating the top and bottom layer, since they seem to be locked to each other, is to do a vertical string starting with the bottom half, step over/through 2 attribute bits and wrap around to the top. That's just a tiny optimization though, so I'd still go back to my first question (i.e. is it actually a problem that needs special tricks to solve?)


Top
 Profile  
 
PostPosted: Wed May 02, 2018 11:36 pm 
Offline
Formerly WheelInventor

Joined: Thu Apr 14, 2016 2:55 am
Posts: 1778
Location: Gothenburg, Sweden
Probably some sort of bi-format? Ie. one for the game physics-important content (meta tiles), and one for parallaxed content (rle compressed strips; looped). If you need different signs to appear, like in your video, maybe those could be overwritten on top.

the castle example i showed last autumn is a loop (though the sample level doesn't go far enough to loop it here as the far bg moves slower), but is then replaced with the storage-hungry castle. In textile pattern design (which shares a great deal with early, pattern based computer graphics), the length of such a loop is called a 'report'. At the seam of the report, you could either repeat the same pattern or call in another pattern, which is what happens with the castle scene. A counter would keep track of that.

Most of the sky is naturally great with RLE. The gradient on top (which doesn't move) works better with a repeated metatile, unless the RLE method can take care of two-tile patterns.


Attachments:
castle_x1_3.png
castle_x1_3.png [ 28.59 KiB | Viewed 2429 times ]

_________________
http://www.frankengraphics.com - personal NES blog
Top
 Profile  
 
PostPosted: Thu May 03, 2018 5:47 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20552
Location: NE Indiana, USA (NTSC)
rainwarrior wrote:
I don't think there would be any special technique that would make this more efficient than what I'd think of as the naive approach. My counter-question would be instead: is the naive approach not efficient enough?

If I am doing vertical column updates, then every time I change the low 3 bits of the horizontal position, I have to update about six pointers to correspond to the new horizontal position:

  1. 32x32-pixel metatile for top left or top right quadrant of 64x64-pixel tile, based on X tile position bit 2
  2. 32x32-pixel metatile for bottom left or bottom right quadrant of 64x64-pixel tile, based on X tile position bit 2
  3. 16x16-pixel metatile for top left or top right quadrant of 32x32-pixel tile, based on X tile position bit 1
  4. 16x16-pixel metatile for bottom left or bottom right quadrant of 32x32-pixel tile, based on X tile position bit 1
  5. 8x8-pixel metatile for top left or top right quadrant of 16x16-pixel tile, based on X tile position bit 0
  6. 8x8-pixel metatile for bottom left or bottom right quadrant of 16x16-pixel tile, based on X tile position bit 0

Calculating these pointers once per frame, as in my current engine, is practical. Calculating these pointers potentially up to eight times per frame can become painful. And adding attributes into the mix might cause its complexity to overflow what I feel comfortable maintaining. But I don't know where to draw the line between practicality of maintenance and heroic effort to give NES games a sense of space rivaling 16-bit games.

rainwarrior wrote:
TBH I think doing that is a rather subtle gesture in most contexts, probably way too fussy a detail to remain in-scope for a commercial game.

I completely agree with you. I'm trying to convince someone else that this is the case. He wants to push the limits of art style on the NES very close to theoretical. He wants a game using 512K of ROM, 10K of RAM (the 2K in the console and 8K that we plan to add to the cartridge), and 34K of video memory (2K for nametables in the console and 32K of CHR RAM in the cartridge) to attempt to compete artistically with 2D pixel art games on platforms using downloads tens of megabytes in size, hundreds of megabytes of RAM, and no attribute table complexity. I mention ROM size because I'd totally do it if I didn't have to worry about real-time 2- or 8-directional map decompression.

rainwarrior wrote:
That said, if any game does it, I'd say it would be Bucky, but it seems highly probable to me all of its multi-split effects are loops.

That's fortunate, as someone else is a big Bucky fan.

rainwarrior wrote:
One thing you could probably get away with when updating the top and bottom layer, since they seem to be locked to each other

Top and bottom happen to have the same Z level (distance from the camera) in this example. They are not locked to each other in general.

rainwarrior wrote:
That's just a tiny optimization though, so I'd still go back to my first question (i.e. is it actually a problem that needs special tricks to solve?)

I anticipate dropping below 60 frames per second to be a problem, especially when I have to put attributes into the mix as well and perform collision detection on the player and a handful of enemies. Fortunately, the data structures for collision detection are completely separate from those for display.

FrankenGraphics wrote:
In textile pattern design (which shares a great deal with early, pattern based computer graphics), the length of such a loop is called a 'report'. At the seam of the report, you could either repeat the same pattern or call in another pattern, which is what happens with the castle scene. A counter would keep track of that.

That sounds ultimately like another level of metatiles. But it'll be even more difficult in that I'll also need to be scrolling vertically in some areas.

Perhaps the real problem is inability to politely get across that I'm being asked to punch above my weight.


Top
 Profile  
 
PostPosted: Thu May 03, 2018 6:29 am 
Offline

Joined: Tue Feb 07, 2017 2:03 am
Posts: 578
I would cache the 64x64(/16x16 as needed) tiles to RAM, 1 per layer needed, ( will the top and bottom XXX always be the same?, if so that is one less ). I would have a buffer for Next Tile L and next Tile R, this way your copy code only needs to index and wrap on the RAM buffers. If plotting is expensive you could double buffer those, so as you are drawing 1 you spend some frame time unpacking the Next tile for the direction.
For the tile that is disappearing off the other side, pulling the values from VRAM vs rebuilding the tile I guess is a VBlank cost vs Frame cost that you need to evaluate.

For the "foreground" over parallax, I would fake them with sprites, this probably places a limit that I would enforce in the level editor, of 1 palette per all "fake background" objects per so many chars(as determined by the engines limits), this also means that you lose one pallets for sprites but again it can be temporary.


Top
 Profile  
 
PostPosted: Thu May 03, 2018 7:45 am 
Offline
Formerly WheelInventor

Joined: Thu Apr 14, 2016 2:55 am
Posts: 1778
Location: Gothenburg, Sweden
The top/bottom could be kept to a single 2x2 metatile (or a few more if you want varations), while the signs could be ”structures” kept outside the metatile system. This would save precious metatile space that is (imo) best spent on more repeatable patterns. Metatiles of metatiles and unique structures are opposing concepts. Metroid is using structures of the kind i’m thinking of (but not meta tiles), if you want a case study. The drawback is obviously adding another process. But if the top/bottom is *just* one or a few metatiles sans the signs, i believe you needen’t update the seam at all on those rows until you want a sign, in which case you fetch the structure. The structure-getting would be easier in a one-way scroller though.

_________________
http://www.frankengraphics.com - personal NES blog


Top
 Profile  
 
PostPosted: Thu May 03, 2018 7:57 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20552
Location: NE Indiana, USA (NTSC)
In general, the top and bottom strips will not necessarily A. be the same height as one attribute byte or two color areas or four tiles or 32 pixels, B. scroll at the same rate, or C. be a repeating pattern interrupted by signboards. These are artifacts of the particular programmer art that I used to represent the functionality in the video. I am negotiating for more representative art that I am allowed to release. In addition, even if the top and bottom strips were a repeating pattern interrupted by signboards, I would still need to erase the signboards that do not appear in a particular area.


Top
 Profile  
 
PostPosted: Thu May 03, 2018 2:39 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6797
Location: Canada
tepples wrote:
rainwarrior wrote:
TBH I think doing that is a rather subtle gesture in most contexts, probably way too fussy a detail to remain in-scope for a commercial game.

I completely agree with you. I'm trying to convince someone else that this is the case.

This quote was meant in the historical "commercial era" sense. I was describing what happened in the past. Whether its viable now is a different (and open) question.

tepples wrote:
I don't know where to draw the line between practicality of maintenance and heroic effort to give NES games a sense of space rivaling 16-bit games.

Well, the line is yours to draw. If this is a negotiation with someone who is paying you to do it, this is probably a point where I'd try and put a price on it. Though, estimating programming work is a really hard problem, IMO. As bad as I am at estimating my own time, I'd be completely hopeless trying to guess how much work it is for you, especially without any perspective on the rest of the project.

All I can say is that it's very possible to do, and I think there are situations where it could be quite reasonable to do. (I've sketched similar multi-rate scrolling ideas several times, myself.)


In most cases like this I'd probably try to just implement it cheaply first, or implement enough of it to see what I need to see, just as a bit of research work. Sometimes you get lucky and the cheap way is good enough, but otherwise you might gain information that will help you make a better decision about whether to continue with it, or try something else. It seems you're already part of the way there with the video mockup you made.


Top
 Profile  
 
PostPosted: Sun May 06, 2018 1:29 pm 
Offline
User avatar

Joined: Thu Mar 31, 2016 11:15 am
Posts: 358
Quote:
up to eight times per frame

So it's a problem of dividing the work evenly across frame. That's not too bad. You can pre-compute a repeating sequence of updates to do over multiple frames. For example, if split 1 scrolls twice as fast as split 2, you'd update in this repeating order: 1, 1, 2, 1, 1, 2, 1, 1, 2...

Quote:
adding attributes

If you have 4 nametables then take advantage of that. Pad the tiles vertically so that no two splits share the same attribute. This will spill your data onto the lower two nametables, but it's much simpler.


Top
 Profile  
 
PostPosted: Sun May 06, 2018 9:01 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20552
Location: NE Indiana, USA (NTSC)
pubby wrote:
Quote:
up to eight times per frame

So it's a problem of dividing the work evenly across frame. That's not too bad.

It limits the maximum scroll rate, which some may not find acceptable especially when doing rapid scrolling in a cutscene or when the player changes facing direction.


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 1 guest


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