It is currently Sat Dec 15, 2018 9:29 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 14 posts ] 
Author Message
PostPosted: Fri Jul 06, 2018 7:05 am 
Offline
User avatar

Joined: Wed Oct 22, 2008 9:27 pm
Posts: 101
I'm doing some pixel art and I'd like to know if there's a technical limitation holding back smooth animation on NES hardware. Seems like most games use very few frames for running. I was able to dramatically improve Contra's run animation by going from 3 unique leg positions to 5.

Is it possible to delay each frame individually by a different amount? In photoshop, I'm able to specify a delay in fractions of a second. And I can also give some frames more delay than others. Can the NES do this?

Lastly, has anyone made a demo showing a heavy frame running animation like that in Super Metroid?


Top
 Profile  
 
PostPosted: Fri Jul 06, 2018 7:11 am 
Offline
User avatar

Joined: Wed Sep 07, 2005 9:55 am
Posts: 339
Location: Phoenix, AZ
There is no hardware limitation on having different times for each frame of an animation. My animation code allows for this, but it does double the size of an animation definition (which isn't really a problem these days).

Without bank switching or chr-ram you might run out of tiles to use on other things though.

_________________
. That's just like, your opinion, man .


Top
 Profile  
 
PostPosted: Fri Jul 06, 2018 7:40 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7018
Location: Canada
FitzRoy wrote:
I'm doing some pixel art and I'd like to know if there's a technical limitation holding back smooth animation on NES hardware.

It's memory, both limited in total data size, and also limited by the small amount of data visible to the NES during a frame.

In FCEUX open up: Debug > PPU viewer. This will show you exactly what's going on.

Some of the more advanced mappers can page 1k chunks of graphic tiles. If you use 1 of these for each active character, you could have 3 or 4 characters with large amounts of sprite data, but it's very limiting to do this for all characters. Batman - Return of the Joker, for example, does it for only the player character, and the other 3 pages are fixed for any given room, so all of the other sprites have to fit into those 3 extra pages. (Having to partition sprites into 1k blocks also tends to end up with a lot of empty/wasted space, and with existing mappers you're going to have a hard limit of 256 pages total to use, or maybe less.)

FitzRoy wrote:
I was able to dramatically improve Contra's run animation by going from 3 unique leg positions to 5.

Contra had to fit all sprites into memory at once, because it had no banking. It uses CHR-RAM so it can change some sprite tiles as needed, but the NES doesn't have much bandwidth to do this. Battletoads uses RAM and updates some tiles each frame for the main characters, but nothing else, and it had to use special techniques to extend the vertical blank period so it could have time to upload this much graphic data. (Again, look at these with the PPU viewer to see how that memory is organized.)

FitzRoy wrote:
Is it possible to delay each frame individually by a different amount?

Absolutely. You can see it already in the upper body run animation in Contra.

FitzRoy wrote:
Lastly, has anyone made a demo showing a heavy frame running animation like that in Super Metroid?

Kasumi's Indivisible demo has some of the most detailed animation I can think of on the NES: https://kasumi.itch.io/indivisible
Kasumi also is making a tool for animation, with some examples that might fit your bill: https://forums.nesdev.com/viewtopic.php?f=21&t=17082


Top
 Profile  
 
PostPosted: Fri Jul 06, 2018 7:54 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11012
Location: Rio de Janeiro - Brazil
The number of tiles the PPU can use for sprites is 256. These have to be shared among all sprites, including enemies, items and such, so there may not be much left for smoothly animating the player sprite. This can be circumvented with fine CHR-ROM bankswitching (1 or 2KB chunks), so that the space reserved for player sprites can be instantaneously mapped from anywhere in the ROM. CHR-RAM can also help here, because tiles can be redrawn on the fly, but this is not instantaneously, it's actually pretty slow, so depending on how much you have to update each frame, they're might not be much time left for updating patterns.


Top
 Profile  
 
PostPosted: Fri Jul 06, 2018 7:54 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 3141
Location: Tampere, Finland
rainwarrior wrote:
Some of the more advanced mappers can page 1k chunks of graphic tiles. If you use 1 of these for each active character, you could have 3 or 4 characters with large amounts of sprite data, but it's very limiting to do this for all characters. Batman - Return of the Joker, for example, does it for only the player character, and the other 3 pages are fixed for any given room, so all of the other sprites have to fit into those 3 extra pages. (Having to partition sprites into 1k blocks also tends to end up with a lot of empty/wasted space, and with existing mappers you're going to have a hard limit of 256 pages total to use, or maybe less.)

Moon Crystal (Japan only) is widely known to have very smooth character animations. It uses exactly this technique.

By the way, if you use 8x16 sprites you can also sacrifice some background tiles to get more sprite tiles. With MMC3 this can get awkward though because the IRQ counter doesn't behave well if sprites from both 4 KB pages are accessed.

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi


Top
 Profile  
 
PostPosted: Fri Jul 06, 2018 8:06 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20880
Location: NE Indiana, USA (NTSC)
Ninja'd thrice while I was composing this:

FitzRoy wrote:
I'm doing some pixel art and I'd like to know if there's a technical limitation holding back smooth animation on NES hardware. Seems like most games use very few frames for running. I was able to dramatically improve Contra's run animation by going from 3 unique leg positions to 5.

The following factors are why you don't often see 15 to 30 fps sprite animations on NES:

ROM size limit
At launch, a game had only 8 KiB of CHR ROM, allowing up to 256 distinct background tiles and 256 distinct sprite tiles (or 128 tall tiles in 8x16 mode). In 8x16 mode, a sprite can borrow a pair of tiles from the background half.

Later games are affected by ROM size to a lesser extent. Only a handful of licensed games are larger than the 512 KiB Mega Man 4 through Mega Man 6, and some of them cut back on player cels in order to fit more background environments and enemy cels. Late development of The Curse of Possum Hollow was a game of Sokoban as I moved code and data around to fit them in the banks of the 512 KiB PRG ROM.

CHR ROM bank switching granularity limit
MMC3-class mappers support only 4 sprite windows. You can put different cels of a character's animation in different banks, and then you animate by changing banks. But if you have more than four actors on the screen, at least two of them have to share a window, and the sprite sheet for that actor is thus limited to one bank, which is 64 tiles (or 32 tall tiles in 8x16 mode). Borrowing from the background pattern table isn't possible in levels that use parallax scrolling due to a quirk in the MMC3's interval timer.

Here's how Curse lays out its PPU address space:

$0000-$0FFF (4K): Playfield or parallax loop
$1000-$13FF (1K): Current frame of Donny or Tami
$1400-$17FF (1K): Enemy sprite sheet 1
$1800-$1BFF (1K): Enemy sprite sheet 2
$1C00-$1FFF (1K): Common sprites, such as powerups, projectiles, lifts, and small objects that appear in many environments

The game uses 8 banks of tiles for Donny and 7 more for Tami, switching to whatever bank has the tiles for a particular cel. If a sprite sheet is only one bank (32 tall tiles in 8x16 mode), more than one enemy on the screen can use it, but an enemy with a larger sprite sheet (that is, a boss) will hog one of the sprite windows. So level designs have to be careful not to try to put more than two different enemy types together, or three if two of the enemy types are in the same sprite sheet.

MMC1-class mappers used with CHR ROM (e.g. SLROM, SKROM) have even coarser granularity: each page is 4 KiB or 256 tiles or 128 tall tiles in 8x16 mode. Thus all the sprite tiles used by a level have to fit into one 4K bank, including the player and enemies for a given environment type. The player's tiles also have to be repeated for different environment type.

CHR RAM bandwidth limit
Let's say a game streams cels from PRG ROM to CHR RAM in order to circumvent bank switching granularity. Haunted: Halloween '85 does this for all sprites, and Battletoads does this for some sprites. Under normal circumstances, only about 128 bytes can be copied from ROM (or a decompression buffer in RAM) to CHR RAM in each NTSC vertical blanking period. This means eight tiles or four tall tiles in 8x16 mode. If an actor uses more than that, it has to be double-buffered; fortunately, there's enough CHR RAM on the sprite half of the pattern table to double-buffer everything. But if you decide to have many actors changing their cel at once, they may lag. One thing Haunted does to hide the lag is try to guess the actor's next cel based on what most commonly follows the current cel and then preload that into each actor's back buffer.

FitzRoy wrote:
Is it possible to delay each frame individually by a different amount?

Yes, each cel in a sequence can have a different duration, but a particular engine might not necessarily support that. It's slightly more difficult code-wise to scale duration-per-cel to an actor's movement speed, as might happen in a walk cycle.

FitzRoy wrote:
Lastly, has anyone made a demo showing a heavy frame running animation like that in Super Metroid?

I've never played Super Metroid. How many cels does Samus (or whatever other character you're thinking of) have? I made a tech demo with a 12-cel walk cycle during the early development of a project related to Concentration Room, but it didn't have a lot else going on.


Top
 Profile  
 
PostPosted: Fri Jul 06, 2018 8:08 am 
Offline
Formerly WheelInventor

Joined: Thu Apr 14, 2016 2:55 am
Posts: 1786
Location: Gothenburg, Sweden
I was coincidentally just in the process of cleaning up some sprite and OAM tables for the game gauauu and me are making, so some tips and tricks are right in front of me.

Your sprite object handler can be programmed to do whichever as long as you don't run out of tiles.

This running cycle is using no less than 16 unique animation cels.
Image

To keep the # of unique tiles down, i do the following:
-look for opportunities to use fewer tiles by merging overlapping ones (this can both shrink and expand the number of total tiles depending on situation).
-move the same tiles around across multiple cels. This works best/easiest when moving the position on the x-axis, because you want to avoid overlap on the y axis as much as possible.
-Alternate priorities. Pixels hidden in one tile by another may add something (a hip, a shoulder) to the animation on the exact opposite of the cycle.
-The whole thing is moved up and down in little arcs to make leaps. Walking would have an up/down pattern more resembling wave crests.

Here's a slowmo of what is happening.
Image

-my overall goal was to reduce the tile bandwidth from 1/4th of the scanline limit to 1/8th wherever possible, and try to avoid using 3/8th:s without exploding the tile estate required.

I was thinking i might do a more detailed blog update once i was finished with the tileset cleanup, but this is basically all there is to it.

A general note on position animation:
Big and slow changing entities may benefit significantly from the added fidelity. This rat which you can encounter in Inherent Smile from last years' compo is pretty darn big for a NES enemy, but is using the same technique.
A major difference is that it is also shifting tiles up and down in column groups, but avoids overlap. When moving things on the y axis, either move them as one, move them apart, or move them together so that they touch, but -again- try to avoid overlap in this case.
Image

...I thought i'd be the first replier since i was sitting with this right in front of me. Got super ninja'd. :lol:

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


Top
 Profile  
 
PostPosted: Fri Jul 06, 2018 11:05 am 
Offline
User avatar

Joined: Sat Jan 09, 2016 9:21 pm
Posts: 518
Location: Central Illinois, USA
FrankenGraphics wrote:
-Alternate priorities. Pixels hidden in one tile by another may add something (a hip, a shoulder) to the animation on the exact opposite of the cycle.


Huh, I didn't take this into account in the flicker managing stuff I started working on -- I'll need to make some adjustments to preserve your priorities. I'm glad I saw this post! :-)

_________________
My games: http://www.bitethechili.com


Top
 Profile  
 
PostPosted: Fri Jul 06, 2018 11:43 am 
Offline
Formerly WheelInventor

Joined: Thu Apr 14, 2016 2:55 am
Posts: 1786
Location: Gothenburg, Sweden
gauauu wrote:
FrankenGraphics wrote:
-Alternate priorities. Pixels hidden in one tile by another may add something (a hip, a shoulder) to the animation on the exact opposite of the cycle.


Huh, I didn't take this into account in the flicker managing stuff I started working on -- I'll need to make some adjustments to preserve your priorities. I'm glad I saw this post! :-)


It might be solveable another way - maintain priorities within an object as per normal, but switch ID:s and positions instead. Or wait, each cel is just a listing of sprites. No action should be needed? PM me if we need to go through details!

Does the engine take into account that the entity is using a changing total of sprites? A termination byte at the end ($00?) should be able to help with that.

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


Top
 Profile  
 
PostPosted: Fri Jul 06, 2018 12:25 pm 
Offline
User avatar

Joined: Sat Jan 09, 2016 9:21 pm
Posts: 518
Location: Central Illinois, USA
FrankenGraphics wrote:
It might be solveable another way - maintain priorities within an object as per normal, but switch ID:s and positions instead. Or wait, each cel is just a listing of sprites. No action should be needed? PM me if we need to go through details!

No worries, it's a simple change on my end, I just hadn't thought about maintaining the priority.

Quote:
Does the engine take into account that the entity is using a changing total of sprites? A termination byte at the end ($00?) should be able to help with that.

Yeah, that's not a problem.

_________________
My games: http://www.bitethechili.com


Top
 Profile  
 
PostPosted: Sat Jul 07, 2018 3:50 am 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1254
FitzRoy wrote:
Lastly, has anyone made a demo showing a heavy frame running animation like that in Super Metroid?

My Indivisible has an 8 frame run: https://kasumi.itch.io/indivisible

Attached is some 3rd Strike animation in an NES ROM.
Attachment:
3rdStrikeChun.nes [384.02 KiB]
Downloaded 100 times

A changes the animation. While I didn't change the timing per frame for this, it's certainly possible.
Edit: Just because it's easy for me to do, here's specifically Samus' run from Super Metroid. :wink:
Attachment:
SamusRun.nes [40.02 KiB]
Downloaded 88 times


These ROMs were made in the unreleased build of my I-CHR software that rainwarrior mentioned. There are holes in Chun Li's body because most of the frames use more than 63 sprites. (NES can draw 64 sprites, I-CHR only supports 63 in a single character frame to avoid moving a pointer)

Here's the workflow:
Image
Not shown, but this program does guess palettes and make tiles even if the sprite is >3 colors. (Like Indivisible's Ajna.) You basically import a PNG sequence and it does the rest.
Everyone else did a good job explaining why many games probably avoided doing animation like this, so I won't cover it again.

I hope to make it easier to do with I-CHR, but it seems like the version of the program that handles sprite animation will never actually come out.

_________________
https://kasumi.itch.io/indivisible


Top
 Profile  
 
PostPosted: Mon Jul 09, 2018 7:16 pm 
Offline
User avatar

Joined: Wed Oct 22, 2008 9:27 pm
Posts: 101
Kasumi wrote:
Attachment:
SamusRun.nes


Yeah, that's pretty interesting stuff. Thanks for that.

I'm still a bit puzzled as to why we don't see more hacks doing stuff like this. I have seen a lot of redone sprites, just not a lot of extra animations being inserted and reprogramming the game to use them.


Top
 Profile  
 
PostPosted: Mon Jul 09, 2018 7:24 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7018
Location: Canada
FitzRoy wrote:
I'm still a bit puzzled as to why we don't see more hacks doing stuff like this. I have seen a lot of redone sprites, just not a lot of extra animations being inserted and reprogramming the game to use them.

Again the problem is memory.

Redoing an existing sprite just replaces its data where it is. It's very simple and easy to do this.

Adding a new sprite means you need to find new space for new graphics data, and also add extra code to deal with it. If the code isn't designed around banking individual characters already (which very few games are) then this might involve a lot of rewriting of how it renders things, hacking the whole game to work with a different mapper, etc. How the game manages memory for graphics is a big deal part of NES game design, and making changes to it probably involves making deep changes throughout the game.

Like, you can't even just find a blank space in CHR-ROM or even increase the ROM size and stick more sprites in there, you need to work out a system so that the new sprites can be visible to the NES (i.e. banked-in) at the time they're needed, along with all other sprites needed at that same instant, and there's no standard scheme for doing this. Every game manages this in its own way. This will generally require big code changes, and a lot of playing through / debugging / testing of the whole game.

Replacing an existing sprite, on the other hand, may not have any code consequences at all, and really doesn't need much testing.


This two-player Ducktales 2 hack is one of the most impressive hacks I've seen for that reason. They managed to fit a whole second player character into it, which involved creating a way to continually inject new sprites into memory that the game did not have before.
https://www.romhacking.net/hacks/2141/


Top
 Profile  
 
PostPosted: Mon Jul 09, 2018 10:11 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3725
Location: Mountain View, CA
Welcome to what romhacking is all about, and why it's a kind of art, driven by passion and dedication. And why, in almost all circumstances, you need an assembly programmer to disassemble + reverse-engineer the game to figure out a) where there's free space (if any; and if not, double the ROM size and write code to make use of the new space), b) figure out how all the existing code works, and c) make relevant code changes so that said new graphics can get utilised correctly. Full-fledged romhacks of this sort are very complicated and time-consuming. That is why you don't see more of them.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 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