I'm trying to develop an oldschool NES-style video game, with sprite flickering and graphical slowdown. I've been thinking of what type of logic I should use to enable such effects.
I have to consider the following restrictions if I want to go old-school NES style:
- No more than 64 sprites on the screen at a time
- No more than 8 sprites per scanline, or for each line on the Y axis
- If there is too much action going on the screen, the system freezes the image for a frame to let the processor catch up with the action
From what I've read up, if there were more than 64 sprites on the screen, the developer would only draw high-priority sprites while ignoring low-priority ones. They could also alternate, drawing each even numbered sprite on opposite frames from odd numbered ones.
The scanline issue is interesting. From my testing, it is impossible to get good speed on the XBOX 360 XNA framework by drawing sprites pixel-by-pixel, like the NES did. This is why in old-school games, if there were too many sprites on a single line, some would appear if they were cut in half. For all purposes for this project, I'm making scanlines be 8 pixels tall, and grouping the sprites together per scanline by their Y positioning.
To clarify, I'd be drawing sprites to the screen in batches of 8x8 pixels, not 1x1.
So, dumbed down I need to come up with a solution that....
- 64 sprites on screen at once
- 8 sprites per 'scanline'
- Can draw sprites based on priority
- Can alternate between sprites per frame
- Emulate slowdown
Here is my current theory
First and foremost, a fundamental idea I came up with is addressing sprite priority. Assuming values between 0-255 (0 being low), I can assign sprites priority levels, for instance:
- 0 to 63 being low
- 63 to 127 being medium
- 128 to 191 being high
- 192 to 255 being maximum
Within my data files, I can assign each sprite to be a certain priority. When the parent object is created, the sprite would randomly get assigned a number between its designated range. I would then draw sprites in order from high to low, with the end goal of drawing every sprite.
Now, when a sprite gets drawn in a frame, I would then randomly generate it a new priority value within its initial priority level. However, if a sprite doesn't get drawn in a frame, I could add 32 to its current priority. For example, if the system can only draw sprites down to a priority level of 135, a sprite with an initial priority of 45 could then be drawn after 3 frames of not being drawn (45+32+32+32=141)
This would, in theory, allow sprites to alternate frames, allow priority levels, and limit sprites to 64 per screen.
Now, the interesting question is how do I limit sprites to only 8 per scanline?
I'm thinking that if I'm sorting the sprites high-priority to low-priority, iterate through the loop until I've hit 64 sprites drawn. However, I shouldn't just take the first 64 sprites in the list.
Before drawing each sprite, I could check to see how many sprites were drawn in it's respective scanline via counter variables . For example:
- Y-values between 0 to 7 belong to Scanline 0, scanlineCount[0] = 0
- Y-values between 8 to 15 belong to Scanline 1, scanlineCount[1] = 0
- etc.
I could reset the values per scanline for every frame drawn. While going down the sprite list, add 1 to the scanline's respective counter if a sprite gets drawn in that scanline. If it equals 8, don't draw that sprite and go to the sprite with the next lowest priority.
SLOWDOWN
The last thing I need to do is emulate slowdown. My initial idea was that if I'm drawing 64 sprites per frame and there's still more sprites that need to be drawn, I could pause the rendering by 16ms or so. However, in the NES games I've played, sometimes there's slowdown if there's not any sprite flickering going on whereas the game moves beautifully even if there is some sprite flickering.
Perhaps give a value to each object that uses sprites on the screen (like the priority values above), and if the combined values of all objects w/ sprites surpass a threshold, introduce slowdown?
IN CONCLUSION...
Does everything I wrote actually sound legitimate and could work, or is it a pipe dream? What improvements can you all possibly think with this game programming theory of mine?