It is currently Thu Dec 14, 2017 10:19 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 42 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
PostPosted: Fri Aug 26, 2016 7:16 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19343
Location: NE Indiana, USA (NTSC)
Controller reading in the NMI and game logic in the main thread could cause your game logic to miss presses, especially if the NMI handler also calculates the "pressed or released since last frame" flag.


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 12:35 am 
Offline
Site Admin
User avatar

Joined: Mon Sep 20, 2004 6:04 am
Posts: 3487
Location: Indianapolis
tokumaru wrote:
Don't forget about raster effects. If you have a sprite 0 status bar, effects based on IRQs, and stuff like that, you also need to reset them for the new frame, otherwise you'll get glitched frames every time there's slowdown.

Ah yeah. On that topic too, I think it's crazy that so many games have the sprite 0 status bar on the bottom of the screen (looking at you, Rare!), that trick is a lot fancier than most (non-dev) people would think. You can't even have a frame-time overflow in the case. I mean, you can without a complete disaster, but it'll look like Konami's first TMNT game - maybe the glitchiest status bar ever?

tepples wrote:
Memblers wrote:
I've been doing a soundtrack for a game I'm making and I haven't even started considering sound effects yet, but I've had my old Nerdtracker 2 habits in mind.

As far as I know, of the current game-oriented homebrew NES sound drivers, only Pently supports NT2-style decaying envelopes.

Oh man, kill it with fire.. :lol: I'll always love NT2 but I don't make new stuff in it. I spent so much effort working around that to make it sound better without knowing why exactly, didn't realize at the time that because the NES volume control is linear, a linear fade sounds terrible. That's why the NES's hardware decay sounds so distinctive and weird, it's just.. wrong. A built-in logarithmic decay could be useful perhaps, I suppose everyone will just build their own envelopes to do it themselves, though. But, being able to scale that (like the FT2's volume control channel) is something I really like, I'm glad you're considering that for the future. I suppose it can be quickly done with a 4-bit x 4-bit look-up table?

I had it in my head that Pently only accepted MML-type input, but looking into it again I see that NovaSquirrel had made a Famitracker converter for it. With that, I am immediately intrigued. The little testing I did previously seemed to have Pently appearing to be CPU efficient to an impressive degree, that's definitely something I will be exploring!


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 2:56 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2982
Location: Tampere, Finland
Memblers wrote:
Ah yeah. On that topic too, I think it's crazy that so many games have the sprite 0 status bar on the bottom of the screen (looking at you, Rare!), that trick is a lot fancier than most (non-dev) people would think. You can't even have a frame-time overflow in the case. I mean, you can without a complete disaster, but it'll look like Konami's first TMNT game - maybe the glitchiest status bar ever?

In some earlier discussions we figured that this is probably because it's much more difficult to set the scroll arbitrarily mid-screen than in VBlank. Few developers seemed to manage it back in the day (like Rare in Battletoads). But it is indeed a PITA to have the status bar at the bottom without mapper IRQs.

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


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 3:19 am 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1515
thefox wrote:
In some earlier discussions we figured that this is probably because it's much more difficult to set the scroll arbitrarily mid-screen than in VBlank.

What's so difficult about it? My game is mapper 0 without any fancy stuff and yet I easily managed clean parallax scrolling.*
Just make sure that there's one pixel line that consists of all the same color. Put the sprite 0 there. And then set the scrolling. The scrolling change will be done before rendering the line is over and since the line consists of pixels of the same color, the player won't notice any artifacts.

* In fact, I do three scrolling changes per frame:
First one in NMI that goes to scrolling position 0.
Then the status bar is drawn. While this is done, I do some game logic whose duration is always pretty constant.
Then I wait for the nine sprites per scanline flag because I positioned nine empty sprites below the status bar. There, I set the scrolling for the background.
Then the background is drawn. In the meantime, I do the majority of the game logic.
Then sprite 0 split.
Then the foreground is drawn and I use the remaining time for some other constant-time logic.

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 3:35 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2982
Location: Tampere, Finland
DRW wrote:
thefox wrote:
In some earlier discussions we figured that this is probably because it's much more difficult to set the scroll arbitrarily mid-screen than in VBlank.

What's so difficult about it? My game is mapper 0 without any fancy stuff and yet I easily managed clean parallax scrolling.

Setting the X scroll is trivial (they managed that even in SMB1), but setting the Y scroll with pixel precision is rather involved. See http://wiki.nesdev.com/w/index.php/PPU_ ... g#Examples

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


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 3:39 am 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1515
Oh, you're talking about vertical scrolling. Sorry, I thought it was just about status bar on top vs. status bar at the botton.

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 7:15 am 
Offline
User avatar

Joined: Sat Nov 13, 2004 9:43 pm
Posts: 316
Location: Ohio, USA
tepples wrote:
Controller reading in the NMI and game logic in the main thread could cause your game logic to miss presses, especially if the NMI handler also calculates the "pressed or released since last frame" flag.


It sounds like I need to move the controller code out of the NMI then if it's going to be buggy.

Now I'm back to the beginning. Should I make a loop in the reset to run the controller and logic code?

For example.

Code:

LDA #%10010000    ; enable NMI, background $1000 VRAM, sprites $0000 VRAM
STA $2000         ; sprite size 8x8, PPU increment 1, name table $2000 VRAM
LDA #%0011000     ; background visible, sprites visible, background & sprites clipped
STA $2001         ; color display

startloop:

JMP startloop



Where I have the JMP startloop is where I should put logic code instead? One time I tried putting code there and it was running way faster than it should be. I also ran the sound driver init here once and the NTSC music driver I was using sped up big time, sounded like PAL. So then I tried keeping code out of there because at the time I didn't have the skill to work out some type of timing or I just had the wrong idea. This has always been a problem for me.

_________________
Gil-Galad


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 7:18 am 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1868
Location: DIGDUG
You don't need to move the controller code, unless you're making a zapper game. :)

Wait, no, tepples is right..IF your game logic goes longer than 1 frame, the logic will miss a change in button presses event. (Events like, Title Screen, exit if Start wasn't pressed last frame && Start is pressed this frame)

Move the jsr button_check to the infinite loop.

EDIT...
Have a flag for when the game logic is done, and only check buttons if it is set, or something like that.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 8:07 am 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1515
Gil-Galad wrote:
Now I'm back to the beginning. Should I make a loop in the reset to run the controller and logic code?


I'm writing you a shortened version of my own code. This works without problems and the NMI only does stuff that needs to be done during vblank.

Code:
Reset:
   ; All the initialization stuff.
   ; ...

@gameLogic:
   LDA WaitForNmi
   BNE @end
   JSR ControllerInput
   JSR GameLogic
   LDA #true
   STA WaitForNmi
@end:
   JMP @gameLogic

Nmi:
   PHA
   TXA
   PHA
   TYA
   PHA
   LDA WaitForNmi
   BEQ @end
@nmiStart:
   LDA #false
   STA WaitForNmi
   LDA PpuMaskValue
   STA PpuMask
   BEQ @end
   LDA #<Sprites
   STA OamAddr
   LDA #>Sprites
   STA OamDma
   JSR UpdatePpu
   JSR SetScrolling
@end:
   JSR SoundUpdate
   PLA
   TAY
   PLA
   TAX
   PLA
   RTI

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 8:20 am 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1515
dougeff wrote:
IF your game logic goes longer than 1 frame, the logic will miss a change in button presses event.

Why is this a bad thing? Of course, if your game lags, the controller won't be updated until the logic is done. But that's what it's supposed to do.

If I read the controller in every NMI interrupt call, even if my game logic isn't finished yet, then this means that half of the logic will do status updates based on another input than the other half:

- Read Controller: Player presses right.
- Start move function: Update vertical movement based on player pressing right.
- Continue move function: Update weapon attack based on player pressing right.
- Oops! Lag. NMI interrupts the program and reads the controller again: Player presses left.
- Continue move function: Update horizontal movement based on player pressing left.
--> Inconsistency! The value changed in the middle of a function that was never meant to handle a change of the value.

You want that?

This one is better in my opinion:

- Read Controller: Player presses right.
- Start move function: Update vertical movement based on player pressing right.
- Continue move function: Update weapon attack based on player pressing right.
- Oops! Lag. NMI interrupts the program, but doesn't read the controller again: Player presses left, but the value is still set to right.
- Continue move function: Update horizontal movement based on player pressing right.
--> No inconsistency at all. The game logic will recognize the new button press at the start of the next frame when the game logic starts again.

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 8:37 am 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1046
Quote:
Why is this a bad thing? Of course, if your game lags, the controller won't be updated until the logic is done. But that's what it's supposed to do.

You're misunderstanding. It's not about the a change in button state during lag not being read. That is indeed expected and normal. It's about a change in button state during lag being read, and then having an undesired effect.

NMI happens at ~60 FPS while it's enabled regardless of anything. I am reading my controller in the NMI, and so by extension it's happening at ~60FPS regardless of anything.

My game loop takes too long.

Code:
GAMELOOP STARTS
NMI OCCURS: I have pressed A.
GAMELOOP CONTINUES
NMI OCCURS: I am still holding A. My "press" of A has become a hold.
GAMELOOP CHECKS FOR A PRESS OF A TO JUMP. But I am now holding A because the NMI hit twice during the game loop.
The jump fails.

This is the case people are saying he should look out for when reading from the NMI.

Yes, you can read the joypad but not update whatever controls presses vs holds in your game in the NMI, and yes, you can conditionally not read/update the joypad in the NMI if the game loop has taken too long. But you wouldn't need those extra conditions at all if you just read the joypad not in your NMI.

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


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 9:10 am 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1515
Kasumi wrote:
Code:
GAMELOOP STARTS
NMI OCCURS: I have pressed A.
GAMELOOP CONTINUES
NMI OCCURS: I am still holding A. My "press" of A has become a hold.
GAMELOOP CHECKS FOR A PRESS OF A TO JUMP. But I am now holding A because the NMI hit twice during the game loop.
The jump fails.

This is the case people are saying he should look out for when reading from the NMI.

That's why I think you should never read the controller during NMI, but at the start of the game logic:

Code:
CONTROLLER READING: I have pressed A.
GAMELOOP STARTS
NMI OCCURS: I am still holding A. But it isn't read. So, it doesn't become a hold.
GAMELOOP CONTINUES
NMI OCCURS: I am still holding A. But it isn't read. So, it doesn't become a hold.
GAMELOOP CHECKS FOR A PRESS OF A TO JUMP. Everything is fine. It's not a hold.


Kasumi wrote:
But you wouldn't need those extra conditions at all if you just read the joypad not in your NMI.

Exactly. So, why is reading the controller in the NMI an issue at all?

Even if I absolutely have to read the controller in NMI for some reason, it would still be trivial to avoid this problem: You don't need to implement any special conditions.
Since you need to have a condition to leave the NMI early anyway:
Code:
Nmi:
   PHA
   TXA
   PHA
   TYA
   PHA
   LDA WaitForNmi
   BEQ @end
@nmiStart:
   LDA #false
   STA WaitForNmi
   LDA PpuMaskValue
   STA PpuMask
   BEQ @end
   LDA #<Sprites
   STA OamAddr
   LDA #>Sprites
   STA OamDma
   JSR UpdatePpu
   JSR SetScrolling
@end:
   JSR SoundUpdate
   PLA
   TAY
   PLA
   TAX
   PLA
   RTI

you would just add this:
Code:
Nmi:
   PHA
   TXA
   PHA
   TYA
   PHA
   LDA WaitForNmi
   BEQ @end
@nmiStart:
   LDA #false
   STA WaitForNmi
   LDA PpuMaskValue
   STA PpuMask
   BEQ @end
   JSR ReadController ; --> New code.
   LDA #<Sprites
   STA OamAddr
   LDA #>Sprites
   STA OamDma
   JSR UpdatePpu
   JSR SetScrolling
@end:
   JSR SoundUpdate
   PLA
   TAY
   PLA
   TAX
   PLA
   RTI

That's it. Controller reading in NMI without any issues and without any additional dedicated code to check for lag in the controller routine.

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 9:17 am 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1046
Quote:
That's why I think you should never read the controller during NMI, but at the start of the game logic:

I'm not sure we're reading the same things. That's what everyone is saying!
Quote:
Exactly. So, why is reading the controller in the NMI an issue at all?

For that reason I said? Also note that I said this too:
Quote:
Yes, you can read the joypad but not update whatever controls presses vs holds in your game in the NMI, and yes, you can conditionally not read/update the joypad in the NMI if the game loop has taken too long. But you wouldn't need those extra conditions at all if you just read the joypad not in your NMI.

It's like... so we're warning him about a thing that can happen. And you're posting ways to fix that thing that can happen to say it's not a problem. And yeah, it's not a problem if you know about it. But... we warned him because he may not know about it, but also because there are better ways to do it. See the first thing I quoted from you in this post. Does that make sense?

Maybe you don't need an extra condition, but it depends on your setup. And again: It's more about, "Hey, know about this thing." It's not, "Never do this thing, because there's no way around it." It's, "Here's a better way so you don't have to even think about it."

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


Last edited by Kasumi on Sat Aug 27, 2016 9:21 am, edited 1 time in total.

Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 9:20 am 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1868
Location: DIGDUG
DRW's example would work fine. That's basically what I do....

The first example that starts off like
Quote:
I'm writing you a shortened...

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Sat Aug 27, 2016 9:29 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2982
Location: Tampere, Finland
Has anybody done measurements on what is a typical minimum "pulse width" on button presses (or releases) that one can expect? That is, if a player quickly taps the button. Or, holds it down, quickly releases it and then holds it down again.

I guess I might throw together a small test ROM for it.

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


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 42 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 5 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