Controlling Play Speed

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

User avatar
clueless
Posts: 498
Joined: Sun Sep 07, 2008 7:27 am
Location: Seatlle, WA, USA

Post by clueless » Thu Dec 02, 2010 1:02 pm

My game detects, but does not count, frames missed. If I frame is missed (and the game is compiled in debug mode), the background palette color will change (as a debugging aid). For my game, I consider missing ANY frames a bug (I've blown my CPU budget). However, my NMI handlers and main loop do co-operate so that if I skip a frame the game will not crash - it will continue normally.

User avatar
tokumaru
Posts: 11996
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Thu Dec 02, 2010 1:14 pm

clueless wrote:For my game, I consider missing ANY frames a bug (I've blown my CPU budget).
That can't be said of all games though. There are some types of games where the CPU load varies too much, mostly those with dynamic object loading/unloading, where certain object combinations in certain parts of the levels can be too CPU-intensive. Simpler games with a constant number of active objects certainly shouldn't suffer from slowdowns though.

Anyway, I don't think that dumbing the entire game down to make it easier on the CPU is a good solution, I'd rather live with a couple of "slow spots" in my games than greatly simplifying them and use less than 30% of the CPU power most of the time. I mean, even games considered to be among the NES' greats (SMB3, Kirby's Adventure, the Mega Man series) suffer from slowdowns once in a while. Even games on newer platforms (SNES and Genesis/MD) suffer from occasional slowdowns. That's not something to be ashamed of, as long as it doesn't happen ALL the time (and it does in some NES games).

User avatar
clueless
Posts: 498
Joined: Sun Sep 07, 2008 7:27 am
Location: Seatlle, WA, USA

Post by clueless » Thu Dec 02, 2010 1:35 pm

tokumaru wrote:
clueless wrote:For my game, I consider missing ANY frames a bug (I've blown my CPU budget).
That can't be said of all games though. There are some types of games where the CPU load varies too much, mostly those with dynamic object loading/unloading, where certain object combinations in certain parts of the levels can be too CPU-intensive. Simpler games with a constant number of active objects certainly shouldn't suffer from slowdowns though.

Anyway, I don't think that dumbing the entire game down to make it easier on the CPU is a good solution, I'd rather live with a couple of "slow spots" in my games than greatly simplifying them and use less than 30% of the CPU power most of the time. I mean, even games considered to be among the NES' greats (SMB3, Kirby's Adventure, the Mega Man series) suffer from slowdowns once in a while. Even games on newer platforms (SNES and Genesis/MD) suffer from occasional slowdowns. That's not something to be ashamed of, as long as it doesn't happen ALL the time (and it does in some NES games).
I absolutely agree. Frame skipping is ok in some games, and not ok in others. But for the game that I'm creating for the compo (hey, does it still exist??), the number of objects is small and the game should never lag / skip.

I can even envision a game divided into three threads:

1) NMI handler: PPU updates, APU updates
2) Main game logic (moving stuff, joypads, physics)
3) Background simulation / AI planning which may take MANY frames.

Items #1 and #2 should run every frame, but when spinning for the NMI, the CPU really should be running thread #3.

User avatar
MottZilla
Posts: 2835
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla » Thu Dec 02, 2010 1:41 pm

Right, anything you can't afford to miss you could put in your NMI. You NMI could handle your Sprite Hit Zero waiting loop. Ofcourse you wouldn't be able to do like TMNT1 which uses sprite 0 but doesn't just waste CPU time for that status bar at the bottom. Ofcourse that method has the drawback of too much going on causing status bar flicker glitches.

When I heard that some games run entirely in NMI I thought that was pretty awful. Whatever works I guess, but it still seems hacky or unprofessional.

There is a Bugs Bunny game on NES that looks awful as I recall as it runs at 30fps or something like that because it was programmed so badly.

User avatar
tokumaru
Posts: 11996
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Thu Dec 02, 2010 1:58 pm

clueless wrote:3) Background simulation / AI planning which may take MANY frames.
Yeah, complex AI can be a problematic thing to handle. But if you can find a way to break it down into smaller steps and execute as many as possible every frame, so that only the AI will slow down as necessary, that's great.
MottZilla wrote:Whatever works I guess, but it still seems hacky or unprofessional.
I agree. I think that these alternate methods should really only be used when you are 100% sure that your frame calculations will always end in time. I mean, if these glitches can be avoided so easily, why take a risk? I guess that programmers who have made this kind of mistake in the 80's can be excused to some extent, as they possibly didn't have full understanding of the machine they were working with.
There is a Bugs Bunny game on NES that looks awful as I recall as it runs at 30fps or something like that because it was programmed so badly.
I can't think of any licensed games right now, but a lot of those Hong Kong pirates suffer from terribly inconstant frame rates all the way through. As if the crappy physics wasn't enough to make the experience of playing them terrible.

tepples
Posts: 22281
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Thu Dec 02, 2010 3:42 pm

tokumaru wrote:
MottZilla wrote:There is a Bugs Bunny game on NES that looks awful as I recall as it runs at 30fps or something like that because it was programmed so badly.
I can't think of any licensed games right now,
Choppy licensed Bugs Bunny game: The Bugs Bunny Birthday Blowout aka Happy Birthday Bugs by Kemco.

Also choppy licensed games: Hello Kitty World and any game ghost-developed by Micronics.

Even choppier unlicensed game with a character resembling Bugs Bunny: Wait and See aka Ну, погоди.

User avatar
Kasumi
Posts: 1292
Joined: Wed Apr 02, 2008 2:09 pm

Post by Kasumi » Thu Dec 02, 2010 6:42 pm

tokumaru wrote: Not it wouldn't... That flag only stays up during VBlank, and since VBlank doesn't last very long, if your logic took longer than a frame to complete, the chances that it also goes over the time of VBlank are pretty high...
Ah. That is a shame. I thought it stayed set until it was read. :oops: Sorry.
At the end of my main loop, I set a variable indicating that all the logic has completed, and the NMI uses that to decide if it should update the PPU or not (it doesn't if the frame logic isn't complete), but I could also use it to detect when I missed a frame...
That's a good idea. I already use a variable to let the NMI know the buffers that tell the NMI what to write to $2006/7 are finished updating, but I hadn't thought of using that to detect a dropped frame.
MottZilla wrote:What is the point in counting the frame updates missed? I don't think that there will be much you can do about it.
I've toyed with the idea, since my slope detection does many checks that aren't necessary, but make things much smoother. If they cause the game to lag, I could certainly drop some of them for a few frames to save hundreds or thousands of cycles, depending on how many enemies are on screen. I could also update enemies less, or only update the most crucial parts of the AI in times of strain. I really don't want my game to lag as much as Kirby's Adventure, or even Megaman games. I've also thought of using it purely for debug purposes like clueless, so I can do my best to avoid situations that cause heavy strain when designing levels rather than resolving the problem at runtime.

Kirby lags too much in my opinion. Megaman games are mostly fine, but I want to at least beat or tie them.

User avatar
MottZilla
Posts: 2835
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla » Thu Dec 02, 2010 8:47 pm

Well it seems you have a clear path of calculations you could cut out. But then you have to manage when to cut them when not to and you'd want to avoid a see-saw effect where it runs normal for a few frames, then lags for a frame or two. That would be worse than a constant slowdown. So you might want to drop unnecessary calculations based on something better than missed frames and either combine it with missed frames and number of active objects relative to a known amount that causes slowdown. So if the player and a few objects are on screen you can use the extra cpu time but when you get alot of objects and are running out of time you can free some up.

It's an interesting problem. Slowdown should definitely be avoided but it's acceptable in certain places and even in others it might be disliked but still not ruin the entire game.

User avatar
Memblers
Site Admin
Posts: 3898
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers » Thu Dec 02, 2010 9:07 pm

cartlemmy wrote:Ah yes, actually I guess I use a counter. I like using the counter, because you can use it for things like "Do this every n frames":
I used to do timing that way, but in most cases it turned out to be really limiting compared to using a fixed-point counter. With fixed point for example, if you wanted to do something every 2 frames, you would add $80 to the counter every frame, and trigger on carry. Instead of $80 though you can add any value (zero would stop it) for 256 different speeds.

Tom
Posts: 68
Joined: Wed Apr 06, 2005 5:36 am
Location: Massachusetts

Post by Tom » Thu Dec 02, 2010 10:20 pm

MottZilla wrote:I forget which games do it, but some have bad music distorting/slowdown when the game slows down because they do not update the music engine every 1/60th second if the game is slowing down due to heavy cpu load. You should avoid this.
I've been thinking about this lately. There's two potential problems with updating the sound engine in NMI. The first is it's possible you have a sound effect or something that's synchronized with some graphical animation. So if there's lag, they'll get desynchronized. I think this is probably not a huge problem, practically speaking.

The bigger problem is if you're updating the sound engine in the main loop (like starting a sound effect), and an NMI triggers in the middle of it, things could go pretty wrong. With the PPU the solution is to buffer any changes, and set a flag when it's ready for the NMI to use. But sound engines tend to be more complicated, making such buffering harder (I haven't figured out a good way to do it with my engine yet).

One the other hand, if you only update the sound engine in the main loop, you can just buffer the values to write to the sound registers pretty easily for NMI use. Of course if there's lag, the sound with also slowdown. Worse, if you're using hardware effects (length counters, sweeps etc), those won't lag, which could sound pretty bad.

User avatar
tokumaru
Posts: 11996
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Fri Dec 03, 2010 8:16 am

Tom, you might be able to deal with these problems by using a flag system similar to the one used for PPU stuff:

All sound-related functions could have a protection flag. For example, when you call a function requesting that a new song starts playing, this function will first set this protection flag indicating that critical sound operations are happening. In the NMI, when the time to update the sound comes, check this flag. If a crucial operation was interrupted, meaning that pointers and other variables could be inconsistent, you just clear the flag and return. The CPU will then resume the critical code, and before finishing, it checks the flag. If it is clear, it calls the routine that updates the sound, if not, it just clears it and returns.

The good thing about audio is that, unlike the video, you can update it at any time, so the delays will actually be very subtle, instead of whole frames, and will probably go unnoticed.

As for the sound effects, remember that the NMI routine has ways to know if a frame was missed or not, so as long as your sound engine knows the difference between music and sound effects it can delay the sound effects in case of lag frames. Most of the time I think you'd not want to do that, but if it's really important that some effects are in sync, you could add a flag to each sound effect indicating whether they should lag along with the video.

User avatar
cartlemmy
Posts: 193
Joined: Fri Sep 24, 2010 4:41 pm
Location: California, USA
Contact:

Post by cartlemmy » Fri Dec 03, 2010 9:31 am

Memblers wrote:I used to do timing that way, but in most cases it turned out to be really limiting compared to using a fixed-point counter. With fixed point for example, if you wanted to do something every 2 frames, you would add $80 to the counter every frame, and trigger on carry. Instead of $80 though you can add any value (zero would stop it) for 256 different speeds.
True, and I do use such a counter as well... But it's cool to not have to use an extra byte of memory (and some cpu time) if your counter happens to need to fire every 2^(0...7) times.

User avatar
Memblers
Site Admin
Posts: 3898
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers » Fri Dec 03, 2010 4:33 pm

I have been curious, I haven't tried it yet but how well it would work to use fixed-point for everything timing-related, and then have the assembler calculate the timing for PAL/NTSC. Seems like it should work OK, maybe it could some variations/errors, but probably nothing all that bad.

User avatar
tokumaru
Posts: 11996
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Fri Dec 03, 2010 5:07 pm

Memblers wrote:I have been curious, I haven't tried it yet but how well it would work to use fixed-point for everything timing-related, and then have the assembler calculate the timing for PAL/NTSC. Seems like it should work OK, maybe it could some variations/errors, but probably nothing all that bad.
I have considered doing that... In theory it should work, but I can't stop thinking that the limited precision of fixed-point numbers could make some things behave visibly different between versions.

You also have to be careful about things that could break due to limitations of your engine... Scrolling, for example. If your scrolling engine can update a column of metatiles that's 16-pixels wide every frame, the maximum speed of the camera is 16 pixels per frame. If you are working with NTSC and want to convert that to PAL, the camera would have to move faster than 16 pixels per frame in order to have the same apparent maximum speed, and that would screw up your background rendering. So you have to make sure that 16 pixels per frame is the maximum speed on PAL, but 13 1/3 in NTSC.

tepples
Posts: 22281
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Fri Dec 03, 2010 5:27 pm

tokumaru wrote:If you are working with NTSC and want to convert that to PAL, the camera would have to move faster than 16 pixels per frame in order to have the same apparent maximum speed, and that would screw up your background rendering. So you have to make sure that 16 pixels per frame is the maximum speed on PAL, but 13 1/3 in NTSC.
But PAL's vblank is over three times as long. So if you have the RAM to spare for a bigger transfer buffer, and you have some CPU time to spare, you could design the engine so that the PAL version's camera can move faster.

Post Reply