It is currently Mon Oct 23, 2017 4:55 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 35 posts ]  Go to page 1, 2, 3  Next
Author Message
 Post subject: scanline "detecting"
PostPosted: Sun Feb 13, 2005 9:52 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10067
Location: Rio de Janeiro - Brazil
Hi!

I'd like to discuss ways to know when is the right time to change stuff in the screen mid-frame. I'd like to know what you guys do...
I want to ask you a couple of things about the methods I know:

Sprite 0 hit:
1.does it work ok if the sprite has low priority?
2.if the left 8 pixels of the bg are disabled, does it work (I gess not, because of the "nothing to colide with" thing)?
3.it can be used only once in a frame? can't I change the position of the sprite and wait for another hit?
4.(not actually sprite 0)Bregalad said he intented to do it by putting 9 sprites in the desired scanline, and since the ppu warns us of this every scanline, it can be reused. The problem is if you accidentaly put 9 sprites in a scanline...

Timed code:
1.doesn't it eat all your time? Since you can't do anything else but wait for the time to do stuff. It seems good for demos, but useless for actual games since there would be no time left for anything else...
2.one scanline does not last an integer number of cycles, how do you compensate that?
3.what math do you do when calculating cycles and all?
4.when do you start counting? as soon as vblank ends?(can you detect the end of a vblank? when bit 7 of $2002 turns 0 means you just left vblank?)

I have no intention to use mappers with scanline counting capabilities for now. That's why I'm researching to see how far I can get using what the NES gives us.

I'm betting on the Sprite options, with a little help of timed code. With sprites I have time left to do other stuff, like physics calculations and all sorts of things games need. I just have to make sure my code does not go beyond the point I want to do the "magical" stuff. But then, I could do it like this: if the "point" is before the middle of the screen, wait for it and then do the other stuff, or, if it is after the middle, do the stuff and then wait. I cut my time in half like this, but at least I get some time!

Answers and opinions appreciated! =)
Thank you in advance!

Tokumaru


Top
 Profile  
 
 Post subject: Re: scanline "detecting"
PostPosted: Sun Feb 13, 2005 10:13 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19116
Location: NE Indiana, USA (NTSC)
tokumaru wrote:
Sprite 0 hit:
1.does it work ok if the sprite has low priority?

You mean the "behind" bit set? Yes.

Quote:
2.if the left 8 pixels of the bg are disabled, does it work (I gess not, because of the "nothing to colide with" thing)?

Visible sprite has to overlap visible background, and it can't be in the rightmost pixel column (x=255) either.

Quote:
3.it can be used only once in a frame? can't I change the position of the sprite and wait for another hit?

You can't change the position of a sprite in mid-frame without DMAing OAM again, and for that you have to turn off rendering for at least five scanlines. Bigfoot does this.

Quote:
The problem is if you accidentaly put 9 sprites in a scanline...

This is a problem, unless you use Atari 2600 style game designs that ensure that 9 sprites will never wander into a scanline.

Quote:
Timed code:
1.doesn't it eat all your time?

Not if you only do it for a small portion of the screen. Look at Rad Racer, and notice that it does timed code only for a small part of the screen, starting at sprite 0 hit and ending several dozen scanlines later. You have from the top of the screen until sprite 0 hit to do game logic, and you have from the top of the status bar until the bottom of the screen to do game logic.

Quote:
It seems good for demos, but useless for actual games since there would be no time left for anything else...
2.one scanline does not last an integer number of cycles, how do you compensate that?

In your scanline loop, use a piece of code that will run one cycle longer 67 percent of the time:
Code:
  clc
  lda subcycle
  adc #171
  sta subcycle
  bne :+
:


Quote:
4.when do you start counting? as soon as vblank ends?

Normally, you start counting after sprite 0 turns on.

Quote:
(can you detect the end of a vblank? when bit 7 of $2002 turns 0 means you just left vblank?)

No. Bit 7 of $2002 will turn 0 right after you read it. The easiest way to detect the end of vblank is when the sprite 0 bit turns off.

Quote:
I'm betting on the Sprite options, with a little help of timed code. With sprites I have time left to do other stuff, like physics calculations and all sorts of things games need. I just have to make sure my code does not go beyond the point I want to do the "magical" stuff. But then, I could do it like this: if the "point" is before the middle of the screen, wait for it and then do the other stuff, or, if it is after the middle, do the stuff and then wait. I cut my time in half like this, but at least I get some time!

Or divide your "stuff" (game logic) into several pieces of execution, such as multiple passes over the data or one pass over several pieces of data, and execute only some parts of game logic before the split and some after.


Top
 Profile  
 
 Post subject: Re: scanline "detecting"
PostPosted: Sun Feb 13, 2005 10:24 pm 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1845
tokumaru wrote:
3.it can be used only once in a frame? can't I change the position of the sprite and wait for another hit?


tepples pointed out why this would be difficult. But even if moving the sprite were simple (which it might be... I don't see why a $2004 write wouldn't do the trick) it still wouldn't work. Once the Sprite 0 flag is raised... it remains raised until the end of VBlank next frame. So this is a once-per frame deal.

Quote:
4.(not actually sprite 0)Bregalad said he intented to do it by putting 9 sprites in the desired scanline, and since the ppu warns us of this every scanline, it can be reused. The problem is if you accidentaly put 9 sprites in a scanline...


The exact cycle on when this would occur is questionable... but same with sprite 0. This is a once-per-frame deal. Once the 9-sprite flag is raised... it stays raised until the end of next VBlank.

The PPU does not refresh the flag every scanline -- I think some emus emulate it that way but I'm pretty sure they're mistaken in doing so.

I think tepples covered the rest nicely.


Top
 Profile  
 
 Post subject: Re: scanline "detecting"
PostPosted: Sun Feb 13, 2005 10:45 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10067
Location: Rio de Janeiro - Brazil
Quote:
You mean the "behind" bit set? Yes.
That's good... (from now on, only bad news, I see...)

Quote:
Visible sprite has to overlap visible background, and it can't be in the rightmost pixel column (x=255) either.

I expected that... but the rightmost pixel thing is new to me! Where would you usualy want the hit to happen if you want to apply the changes on the start of an scanline? Must you put it in the scanline before in order to have some time?

Quote:
You can't change the position of a sprite in mid-frame without DMAing OAM again, and for that you have to turn off rendering for at least five scanlines. Bigfoot does this.

Can't it be done via $2003-$2004? You have to turn sprites off to mess with them too? I thought this was a bg thing only...

Quote:
Normally, you start counting after sprite 0 turns on.

Makes sense!

Quote:
No. Bit 7 of $2002 will turn 0 right after you read it. The easiest way to detect the end of vblank is when the sprite 0 bit turns off.

Supposing it got set in the previous frame, right? It is quite bad that bit 7 of $2002 is cleared on read.

Quote:
Or divide your "stuff" (game logic) into several pieces of execution, such as multiple passes over the data or one pass over several pieces of data, and execute only some parts of game logic before the split and some after.

Yeah... thanks for the help!


Top
 Profile  
 
 Post subject: Re: scanline "detecting"
PostPosted: Sun Feb 13, 2005 11:01 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10067
Location: Rio de Janeiro - Brazil
Disch wrote:
tepples pointed out why this would be difficult. But even if moving the sprite were simple (which it might be... I don't see why a $2004 write wouldn't do the trick) it still wouldn't work. Once the Sprite 0 flag is raised... it remains raised until the end of VBlank next frame. So this is a once-per frame deal.


As expected... I also thought moving sprites was an easy thing...

Quote:
The exact cycle on when this would occur is questionable... but same with sprite 0. This is a once-per-frame deal. Once the 9-sprite flag is raised... it stays raised until the end of next VBlank.

The PPU does not refresh the flag every scanline -- I think some emus emulate it that way but I'm pretty sure they're mistaken in doing so.


I got the impression (from reading the docs) that this bit would change every scanline.

Well, at least we got two sprite-based ways to do the trick... each one with their advantages and disadvantages... With sprite 0 you have to make sure a visible pixel in the sprite will meet a visible pixel in the bg. With the 9 sprites thing you must be careful not to let it happen in the wrong place, before the place you actually want. Gotta love the NES! =D


Top
 Profile  
 
 Post subject: Re: scanline "detecting"
PostPosted: Mon Feb 14, 2005 4:14 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7235
Location: Chexbres, VD, Switzerland
Quote:
Well, at least we got two sprite-based ways to do the trick... each one with their advantages and disadvantages... With sprite 0 you have to make sure a visible pixel in the sprite will meet a visible pixel in the bg. With the 9 sprites thing you must be careful not to let it happen in the wrong place, before the place you actually want. Gotta love the NES! =D

The 9 sprites thing also has the inconvenient to be very badly emulated for now. In all emulators I checked, only FCEUltra and Nintedulator are doing it right. If the flags get clearing after the next scanline this isn't much important scince you detect it just one time, but in VirtuaNES and Nester it's already set when 8 sprites are on the same scanline. I was planning to have a sprite-only stauts bar and having just 8 elements per line is already very restricted. So this flag woulb be set too early and the status bar will be turned off too early.
It's also possible to have a 100% time VBlank code. Look at Final Fantasy (1, 2 and 3) they all have a cool effect when wrapping from a place to another. What the code do is turn both sprites and BG off, wait end of VBlank, wait a variable number of scanlines, turn on BG wait another variable number of scanlines, and definitively turn off the BG. From here the waiting part is finished. (Final Fantasy 2 and 3 improved this stuff and change the scrolling midframe while wriapping on the overworld map).
Also, there is a more impressive timed stuff in Final Fantasy. When you light an orb, a light beam is done with the $2001.0 "grayscale" bit. At VBlank the code does sprite DMA, then wait the end of the VBlank, then turn the grayscale mode on, wait some cycles, turn if off, wait the remaining scanline time (it waits a 114 cycles, a bit more than one scanline, this is the reason why the beam is diagonal). The only emulator that does correcly emulate this is Nintendulator.
I think it sould be possible to do better thing with 100% timed code. For example, in a NMI, you can upload data to the name table and attribute table, set scrooling and $2000 reg, do sprite DMA, and then wait for X time. Joypad and Music could wait for after the mid-frame change. Scince all data to write to the PPU are stored in buffers, it would always take the same amount of time. If no data have to be written to the PPU, the previous data will be written every frame indefinitively.

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
 Post subject: Re: scanline "detecting"
PostPosted: Mon Feb 14, 2005 6:31 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10067
Location: Rio de Janeiro - Brazil
Quote:
In your scanline loop, use a piece of code that will run one cycle longer 67 percent of the time:
Code:
  clc
  lda subcycle
  adc #171
  sta subcycle
  bne :+
:



I read somewhere that most changes you do to the ppu only become visible in the next scanline. Is that true? If it is it's, the "fraction of cycle" thing is not such a big problem, right?


Top
 Profile  
 
 Post subject: Re: scanline "detecting"
PostPosted: Mon Feb 14, 2005 8:58 am 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1845
Quote:
I read somewhere that most changes you do to the ppu only become visible in the next scanline. Is that true? If it is it's, the "fraction of cycle" thing is not such a big problem, right?


On the contrary. Most things take effect immediatly. The only thing that's 'delayed' is CHR swapping... which is because tile graphics are loaded ~16 pixels before they're actually drawn to the screen. Sprite stuff might also be delayed until the next scanline (due to sprite in range evaluations being done on the previous scanline).

And @ Bregalad: I thought a few emus did the FF1 effect properly (I remember Fx3 stepping in saying RockNES does it right... and I know my emu does it-- though it's not released =P)


Top
 Profile  
 
 Post subject: Re: scanline "detecting"
PostPosted: Mon Feb 14, 2005 10:33 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10067
Location: Rio de Janeiro - Brazil
Quote:
Quote:
I'm betting on the Sprite options, with a little help of timed code. With sprites I have time left to do other stuff, like physics calculations and all sorts of things games need. I just have to make sure my code does not go beyond the point I want to do the "magical" stuff. But then, I could do it like this: if the "point" is before the middle of the screen, wait for it and then do the other stuff, or, if it is after the middle, do the stuff and then wait. I cut my time in half like this, but at least I get some time!

Or divide your "stuff" (game logic) into several pieces of execution, such as multiple passes over the data or one pass over several pieces of data, and execute only some parts of game logic before the split and some after.

The reason I have to do it that way is because I don't know where the "split" is gonna be. It's dynamic, like the water line in a game that can scroll vertically: the water can start at the very bottom of the screen or at the very top. Or not show up at all. That way I can't know at coding time how to split game logic, it is not a static thing. That's why I thought of the method I described.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 14, 2005 12:37 pm 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1845
Timing like this can be tricky. Usually, games which need this king of timing fall back on IRQs. If you don't want to rely on a mapper which has IRQ generation... you could fall back to using DMC irqs.

Getting the exact cycle down with the DMC would be VERY VERY difficult. Some codemaster games do it (Mig-29 Soviet Fighter comes to mind). However you could do a combination of DMC IRQ and sprite 0 hit. Just get the DMC to approximate the the time you need (try to get it a little early) then in your IRQ routine, do a sprite 0 hit and wait for the exact time.

This could work but it'd be a little tough to get going... especially since DMC IRQ emulation is shakey at best in most emus (very very few run Mig-29... Nintendulator is the only one I can remember working -- and I had a difficult time getting it working in mine)

Another downside to this is you'd need to reserve a lot of space for DMC samples. It would also mean you can't use the DMC for anything else.... so maybe this isn't the best idea XD

But yeah... for timing of this nature... you're probably better off getting a mapper with IRQ capabilites (MMC3 is pretty common).


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 15, 2005 2:58 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7235
Location: Chexbres, VD, Switzerland
You don't have to get a so complicated stuff.
Just use a sprite 0 hit, if it has it's bottom bit set, and if it's well down, you won't see it. If the water position goes below a point of the screen, you can simply disable it and don't wait for a sprite 0 hit, so you have enough timimg for game logic. I remember a megaman stage that have cool tricks with water, but I forget exactly where.

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 15, 2005 8:00 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10067
Location: Rio de Janeiro - Brazil
Well, continuing with the water example:

Sprite 0 may not be such a good idea, since I can't make sure it will hit a visible pixel in the bg. I could if the water always staid at the same level, because I could then draw a line in the bg.

But the goal here is a water in the style of sonic the hedgehog games: it waves slightly up and down, and ocasionally may flood an entire level.

I guess the only way to assure a sprite 0 hit is to practically give up color 0 in the background, and construct the whole level using only colors 1-3. That would make things quite more restricted and ugly.

I could always intentionally place a solid block at the place I want the hit to happen, very close to the side of the screen, and hope it gets cut off by the TV. Otherwise that block following you would also look quite ugly. But then again, it would be as bad as the palette artifacts to the right side of the screen in horizontal scrolling games using h-mirroring.

Well, I'll think of something.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 15, 2005 11:32 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7235
Location: Chexbres, VD, Switzerland
Usually, the transparent color is $0f (black). And usually, sprites have a second non-transparent black color. If thoose two conditions are respected, you just have to fill a tile in the sprite pattern table with the non-transparent black color and put it as sprite 0 with the low priority flag set. Nothing will be visible, and the hit will always happen except if you use 100% transparent tiles in your level BG graphics. The only bad effect of this is, if another sprite is at the same place than sprite 0, it'll be hidden behind regardeless of it's priority flag (some emus emulates this wrong).

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 16, 2005 10:00 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10067
Location: Rio de Janeiro - Brazil
Bregalad wrote:
Usually, the transparent color is $0f (black). And usually, sprites have a second non-transparent black color. If thoose two conditions are respected, you just have to fill a tile in the sprite pattern table with the non-transparent black color and put it as sprite 0 with the low priority flag set. Nothing will be visible, and the hit will always happen except if you use 100% transparent tiles in your level BG graphics.


Hey Bregalad,
I understand what you're saying, but I actually need some tiles in the BG to be 100% transparent. I think I'll do it like you said, but will also sacrifice 1 color of one of the palettes, making it the same as the transparent color, so I can use it instead. This way a hit will always happen, right?

Quote:
The only bad effect of this is, if another sprite is at the same place than sprite 0, it'll be hidden behind regardeless of it's priority flag (some emus emulates this wrong).


This is indeed bad in this case. But missing such a small portion of a sprite is a small price to pay for the effects you can do using this trick. It can be very usefull if you actually want a sprite to go fully behind an object in the background wich is surrounded by non-color 0 pixels (like walking behind pillars, or behind houses in an RPG).


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 17, 2005 4:55 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10067
Location: Rio de Janeiro - Brazil
Hey, I found a game that draws non-transparent trash in the BG in order to get a sprite 0 hit for the status bar at the bottom of the screen. It's "The Guardian Legend". Just look at the left, right above the status bar and you'll see a dancing blue rectangle in outer space! =D


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

All times are UTC - 7 hours


Who is online

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