So...why not? May or may not implement this, but now I want to play with it. Generally, I've been preserving a subpalette for the menu area. I got the thought about possibly trying to swap the palette after the menu draw, since that area is always static, to maximize colors in gameplay area. Game has no scrolling. Started searching around the forums a bit and found some tips and tricks (and nightmares). I figured I'd toss it out there to see if anyone could help walk me through it.

I saw Tokumaru's responses about preloading A,X,Y with the values, that way you could set $2006 to $3fxx, bit the first write to %2007, then fire AXY as successive writes to $2007 to minimize time this would take. So...conceptually, I would...

1) Load palette with menubar subpal

2) Wait for sprite zero hit (which I'd put at the end of the menu bar), which would look something like:

Code:

checkSpriteZnotHit: bit PPUSTATUS bvs checkSpriteZnotHit

checkSpriteZhit: bit PPUSTATUS bvc checkSpriteZhit/code]

Then wait for hblank (how?)

3) Turn rendering off, then push the three new values to the subpal Then wait for next hblank (how?)

4) Turn rendering on and reset scroll.

That seems...too easy. Granted, I'm not trying to do any sort of scrolling or anything. Is it really that easy? I'm reading about waiting for hBlank, but haven't ever had to do that. How does one know when the hBlank fires (understand the concept of an hBlank, but don't know how to know when it fires like vBlank, or if it's even necessary). Or is it that sprite0 hit *forces* an hblank or something?

There's no signal in NES which tells you that hblank has started. You're going to have to use a timed delay loop (well, it doesn't have to be a loop specifically) after the sprite 0 hit. How long a delay depends on your sprite's X position. (E.g., if your sprite is at X=200, you're going to have to wait approximately 256-200=56 pixels to reach the right side of the screen, i.e., the start of hblank. That comes down to 56/3 ≈ 18.67 CPU cycles on NTSC machines, so about 9-10 NOP instructions would do the job in this case.)

The debugger in Mesen has a pretty cool feature that lets you see the screen as its drawing (Options -> Draw Partial Frame in the debugger window). That could come in useful when debugging things like this. You can also see the PPU cycle count (0-341 -- anything over 256 means you're in hblank).

Sprite 0 hit happens at a certain horizontal position on the scanline, and hblank begins at x=256. Each CPU cycle is worth three pixels. So if you have sprite 0 hit at (say) x=76, that means 256 - 76 = 180 pixels or 60 cycles from that point to the start of hblank. The end of your waiting loop will probably use 5 to 11 of those cycles.

; At this point, one of two things has happened: either sprite 0 hit, ; or sprite 0 missed and vblank began instead. Occasionally ; sprite 0 may miss in lag frames or in the first frame before the ; OAM DRAM controller becomes stable. Distinguish these and skip ; mid-frame effects if it missed. bmi sprite0_missed

So there are two ways to buy enough cycles to set up the PPU port write sequence to happen during horizontal blanking: sprite 0 on the left side of the same scanline or on the right side of the previous scanline.

In my NMI, rendering is off. This code just causes the game to hang indefinitely:

Code:

WaitNotSprite0: LDA $2002 AND #%01000000 BNE WaitNotSprite0

WaitSprite0: LDA $2002 #%01000000 BEQ WaitSprite0

LDX #$10 ;; arbitrary - variableWaitScanline: DEX BNE WaitScanLine

I'd delved deeper but kept freezing, so i figured I'd just start whittling away. It's the WaitSprite0 that causes it to hang. I also made absolute sure, in case it made a difference, that Sprite0 was being drawn on the screen (by literally drawing it just prior to this code). It still froze, gray screen. This is without any sprite0 effect...just the above code inserted in the NMI just prior to palette loads in otherwise working code.

This has nothing to do with the hanging, but here's a quick tip: to reduce the latency when detecting sprite 0 hits, use BIT instead of AND to test the flag:

Code:

WaitSprite0: BIT $2002 BVC WaitSprite0

BIT copies bits 7 and 6 of the read value to flags N and V, respectively, so you can test those bits more quickly. But even when you need to test bits other than 6 and 7, BIT still results in a shorter loop since you can preload the bit mask, reducing the latency anyway:

Actually, I did know that, but I was absently not thinking about the fact that only my MainGame state was drawing sprite 0...forgot to check the game state before doing this call. Oops! Thanks for the tip. Now let's see if I can get it working

I would actually recommend testing both vblank and sprite 0 hit together in the second wait loop:

Code:

lda #%11000000 : bit $2002 beq :-

If done correctly it should only ever exit the loop due to sprite 0 hit, but vblank is an appropriate fall-back in case some disaster causes that sprite 0 to miss. The fallback result wouldn't be pretty, probably it will drop to 50% framerate and be scrolled completely wrong, etc. but the game won't lock up, and if the player can manage to get themselves where it gets restored, they can get back on track without having to abandon and reset.

Just in case, might also be worth saying that you can have "opaque" pixels hit that are the same colour as the background, they just can't be colour index 0. Also the sprite background priority bit doesn't affect the hit test so you can put it "under" the background to hide it as well.

I'm making a bit of progress...right now, in just trying to successfully read a hit without glitching or locking up.

I can visibly see where I'm getting a split (right now, ugly horizontal line that flickers...i'm sure that's a timing issue) but unfortunately, the bigger problem is that:

a) I get a push (like the scroll is getting messed up...can mess with that a bit later)b) it seems like everything *above* the line is drawing from the wrong table, even though there haven't been any writes to 2000 (and even hard-writing something just before the sprite zero check doesn't help this).

Any ideas?

**** Actually, not sure what magic just happened but just going back through seemed to fix things. Huh. Ok. I think I'm right there.

********** Nope, nevermind. Here's what's happening.

(rendering is off)

Code:

;; checks game state...if not a screen where sprite 0 is drawn, skip this code

WaitSpriteNot0: BIT $2002 BVS WaitSpriteNot0

LDA #%11000000checkSprite0: bit $2002 BEQ checkSprite0

;;;;;; some arbitrary numbers in a dummy loop here to try to get to the end of the scanline ;;;;; should change a color in the last sub palette.;;;;;; this works with no issue if I don't do the sprite zero check;;;;; so something with the sprite zero check is the problem?DoSingColorSwap: LDA $2002 LDA #$3f STA $2006 LDA #$0c STA $2006 LDA #$30 STA $2007

If I skip the sprite 0 loop and just do the single color swap, no problem. Work's just fine, for the entire screen. But with the sprite 0 hit and trying to separate the screen, the color does not change, I get *animated junk* at the top, scroll value was pshed off, and it seems that in some spots it is drawing the right value (f5, which should be a blank tile) but from the wrong pattern table. I tried different versions of the sprite zero check discussed here. All with the same result.

Currently, i am drawing sprite zero at #$d0 if it helps (and it is definitely colliding with background).

I find this statement a bit confusing, because rendering must be on for the sprite hit to happen, and off for the palette update to happen, so rendering must be turned off after the hit and before the palette update. Is this what you're doing? Also, after the update, the scroll has to be restored (since you trashed it when updating the palette), and rendering turned back on.

Can you show the complete code for the split, even if it contains temporary junk?

Sorry - that was a misplaced note to myself. Yes, rendering is on for the eval.

Essentially, I load the palettes (all) then turn back on rendering, do the checks for sprite 0 hit, turn rendering back off, and then load the *other* palette* once the hit fires. I have tried zeroing out $2005 afterwards to no avail.

Right now, it looks like I'm getting closer, but my scroll is still off. Hm.

Yeah, I looked at that for a lot of reference. Everything seems fine, except for the sprite 0 hit. If I take the sprite zero hit out, i can change the palettes no problem. But as soon as i do the sprite 0 hit stuff, I crash and get all sorts of funky things happening with scroll. Hm.

Who is online

Users browsing this forum: No registered users and 0 guests

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum