Bregalad wrote:
Well, what to say ? You may be just worrying too much.
Yup.
Quote:
Note that if the Sonic game on the NES looks slightly different than their megadrive counterpart and if a few details are lacking, I guess noone will blame you, because after all, while we all love the NES, it's still technically an inferior system.
Heh, I'm sure I will not be able to fool anyone into thinking "hey, is this for the NES or MD again?", but I want it to feel similar enough, inspite of the obvious graphical inferities. It's not my intention to mimic everything from a MD game anyway, because I'm sure it will look better if I intentionally simplify a few things rather than forcing the NES to do what it obviously can't and fail miserably.
My goal is actually to surpass the SMS titles, getting closer to the MD titles than they ever did. And the NES does have a few advantages over the SMS: there are more tiles available (although they have less colors), which may result in less repetitive graphics, specially when combined with CHR-ROM bankswitching, for example. The SMS games look kinds dull, and whenever a larger amount of tiles needs to be loaded the game lags.
Quote:
If you want to use MMC3 why not change between 4 BG banks/2 SPR banks and 2 BG banks/4 SPR banks ?
Iguess you are right, this would be possible. But I don't think I would "scrifice" anything, meaning that I'd still have a 1KB of common sprites following every 1KB of player graphics, in case sprites use the 2KB switching. And if the background used 2KB switching, I'd make it responsible for animating the common objects stored there (rings, monitors, etc).
Quote:
Also as long as you don't use the scanline counter, you're free to use BG and sprites from any pattern tables with no problem, so if you're going to use any raster effect, you can design your level according to this pattern table limitation, but don't care about it for other levels where there is no raster effects.
There is simply no way for me to act according to it's scanline counter limitations. Except for the border at the top, but as soon as the IRQ fires, I'll do everything that's not allowed. So yeah, I won't be using raster effects during the rest of the frame, not even for the water levels, I have another idea for them already.
Quote:
I guess the better way to hide glitches is to place them where the user will be less likely looking...
The only serious problem with me using that approach is that most NES games only update rows/columns that are a single tile tall/wide when scrolling, while I update full metatiles (2 tiles tall/wide) at a time, because of the fast scrolling. That means more visible glitches than the average game. Unless I'm able to hide exactly 16 pixels in the direction of the mirroring, which is harder to do horizontally (like Alfred Chicken) than vertically.
Quote:
It's rather amazing, I guess somehow the game engine is KNOWING it will lag before actually lagging, and so it perform less calculations for one frame, check for sprite zero hit in time, and repeat next frame, so while the game is technically lagging, the CPU still doesn't run at 100%. I guess other Konami games use similar techniques.
Hum... it may be possible to predict when the calculations are going to take too long. The things that have more impact over the time spent are the need to render a new background row/column and the number of loaded objects. But even then, the complexity of each loaded object can make the actual amount meaningless. But if you think about it, even if a game can predict this, it still must sacrifice a great deal of otherwise usable time just to make sure it doesn't get too close to the hit (risking missing it), even when the sacrificed time might had been enough to finish the calculations, which causes more frame drops.
Quote:
However, Double Dragon handles this badly, and when there is too much CPU process to be completed in a frame, the status bar shakes.
This is just terrible, specially if it happens all the time.
Quote:
For MMC1 writes, the MMC3 won't help much because there is the same problem, an NMI can occur between a write to $8000 and a write to $8001, screwing things up.
I see your point, but I don't think this is as bad. I can think of a simple solution for the MMC3 case, while it's not so easy for the MMC1. Like, setting a flag before mapper writes that might be interrupted, using different registers for each write (say, X for $8000 and A for $8001). Before returning from the interrupting code, it checks this flag and clears it if it's set, then performs the two writes (X to $8000 and A to $8001). This should work well no matter where the code was interrupted. There should be no problem if after returning, both writes occur again, only the second write occurs again, or no write at all. The correct bank will be loaded. Not as simple with the MMC1, because of the larger number of writes to perform a switch and because it's harder to reset it's bit counter in order for the writes to reamain aligned.
Quote:
To fix the problem of the MMC1, you would of course disable NMIs when you're writing to registers, and enable NMI back after this, but this may delay the NMI a little and screw your timing up. Another trick is to simply avoid writing to any MMC1 registers in the NMI routine when a flag is set (and set this flag when the main programm writes to the registers). A third, more sophisticated method, is to disable NMI when the main programm does its MMC1 writes, and after the fifth write read $2002.7 instead before re-enabling NMIs. If the bit was set, then you just missed an NMI but you can call a routine that does exacly the same, and that with a fixed timing that won't screw up (typically the time wasted on the end of the MMC1 write can be saved back by not saving the registers). You may also use the BRK instruction to have an "IRQ" routine that would be a NMI clone that just start differently, and jump to the normal NMI routine, assuming you don't use any other type of IRQs.
Your solutions are interesting, but I'd rather interrupt a MMC3 write than having to worry about the MMC1 ever again! =)
Quote:
For the MMC3, it's simple enough, after write to $8000 simply write a copy of it to a memory location, before writing to $2001. At the end of NMI just read that memory location and write it to $8000, that should do the trick. The above methods will work as well, but it's probably better to "waste" a single byte of RAM.
Oh, I didn't read this before! Yeah, this solution is almost what I said above, but yours is simpler. You are right, there is no need for a flag, and there is no need to write to $8001 as well at the end of the NMI/IRQ. See? It's much better! =)
EDIT: Hey, if do want to have the correct bank loaded after returning from the NMI/IRQ, you do have to write to $8001 as well. Say that I was switching in a bank with metatile definitions when the NMI fired. Inside the NMI, I'll see that the frame isn't ready, and will want to call the sound engine, which switches in a bank with music data in place of the metatile definitions. Before I return, I must write to $8000 and $8001 the value that I was trying to write earlier, if I want the metatile definitions to be there, not the music data.
Quote:
EDIT : If you're really worried about graphical glitches.... I have a method that will completely remove them, both horizontal and vertical, and with any mirroring mode... However this introduce a limitation to the graphics themselves. Are you ready ?
That's nasty... But having a 4-color background would be pretty dull. Not even considering this for a Sonic game!