This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

NES games and differences in input reaction

NES games and differences in input reaction
by on (#204473)
An edit to make things clear: there are two subjects on this post. Subject 1 is resolved. Subject 2 is a curiosity.

Subject 1:
So, I'm developing a demo using ca65. My goal is to add as many standard common features and then see what game I could make with that.

But one thing struck me that I thought maybe I was doing wrong, so I went on to test it. At the start of the nmi I do the OAM DMA transfer, meaning it would update sprites with their state on the previous frame. I thought maybe this was weird, but I think this is advised because of some timing issue (do DMA first). Well, for TESTING I tried this:

Code:
NMI begin:
1 - read controllers
2 - game logic
3 - OAM DMA
4 - scroll
5 - game clock (just 16-bit increment to a reserved ram location)
6 - famitone update
7 - RTI


The problem is, this works in fceux, virtuanes and punes, but it fails on real hardware with everdrive n8, on nestopia and on mesen (no sprites appear on screen). So it is a bad idea (points up to nestopia and mesen). I then went on to test some games and see if any did this (I tested them before I tested my rom on the everdrive or other emulators). Of course, none did. I think this is related to how OAM decays quickly. So that test went nowhere, but I decided to share the following research.

Subject 2:
So, I made a list of screen reaction to controller input. I only tested in-game, as in, when actual gameplay was happening, not title screens or such. Also, I tried several different moves to see the one that was more responsive. Sometimes a character deliberately takes a frame or two before jumping. Sometimes it is inconsistent and seems to be related to how much is going on in the screen at the time.

The count is I pause fceux, hold a button and hit frame advance. When I see the reaction I count how many times I pressed frame advance. So 2 is the minimum.

Here are the results:
2: Super Mario bros 3, Adventure Island, Battle of Olympus, Zelda 2, Kick Master, Batman, Amazon Diet, Yo! Noid, TMNT 2, Contra, Castlevania, Chip and Dale, Battletoads, Donkey Kong, Ghosts'n Goblins (very inconsistent though), Ghostbusters (tested on the car scene), Adventure Island 3, Pac Man (tengen), Lode Runner, Street Fighter 2010, Super Mario Bros, Simpsons Bart vs Space Mutants, Captain Comic, Rockman (inconsistent), Rockman 2, Rockman 3, Rockman 4, Rockman 5, Rockman6, Metroid, M.C kids, Ninja Gaiden, Ninja Gaiden 2, Ninja Gaiden 3, Mario Bros, Balloon Fight (inconsistent)
3: Arkanoid, Yie Ar Kung-Fu, Castlevania 3, Double Dragon (very inconsistent, sometimes takes as many as 11 frames to punch), Dr. Mario, Super Pitfall (original and my hack), Kid Icarus, Gradius, Punch-Out, Elevator Action, Gauntlet, Holy Diver
4: Pinball
5: Tiger-Heli, TMNT
6: Double Dragon 2, Double Dragon 3

Now, out of the games that reacted in 2 frames, some of those I didn't test a lot, and many of them did start playing the sfx immediately. Out of the other games (3+ frames) I tested several different moves and situations to see if it would lower the response time, and I wrote the lowest I got.

I was really surprised to see the Double Dragon games perform the way they did.
Re: NES games and differences in input reaction
by on (#204480)
Quote:
NMI begin:
1 - read controllers
2 - game logic
3 - OAM DMA
4 - scroll
5 - game clock (just 16-bit increment to a reserved ram location)
6 - famitone update
7 - RTI

This is an awful idea. VRAM updates and OAM DMA must happen during the short VBlank time, which happens directly after NMI.
Re: NES games and differences in input reaction
by on (#204481)
That you're getting 2 minimum suggests to me that their order is different than yours.
I in my current case I did NMI: DMA, VRAM [+scroll], controller, [sound], game logic, RTI.

Where is the PC stopped when you frame-advance? If it's at NMI entry (or thereabouts) like I expect, then in the case like mine, you can never get a "one frame" reaction, despite it technically reacting to your inputs on the very next frame it sees them: NMI, you update emu's input register, game updates video, game reads input and reacts, NMI, you have to press frame advance again, the game's reaction is now displayed.

(incidentally, I checked, and at least Zelda II does NMI: DMA, VRAM updates before doing anything with its controller variables, so…)

And yes, what Bregalad said.
Re: NES games and differences in input reaction
by on (#204484)
A little bird told me about an official document mentioning that DMA must begin within 286uS of beginning of NMI (which is about 512 CPU cycles, I think), or "there may be a problem with the DMA transfer". I always thought it was sensible to do the DMA early as possible, but it seems that it's actually required.
Re: NES games and differences in input reaction
by on (#204486)
Bregalad wrote:
Quote:
NMI begin:
1 - read controllers
2 - game logic
3 - OAM DMA
4 - scroll
5 - game clock (just 16-bit increment to a reserved ram location)
6 - famitone update
7 - RTI

This is an awful idea. VRAM updates and OAM DMA must happen during the short VBlank time, which happens directly after NMI.

This is indeed a terrible program structure (which unfortunately appears to be disseminated by the Nerdy Nights tutorials), mainly because it puts the game logic, the slowest part of any game, above VRAM/OAM updates, meaning you basically have to do everything in just 20 or so scanlines, which's ridiculous. This is particularly evil because it appears to work at first, when there's little to no game logic, but as soon as anything more complex than a single moving sprite is implemented, things start to glitch, and less experienced programmers become understandably confused.

But even when done right (PPU updates first, everything else later), the "all in NMI" approach has its pitfalls, the main one being the handling of lag frames, which's possible but not very intuitive. Game states (different game loops) can also be slightly more annoying to implement without a main thread.
Re: NES games and differences in input reaction
by on (#204494)
When I first started, I greatly underestimated how sensible Shiru's neslib was.

Nmi:
Oam update
Palette update (if needed) (from a buffer)
VRAM update (if needed) (from a buffer)
Set scroll
(Increase frame counter)
Music

Main loop:
(wait for frame counter to tick up)
Controller read
Game logic
Clear oam buffer
Fill oam buffer
Fill vram buffer, or just change a pointer to a new array
Re: NES games and differences in input reaction
by on (#204498)
This is not just Shiru's neslib, but the standard way of doing thigngs. My game engine does it precisely like that (it also ticks the random number generator in NMI).
Re: NES games and differences in input reaction
by on (#204499)
Bregalad wrote:
This is not just Shiru's neslib, but the standard way of doing thigngs. My game engine does it precisely like that (it also ticks the random number generator in NMI).

I personally like the idea of ticking the RNG repeatedly in the main thread while waiting for vblank. Since each frame takes a variable amount of time to compute depending on a number of factors, the RNG is clocked a different number of times each frame, improving randomness. And it's not like you'd be using that time for anything else, so why not?
Re: NES games and differences in input reaction
by on (#204500)
I posted the whole thing because I only realized it was fceux's fault later on, but still there's the interesting research on input lag from other games. I'd like to know why there is so much input lag on well programmed games. Is it some input buffer of sorts? For example the game Pinball, I can't imagine they decided "humm... this paddle is reacting too quickly, let's make it wait a few frames before it moves". How can double dragon 1 sometimes take 11 frames to react? This seems like a waste of memory to keep the input for so long?

Anyway, I knew this would happen, such a big post starting with a bad idea. I know it is a bad idea! I even said so in the post
nesrocks wrote:
So it is a bad idea

The thing is, fceux doesn't seem to emulate OAM decay? So it doesn't tell me it is a bad idea. I had to test it on other stuff.

It shouldn't matter because the docs are pretty specific to do oamdma first. But I wanted to see what happened when I did otherwise anyway.

About my game loop, it has always been an all NMI approach with oam dma on the right place. I switched for this test only. But I do have a main loop, it just doesn't do anything. When I try to do as dougef said (which I had tried before), the game either runs too fast (if I put my game logic on the forever loop), or it doesn't show anything on screen (if I put it on the vblank wait loop). I haven't debugged this yet, I will, don't worry. I was just satisfied with the all nmi approach, but if it is not ideal I'll change it. edit: fixed it, now the game is on the main loop. I just need to create the palette buffer.
Re: NES games and differences in input reaction
by on (#204501)
tokumaru wrote:
I personally like the idea of ticking the RNG repeatedly in the main thread while waiting for vblank. Since each frame takes a variable amount of time to compute depending on a number of factors, the RNG is clocked a different number of times each frame, improving randomness. And it's not like you'd be using that time for anything else, so why not?

Sounds like a very Konami-ish way to go ;)

Quote:
About my game loop, it has always been an all NMI approach with oam dma on the right place.

There's nothing inherently wrong with an all-in-NMI approach, I just find it not very intuitive to program myself. For example if you want to fade the palete out, typically you want to darken the palette, wait a couple of frames, darken it again, etc... in a loop. You need to wait for the next NMI every time. Doing it with an all-in-NMI approach is hard, you need to detect that you are in a "fading palette" state, and then detect if you're in a waiting state or if the wait is over and you should darken the palette, or if everything is over and you continue. If done in the main code, the program counter does all that work automatically, but you have to do it manually. But if this is more intuitive or easier for you, by all means go for it.
Re: NES games and differences in input reaction
by on (#204502)
Well... I already did program a fade system (fade in and fade out), and it happens every 2 frames (adjustable). I even use bit emphasis to add in between tones. This works right of the bat when I switched the logic to the main loop just now. edit: I guess this is working only because I am doing the code once and then waiting for vblank again, so it still is like NMI approach. I'll study this further.
Code:
lda fadestate
beq loop ; when fadestate is zero that means there is no fading going on, branch to the logic loop
bne fadepal ; the fadepal manager will decide which fade it is, based on fadestate's value, and then set a new fadestate value if that fade is done. This also means that while fading is going on, no game loop is run


And I don't clear the whole OAM buffer before writing to it like dougeff said, I only clear the trailing bytes. So I don't write twice. I take the oam position and fill the rest with #$FF after I'm done filling it with actual sprites. And I am filling the buffer in a different order every frame so I already have sprite flicker covered (for 8 sprites on the scanline). I even have the main character use a reserved section of the buffer so he never flickers.
Re: NES games and differences in input reaction
by on (#204504)
Oh by the way I forgot to address that:
Quote:
How can double dragon 1 sometimes take 11 frames to react?

Double Dragon games uses the button combination A+B to jump. It is almost impossible to require for the player to press those buttons at the same time, so when the game detect that A or B is pressed, very likely it waits a few frames to see if the player press the other button, if yes then the main character jumps, if no then it punches or kicks. 11 frames still sounds like quite a lot, are sure sure it's not less ? I'd say it's probably about 5 frames, although this must be verified. Also, one frame delay is compulsory because there's one frame delay between when the game decides to run the logic and when it's actually shown on screen.
Re: NES games and differences in input reaction
by on (#204505)
Bregalad wrote:
Double Dragon games uses the button combination A+B to jump. It is almost impossible to require for the player to press those buttons at the same time, so when the game detect that A or B is pressed, very likely it waits a few frames to see if the player press the other button

Very interesting, hadn't thought of that. The thing is, it doesn't just wait that long for A or B, it waits that long for any d-pad button too. That would have been unnecessary, imo.

Bregalad wrote:
11 frames still sounds like quite a lot, are sure sure it's not less ?

As I said in the original post, it is at a minimum 3, and sometimes more, up to 11.

Bregalad wrote:
Also, one frame delay is compulsory because there's one frame delay between when the game decides to run the logic and when it's actually shown on screen.

Yes, I already had understood this on the original post. See the list of games that take 2 frame advances to react.
Re: NES games and differences in input reaction
by on (#204508)
Re:input lag

Consider that some games might be doing acceleration at the sub-pixel level. So, it might only be moving the main character 0.3 pixels for the first few frames...making it appear like no movement has taken place.
Re: NES games and differences in input reaction
by on (#204509)
I once came to the conclusion that the game logic could be simplified a bit if video rendering lagged behind by one frame. There are certain inconsistencies involving object interactions and the camera (e.g. the camera follows the player, that can have its position modified by obstacles, that need the final position of the camera to be drawn) that can be avoided if you rendering everything one frame late, when all objects are guaranteed to have their final positions and states. There are of course solutions that don't require any lag, but they often require more CPU time (e.g. visiting objects more than once per frame).
Re: NES games and differences in input reaction
by on (#204511)
@dougeff: well, I tried several different types of moves for the games that didn't react as fast as possible (the games on the 3, 4, 5 and 6 list of the original post). I tried moving, attacking, jumping, etc, so I think that rules out the sub-frame movement issue.

@tokumaru, so that would explain the games on the "3" list on the original post? I think arkanoid is well programmed, at least it looks super clean and smooth, but it has that extra lag frame.
Re: NES games and differences in input reaction
by on (#204513)
I don't know, I haven't personally reverse-engineered any of those games, that was just a conclusion I came to when developing my own programs.
Re: NES games and differences in input reaction
by on (#204514)
dougeff wrote:
Consider that some games might be doing acceleration at the sub-pixel level. So, it might only be moving the main character 0.3 pixels for the first few frames...making it appear like no movement has taken place.

My nrom-template (along with snrom-template, lorom-template, and the Wrecking Ball Boy tech demo in Pygame, which have similar walking physics) has acceleration lag. Would it be a significant improvement in responsiveness to plug this by moving a stopped player character near the edge of the subpixel that he is facing?

tokumaru wrote:
There are of course solutions that don't require any lag, but they often require more CPU time (e.g. visiting objects more than once per frame).

The Curse of Possum Hollow visits objects twice. The overhead of this is minimal, about two scanlines, and it allows sprite cycling by visiting objects in a varying order. From memory, the logic is something like this:

Code:
; draw enemy closest to player and player
ldx high_priority_actor_id
bmi no_high_priority_actor
  jsr draw_actor_x
no_high_priority_actor:
lda mercy_flash_phase
bne player_hidden_by_mercy
  ldx #0
  jsr draw_actor_x
player_hidden_by_mercy:

; draw other enemies, giving each a chance to be first
ldx #NUM_ACTORS_ROUNDED_UP_TO_POWER_OF_2_MINUS_1
draw_actor_loop:
  txa
  eor flicker_bias  ; this varies each frame
  and #NUM_ACTORS_ROUNDED_UP_TO_POWER_OF_2_MINUS_1
 
  ; Skip already drawn or invalid actor IDs
  beq skip_drawing_actor  ; actor 0 is already drawn
  cmp #NUM_ACTORS
  bcs skip_drawing_actor  ; past the end of the non-PO2 actor table
  cmp high_priority_actor_id
  beq skip_drawing_actor  ; high-prio actor closest to player is already_drawn
    stx cur_turn
    tax
    jsr draw_actor_x
    ldx cur_turn
  skip_drawing_actor:
  dex
  bpl draw_actor_loop
Re: NES games and differences in input reaction
by on (#204518)
nesrocks wrote:
Bregalad wrote:
Double Dragon games uses the button combination A+B to jump. It is almost impossible to require for the player to press those buttons at the same time, so when the game detect that A or B is pressed, very likely it waits a few frames to see if the player press the other button

Very interesting, hadn't thought of that. The thing is, it doesn't just wait that long for A or B, it waits that long for any d-pad button too. That would have been unnecessary, imo.

For the D-pad part, I think it needs some buffer for performing the head butt move via double clicking pressing a direction twice. The game possibly checks whether a direction is kept pressed for a few frame, released for a few frames and then the same direction is pressed again to register it as a head butt (similar things should apply for fighting games with special moves performed with the direction keys, such as Street Fighter) and registers it as walking if the direction is kept pressed for more than some threshold number of frames.
Re: NES games and differences in input reaction
by on (#204521)
Gilbert wrote:
For the D-pad part, I think it needs some buffer for performing the head butt move via double clicking pressing a direction twice. The game possibly checks whether a direction is kept pressed for a few frame, released for a few frames and then the same direction is pressed again to register it as a head butt (similar things should apply for fighting games with special moves performed with the direction keys, such as Street Fighter) and registers it as walking if the direction is kept pressed for more than some threshold number of frames.

This does not require any additional delay, and I'm fairly sure Double Dragon's D-pad is very responsive. Only history of left/right button presses (or possibly time between last button state change) is required, waiting is not required. Only waiting for A+B for jumping is required.

@nesrocks: They way you count frames of delay should be wrong. I am fairly sure that there is a delay for punches and kicks, but it should be a constant amount of frames. It varying randomly between 3 and 10 is unthinkable. Simple quick testing with VirtuaNES indicates me a constant 6-frame delay.

Note that the delay between punches and kick is the reason why the game is challenging at all. If they were instantaneous (aka you press A and next frame your punch is in your opponent's face) then the game would be almost unloosable. That tiny window where the enemy can attack first is what makes the game dangerous, and as so, fun to play.

Dragon Warrior games as well as Ultima seems to wait that the engine's frame counter is at a multiple of 16 before starting any movement, probably because their scrolling engine is awfully simplified. This provides a delay varying randomly between 1 and 16 frames when moving to a direction after stopping, but no delay when moving and changing direction. This is acceptable (but annoying) because in RPGs timing is not very important, but this would be unacceptable for any action game.
Re: NES games and differences in input reaction
by on (#204524)
I'm not counting it wrong. Open double dragon 1 on fceux, pause the emulator, press and hold "A", hit frame advance 11 times and then the character starts the punch animation. I counted 14 right now on level 4 for the elbow attack. It is inconsistent. Yes, I am including lag frames. I could get it to respond in 2 frame advances when walking (not punching) at some point, but that was the record, not the rule.

Double dragon 2 and 3 are consistent. 6 frames.
Re: NES games and differences in input reaction
by on (#204559)
nesrocks wrote:
Double dragon 2 and 3 are consistent. 6 frames.

It was also consistent 6 frames for 1 for me.

A major problem with this method is that modern keyboards hardly support pressing multiple keys at once. Pressing a letter associated with the A button and then the space bar for frame advance simultaneously can get the OS confused about what to do and it is possible that the emulator does not frame advance even when you press the bar. This might be why either of us can get the count wrong (i.e. too many frames before action). At least for me counting was hard, sometimes it didn't work at all and the character wasn't punching. It's really tedious to see. Playing a "video" with frame advance, and pre-recorded buttons might be a better idea to do that but I don't know how to do it.
Re: NES games and differences in input reaction
by on (#204560)
A USB gamepad makes that problem very easy to solve. I tend to think of one as an essential debugging tool.
Re: NES games and differences in input reaction
by on (#204569)
I'm a veteran speedrunner, I know what I'm doing. The most basic thing is a frame advance... Here are my TAS: http://tasvideos.org/Subs-295up.html
My frame advance key is set to left control, so that problem is non existent. I configured it that way exactly because of that, and I do the same for every new emulator I use, so much so that if the emulator doesn't allow me to configure it like that I don't even use the emulator anymore. Besides, the keyboard ignoring keys is consistent. If A+X doesn't work that's because it won't ever work, so I couldn't be advancing just some frames. I'd be in an eternal stop if that was the problem. So no, I'm not counting it wrong.

What emulator are you using? Is it configured to ignore lag frames? It shouldn't be. As I said in the original post lag frames are included because they are part of the experience and add to the total real response time, which is the point of the whole test. In fact, ignoring lag frames is a terrible idea overall for testing anything. Turn it off and redo your tests.

Here's the thing, since there are lag frames:
walking may take 2-3 frames
kicking may take 5-6 frames
punching may take 11-12 frames
It all depends on when you pressed the button

I have tested double dragon U, double dragon J and even the beta rom and all of them are like this.