A bit of scanline flickering is a fairly common problem on the NES. Even Super Mario Bros. 3 had it, and that game was made by Nintendo themselves.
Game graphics in the 8- and 16-bit ages often came down to tricky hardware manipulation. The art of doing raster effects, changing the registers in the video hardware so as to divide the screen into different sections, ultimately comes down to timing. On the Atari VCS/2600, nearly all the graphics had to be done that way, but it was still a useful technique for over a decade after that.
A lot depends on the specifics of the video chip, a custom-built piece of silicon developed for the express purpose of taking graphics defined in memory and folding it, like electronic origami, into a shape that the TV would perceive as a broadcast signal. At that time, while it might still have been possible with clever coding, CPUs weren’t nearly fast enough to do that job themselves and still produce acceptable graphic quality and run game logic. (If you want to see what it would be like, I refer readers interested in doing it the very hard way to the amazing Freespin demo, which runs on a 1541 disk drive, and no video hardware at all.)
Older NES games used a supported bit of hackery called the “Sprite 0 Hit,” a signal the PPU would send at the moment the first of the system’s 64 sprites began to be drawn. By watching for it, games could do rudimentary raster effects on a system not designed for them. The issue there was processor time: the Sprite 0 Hit feature wasn’t hooked up to an interrupt line, so the program had to continually watch for it, checking a memory location repetitively over and over until it changed. Some games spent large portions of their runtime in a tight loop checking for the Sprite 0 Hit. Since, from the program’s perspective, the signal might come at any time, the loop needed to be tight, meaning the game couldn’t spend that time doing other work or else it might be delayed in responding to the extremely time-sensitive signal.
The MMC3 mapper had a special function though that could time out when a programmable scanline was reached, and send the processor an interrupt request at that time, greatly freeing up the processor for doing other things with that time. But not all programmers understood the best way to use it, which is why Mega Man 3 has some scanline glitching in a couple of very visible places, in the pause window and on the level select screen.
Displaced Gamers’ Behind the Code series, which we’ve linked to multiple times in the past, has done an exposĂ© looking into how Mega Man III’s glitches happen (28 minutes), and even wrote some code that erases all trace of them. As usual for Behind the Code, the explanation is fairly technical, especially of the fix, but the first half of it is fairly comprehensible. No one says you have to watch the whole thing. Or, indeed, any of it, but I always enjoy them!