Skip navigation
Welcome, Guest! Please Login or Join

Loading...

Top Status Bar and Controller Question

May 11, 2010 at 10:36:23 PM
bigjt_2 (17)
avatar
(Yeah, I'm a fat bastard.) < Meka Chicken >
Posts: 703 - Joined: 02/17/2010
Indiana
Profile
Hey Everyone,

I've been able to figure out how to get a status bar working at the bottom of the screen using sprite 0 collision (thanks to the help of albaily and thefox, of course).  Now I've been experimenting with moving the status bar to the top of the screen.  I cannot get it to work without it going all buggy.  Here's my NMI routine:

NMI:
  PHA             ;save registers in case of interrupt
  TXA
  PHA
  TYA
  PHA

  LDA #$00
  STA $2003       ; set the low byte (00) of the RAM address
  LDA #$02
  STA $4014       ; set the high byte (02) of the RAM address, start the transfer


  LDA needdraw
  AND #%00000001
  BEQ .skipcolumns

  JSR load_offscreen_tiles
  JSR load_offscreen_attributes

.skipcolumns:
  LDA needdraw
  AND #%00000010
  BEQ .skipscore
  JSR DrawScore

.skipscore:
  LDA soft_2000
  STA $2000
  LDA soft_2001
  STA $2001

.Scrolling:
  LDA $2002       ;reset the latch
  LDA xScroll
  STA $2005
  LDA #$00
  STA $2005

  LDA #$00
  STA sleeping

.Sprite0_testone:
  BIT $2002
  BVS .Sprite0_testone
.Sprite0_testtwo:
  BIT $2002
  BVC .Sprite0_testtwo

  LDA #%10010000
  STA $2000

  LDA $2002
  LDA #$00
  STA $2005
  STA $2005

  PLA             ; restore registers
  TAY
  PLA
  TAX
  PLA

  RTI             ; return from interrupt

I've attached the full ROM with all the asm and info files in a zip with this post.  At first I tried placing the $2000 and $2005 changes above the sprite 0 code and had it all at the beginning of NMI.  Also, I moved my Sprite 0 coordinates (found in init_PPU.asm) to intersect the lower edge of the status bar at the top of the screen.  For whatever reason, I thought that would work.  Plop.  It didn't.

Also, I've noticed I have a problem coding controller input.  Pushing the "A" and "B" buttons in this demo is supposed to increment/decrement that two-digit counter at the bottom by one.  Instead, it increment/decrements by 6-12 (it changes every time).  I'm guessing it's because each time I push a button, it picks it up over the course of many frames instead of just one, and hence reads it as though I pushed the button many times instead of just one.  Am I right?  If so, anyone know any smooth tricks around this?  I ran into the same problem awhile ago when I was trying to do a pause routine.

PS - Some of my comments may be incorrect in the ASM files (wrong decimal value, for instance)   Sorry if anyone runs into that.

-------------------------
Every thread on this forum is very offensive.  Please lock every last goddammed one of them!

"Tell him you'll break his A button pusher."
                                                  --Otto Hanson
"Unlike the Sega Genesis, which will give you cancer."
                                                  --Randy the Astonishing

May 12, 2010 at 8:38:55 AM
Mario's Right Nut (350)
avatar
(Cunt Punch) < Bowser >
Posts: 6574 - Joined: 11/21/2008
Texas
Profile
Don't do too much with scrolling, but check out the controller reading routine in my Background Compression tutorial that I stole from....someone. The D-PAD buttons only "work" when they are pressed after being released (or, rather, they don't work more than once if you hold the button down).

-------------------------

This is my shiny thing, and if you try to take it off me, I may have to eat you.

Check out my dev blog.



Edited: 05/12/2010 at 08:39 AM by Mario's Right Nut

May 12, 2010 at 5:49:59 PM
MetalSlime (0)
avatar
(Thomas Hjelm) < Crack Trooper >
Posts: 140 - Joined: 08/14/2008
Japan
Profile
Never messed with sprite-0 stuff myself, but if I were to guess how to do it, I'd try this:

1) Draw the status bar at the top of the nametable instead of the bottom.
2) At the end of NMI, set scroll to 0, 0
3) Wait for sprite 0
4) set scroll to scroll_x, 0

For the controller reading,?MRN has the right idea.  You want to make a distinction between a button that is pressed and one that is newly pressed (ie, wasn't pressed last frame).  To do that, you will need to save the button states for last frame:

read_controller:
    lda buttons
    sta buttons_old   ;save last frame's button state before getting the new one
    
    ;snip.. read controller and store result in buttons

    lda buttons_old    ;last frame's buttons
    eor #$FF             ;flip the bits, so 1=not pressed last frame, 0=pressed
    and buttons         ;and with this frame's buttons.
                              ;Only those buttons not pressed last frame and pressed this frame will return as 1.
    sta buttons_newly_pressed  ;store results.
    rts

-------------------------
MetalSlime runs away

My nesdev blog: http://tummaigames.com/blog...

May 12, 2010 at 6:52:58 PM
bigjt_2 (17)
avatar
(Yeah, I'm a fat bastard.) < Meka Chicken >
Posts: 703 - Joined: 02/17/2010
Indiana
Profile
Awesome! I'm crazy busy with work but I'll try this when I get some free time. Thanks MRN and Metalslime!  I think this is what I'm looking for.

-------------------------
Every thread on this forum is very offensive.  Please lock every last goddammed one of them!

"Tell him you'll break his A button pusher."
                                                  --Otto Hanson
"Unlike the Sega Genesis, which will give you cancer."
                                                  --Randy the Astonishing


Edited: 05/12/2010 at 06:53 PM by bigjt_2

May 12, 2010 at 8:39:16 PM
albailey (55)
avatar
(Al Bailey) < Lolo Lord >
Posts: 1521 - Joined: 04/10/2007
Ontario
Profile
Thats an awesome demo dude.

The premise of putting the status bar at the top, is to remember to reset both the nametable page (register $2000) as well as both scroll registers ($2005).

Then you wait for sprite zero to be reset (this happens at the end of vblank)
Then you wait for sprite zero to be set (this happens when the screen draws sprite zero, and at least two of its pixels intersect the status area)
Then you set the nametable correctly in register $2000 (either $2000 or $2400) and the scroll correctly.

Here's example code:

nmiHandler:
; NMIs can be called anywhere at any time, so lets protect A,X,Y by putting them on the stack
PHA ; 3 cycles
TXA ; 2 cycles
PHA ; 3 cycles
TYA ; 2 cycles
PHA ; 3 cycles so 13 CPU cycle setup cost to protect A,X,Y (and another 16 to restore things back at the end of the RTI)


LDA $2002 ; reset address latch


; update the graphics, etc..

; reset the status region to nametable of register PPU Control Register $2000 to be the nametable where the status region is located (usually $2000)
LDA #%10001000
STA $2000
; Reset the scrolling
LDA #$00
STA $2005
STA $2005

; sprite DMA
lda #$02
sta $4014

; Credit to DVDmth and DWEdit and Disch for helping me with sprite 0 detection
; I do not care what is in the accumulator. The BIT command will set overflow based on bit 6 of memory address ($2002)
; Basically here is what happens with Sprite #0. The hit flag is set and stays set for the entire frame and not cleared until scanline #0 starts (end of vblank)
; Hit flag gets set when a non color 00 background instersects a non 00 color sprite pixel. This cannot occurs at X position 255

; Wait for Scanline #0 to reset the Sprite #0 hit flag
: BIT $2002
BVS :-

; Wait for the first intersected pixel of sprite #0 to be rendered
: BIT $2002
BVC :-

; Now set the screen and scroll for the game part
LDA CURRENT_SIDE_SCROLLER_DATA
STA $2000

; FINE X scrolling updates right away, but I do not care so long as the status bar color is the same all the way through nametable $2000 and $2400. Otherwise I will see crawling.
LDA X_SCROLL
STA $2005 ; first write is X scrolling
LDA #$00
STA $2005 ; second write is Y scrolling

etc..
Al


-------------------------

My Gameboy collection  97% complete.          My N64 collection   88% complete



 My Gamecube collection  99% complete        My NES collection   97% complete


May 18, 2010 at 11:39:58 AM
bigjt_2 (17)
avatar
(Yeah, I'm a fat bastard.) < Meka Chicken >
Posts: 703 - Joined: 02/17/2010
Indiana
Profile
Sweet! Thanks Al! Sorry it took me forever to get back to this. Work's been NUUTS! Anyway, I'm going to start working on this and I'll let you know if I have any questions. It looks like you've left a very detailed good description, though, so hopefully I can get this. Thanks again!

-------------------------
Every thread on this forum is very offensive.  Please lock every last goddammed one of them!

"Tell him you'll break his A button pusher."
                                                  --Otto Hanson
"Unlike the Sega Genesis, which will give you cancer."
                                                  --Randy the Astonishing

May 18, 2010 at 12:02:50 PM
bunnyboy (81)
avatar
(Funktastic B) < Bowser >
Posts: 7474 - Joined: 02/28/2007
California
Profile
Originally posted by: albailey

; FINE X scrolling updates right away, but I do not care so long as the status bar color is the same all the way through nametable $2000 and $2400. Otherwise I will see crawling.
LDA X_SCROLL
STA $2005 ; first write is X scrolling
LDA #$00
STA $2005 ; second write is Y scrolling

What I have done is timed loops starting when the sprite 0 hit happens.  If you can get your $2005 writes to happen at the end of the scanline, when the PPU is fetching sprite data, you won't see any graphical glitches.  Sprite fetching is long enough to account for the variable width crawl.

May 19, 2010 at 1:27:02 PM
bigjt_2 (17)
avatar
(Yeah, I'm a fat bastard.) < Meka Chicken >
Posts: 703 - Joined: 02/17/2010
Indiana
Profile
Hey Folks,

Got it working on the top.  Thanks again, Al!  I'm posting the new demo in case any other noobs like myself are messing around with scrolling/Sprite 0 split and need a working demo to reference for their own projects.

Also, this one doesn't have the updating counter on the scrolling bar, but I did get the better controller reading working on the demo with the status bar at the bottom, as well.  So thanks for the help with controller input, Metalslime and Mario's Right Nut.  That also helped me finally get a pause function working on the pong game I made.  Woo-hoo!

Lastly, I took an hour and cleaned up my comments so they ACTUALLY reflected the code.  Novel idea, I know.  I will warn that the comments on the demo with status bar at the bottom have not been checked over and are inaccurate.  The comments in this demo should be fine, though.

-------------------------
Every thread on this forum is very offensive.  Please lock every last goddammed one of them!

"Tell him you'll break his A button pusher."
                                                  --Otto Hanson
"Unlike the Sega Genesis, which will give you cancer."
                                                  --Randy the Astonishing


Edited: 05/19/2010 at 01:31 PM by bigjt_2

May 20, 2010 at 1:44:29 PM
NESHomebrew (20)
avatar
(Brad Bateman - Strange Brew Games) < King Solomon >
Posts: 4203 - Joined: 04/28/2008
Saskatchewan
Profile
I'll have to bookmark this so I can try it when I get home.

May 20, 2010 at 2:18:31 PM
MODERATOR
KHAN Games (88)
avatar
(Kevin Hanley) < Master Higgins >
Posts: 7760 - Joined: 06/21/2007
Florida
Profile
Ohh, thanks for this. I was wanting to learn how to load different nametables ahead of time for scrolling, so I'll definitely take a look at this!

May 20, 2010 at 3:22:55 PM
albailey (55)
avatar
(Al Bailey) < Lolo Lord >
Posts: 1521 - Joined: 04/10/2007
Ontario
Profile
Originally posted by: bunnyboy

Originally posted by: albailey

; FINE X scrolling updates right away, but I do not care so long as the status bar color is the same all the way through nametable $2000 and $2400. Otherwise I will see crawling.
LDA X_SCROLL
STA $2005 ; first write is X scrolling
LDA #$00
STA $2005 ; second write is Y scrolling

What I have done is timed loops starting when the sprite 0 hit happens.  If you can get your $2005 writes to happen at the end of the scanline, when the PPU is fetching sprite data, you won't see any graphical glitches.  Sprite fetching is long enough to account for the variable width crawl.

One other observation about crawling, but not directly pertaining to "fine X" scrolling.

I had a bug a while back where I was using a status area at the bottom of the screen, and was placing the sprite zero on the top row of that status area (around row 22).

My bug was that because I placed the sprite zero in the status area, a portion of that status area would scroll as part of the game scrolling region. This was noticeable because I made the status region not run the entire width of the screen.  This meant I had not used a solid line at the top of my status area, and I could visually see it moving across the screen. 

The bug was actually more serious than just a graphical glitch, because the crawling meant that when an all transparent background  tile scrolled to the location of the sprite zero, I did not get my sprite zero collision, and therefore my NMI routine never returned properly, etc..

I would not have had this problem with a status region at the top of the screen, because the only "crawling" that would be seen is the fine X scroll that Brian alluded to in his post.

A possible work around would have been to locate sprite zero above the status area, but in my opinion that can also lead to trouble, since you need to remember to make sure you do not have fully transparent background blocks in the game area for that row, otherwise you can hit the same problem.

So in summary, if you are going to put a status area on the bottom of your screen, make sure you load it into both $2000 and $2400 nametables, and make sure that at least the top line of the status region runs continuously the entire width. 

Al


-------------------------

My Gameboy collection  97% complete.          My N64 collection   88% complete



 My Gamecube collection  99% complete        My NES collection   97% complete


May 20, 2010 at 5:34:49 PM
bigjt_2 (17)
avatar
(Yeah, I'm a fat bastard.) < Meka Chicken >
Posts: 703 - Joined: 02/17/2010
Indiana
Profile
Originally posted by: albailey


So in summary, if you are going to put a status area on the bottom of your screen, make sure you load it into both $2000 and $2400 nametables, and make sure that at least the top line of the status region runs continuously the entire width. 

Al



I actually noticed this, too, when I first started messing around with the Sprite 0 code a couple weeks ago.  I was originally trying to make my status bar like SMB1s where it seems transparent and only the bottom of the coin is the sprite used for intersection.  As soon as that sprite leaves the non-transparent pixels background, everything crashes.  The best thing to do is what Al suggested above.  I still have no clue how SMB1 got it to work.  (Perhaps moved the sprite as the screen scrolled?  I have no idea.)  But then I guess that game is programmed a little oddly, from what I've heard.

-------------------------
Every thread on this forum is very offensive.  Please lock every last goddammed one of them!

"Tell him you'll break his A button pusher."
                                                  --Otto Hanson
"Unlike the Sega Genesis, which will give you cancer."
                                                  --Randy the Astonishing

May 20, 2010 at 5:38:20 PM
bigjt_2 (17)
avatar
(Yeah, I'm a fat bastard.) < Meka Chicken >
Posts: 703 - Joined: 02/17/2010
Indiana
Profile
Originally posted by: mewithoutYou52

Ohh, thanks for this. I was wanting to learn how to load different nametables ahead of time for scrolling, so I'll definitely take a look at this!


If anyone has any ?s, feel free to PM me or post on the thread.  That background scroller may not be the most ideal, it's just what I've been able to make work so far.  Mario's Right Nut found a bug yesterday where it malfunctions if you change the amount of INC/DEC on the xScroll variable.  I have a temporary working fix that requires changing a couple of hard-coded numbers in the main ASM file.  If anyone else runs into it, let me know and I'll tell you which two numbers to change.

-------------------------
Every thread on this forum is very offensive.  Please lock every last goddammed one of them!

"Tell him you'll break his A button pusher."
                                                  --Otto Hanson
"Unlike the Sega Genesis, which will give you cancer."
                                                  --Randy the Astonishing