This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Asynchronous game logic

Asynchronous game logic
by on (#126450)
Not sure if I can explain this well, and maybe it's already been explored by someone, but this is my idea:

Background:
Most (all?) games try to do everything for the game logic during video rendering and get screen updates ready etc and try to beat the render time. If the game doesn't finish processing whatever it needs to do and the next screen is to be drawn then normally we see slowdown. I was thinking that there may be a way to have more complex (I may not have a good example here.) logic running in a way that slowdown shouldn't be a noticeable issue.

Idea:
Suppose the game is setup with a separate NMI thread structure. http://wiki.nesdev.com/w/index.php/NMI_thread
Most of the game logic would still operate normally during render time, but if the normal game logic was complete, rather than wait for NMI, the game could switch context to another thread (which if implemented simply is not too hard to do on 6502) that is allowed to calculate something over multiple frames. If this thread is interrupted for NMI, save it's state and switch context back to the main logic after the NMI thread is processed.

My thought was that this could help with a more complex enemy AI response, or other things I haven't thought of yet.

Of course you would need flags to hold the state of various things and it would a be a bit tricky to setup as there may be race conditions. Is this a valid idea?
Re: Asynchronous game logic
by on (#126451)
Something like this? viewtopic.php?t=1292
Re: Asynchronous game logic
by on (#126453)
This may be an application of that.
Actually, thinking about it more, it may be simpler to have a NMI only thread structure - if the "normal" frame logic is fast enough to always complete on time and then return to the asynchronous thread, rather than managing three states.
Re: Asynchronous game logic
by on (#126456)
So you're saying you want to have 3 threads: main (game logic), NMI (PPU and APU updates), and a new one for various extra calculations, is that it?

I don't see this bringing any advantage relative to the regulat 2-thread setup. I mean, if you transfer tasks that would normally be in the main thread to this 3rd thread, and the third thread is interrupted by the NMI, the tasks still won't be completed within a frame's time, so you gain absolutely nothing.
Re: Asynchronous game logic
by on (#126469)
I'm doing this in my latest 6502 game project and it does seem to work reasonably well. The trick is finding suitable tasks which may either be completed buffered up ahead of time or non-critical ones which may be allowed to lag behind.

For the record this is a C64 game so I'm somewhat more hampered by the hardware. In particular I need to do some heavy lifting in the scrolling (basically a big memcpy) on crossing 8-pixel tiles. Still, this sort of uneven load is common to all systems to one degree or another and any help in spreading the pain to avoid running over budget on spiky frames is much appreciated. Plus even with an even load it may still be preferable to miss every N frames instead of running at a steady 25/30 Hz (the unintentional bullet-time is often appreciated but the sudden cross-over tends to get me killed in twitch games.)

In my particular case I upload/mirror player sprite during spare cycles, but on running out of time I stick with the previous frame. There is also some loading and decompression going on in the background though aside from music that really only goes on during room transitions.

One cycle-hog of a sub-system which ought to be eminently suitable for prebuffering is music playback though I haven't yet managed to modify a playroutines to do this while mixing in channel-stealing real-time sound effects.

Another alternative would be to buffer up multiple OAM frames (along with scrolling coordinates, palette changes, etc) and allow the whole game to run ahead. Unfortunately the details of the buffering can get surprisingly involved, especially if you ever need to feed any information back to the game logic.
Re: Asynchronous game logic
by on (#126470)
tokumaru wrote:
So you're saying you want to have 3 threads: main (game logic), NMI (PPU and APU updates), and a new one for various extra calculations, is that it?


Based on my 1st post, yes.

tokumaru wrote:
I don't see this bringing any advantage relative to the regulat 2-thread setup. I mean, if you transfer tasks that would normally be in the main thread to this 3rd thread, and the third thread is interrupted by the NMI, the tasks still won't be completed within a frame's time, so you gain absolutely nothing.


Maybe an example of how I am thinking: Imagine really smart 2 player vs CPU Tetris game. You code the game normally and maybe even have some basic AI to deal with the next piece, but have an asyc thread running to do a deeper analysis of what the best move is that is not hampered by having to care that a VRAM update is due. When it is ready to make a change to the gameplay, it can set a flag that the normal frame code can check.. or something like that.

Or if you have a number of enemy objects, you could use this idea to make one or more of them smarter: Even if it takes 5 seconds for a "smart" decision, and set a change in an objects state, the player won't notice if the basic code is doing a good enough job of managing the "normal" tasks.

Or variations thereof. Does that make more sense, or ?
Re: Asynchronous game logic
by on (#126471)
Yes, that makes more sense. I was looking at this all wrong, thinking it was supposed to reduce slowdown, but in fact this is a way to make use of the time that's usually wasted just waiting for VBlank. It's actually a very interesting way to perform non-essential tasks that could improve the overall experience, without sacrificing anything.
Re: Asynchronous game logic
by on (#126475)
Hopefully the idea could be used to reduce slowdown if there are tasks that can be moved to the asynchronous thread.

doynax wrote:
I'm doing this in my latest 6502 game project and it does seem to work reasonably well


I figured I couldn't be the first person to think of this idea.
Re: Asynchronous game logic
by on (#126484)
Not exactly what you have in mind, but a few PC-Engine games use a 3 thread process; vblank/hblank interrupt stuff, game code, and a background process that decompresses LZSS stuff for future vram updates. I assume the game knows how long the LZSS background decompress processing takes, and calls it ahead of time. Gate of Thunder does this, and even on the hardest setting with tons of action on screen - nothing slows down. Ever.


That said, I wonder of parts of the main game logic could start as soon as the last 'frame' finished, instead of just waiting for vblank flag (for vblank related stuffs). I assume that's more along the lines of what you mean?
Re: Asynchronous game logic
by on (#126487)
On NES, it'd essentially be the Super Mario Bros. structure (NMI calls VRAM update and then the next frame's game code) with an LZSS decompressor instead of the forever: jmp forever.
Re: Asynchronous game logic
by on (#126593)
Perfect place to do sprite rotation.