Lately I’ve been wondering if it’s possible to achieve smooth scrolling in Dragon Warrior on the NES.
This post describes the problem and a possible solution. I haven’t tried this solution, but based on my understanding of the NES’s PPU (picture processing unit), I think it could work. At least, maybe it’ll inspire someone to try it or to propose different techniques.
In Dragon Warrior, scrolling is smooth in totally-exposed areas, which means all areas outside of caves. On the NES, this is achieved by using a method typical of the NES: by updating the PPU’s scroll registers and updating the tiles just outside the visible screen area while scrolling. I’m not going to explain PPU mirroring and scrolling; there are explanations of the topic like Retro Game Mechanics Explained’s great video on the topic.
Dragon Warrior uses vertical mirroring, which means that the video memory can support two whole screens wide and tiles can be updated off-screen while moving horizontally; but the tiles being updated on the top and bottom of the screen are visible during a vertical scroll. This is hidden by most TVs (and emulators!) because it’s outside the physically visible screen area, due to overscan.
In caves, Dragon Warrior doesn’t scroll smoothly at all. This is caused by two conflicting factors:
As a result, stepping by one “Dragon Warrior” tile in a cave only has two frames of animation: One stepping halfway (one 8x8 character) and then one to step the next half.
Aside: While viewing the name table in FCEUX I observed that the X scroll position alternates between 32 ⯈ 0 ⯈ 32 during a cave step:
This feels sluggish and disorienting, especially when you’re only using a torch or have no light at all. In fact, the brick floor is only an 8x8 repeating pattern, and since a half-tile step moves by 8 pixels at a time, you can’t tell if you’re moving at all. Pressing in a direction isn’t a reliable way to move because move inputs only seem to register on certain frames, so depending on when you press a direction and for how long, you might turn & move, or just turn.
Most players would be using a torch or the RADIANT spell, so they can orient themselves using the walls visible around them. But speedrunners, especially those playing Dragon Warrior randomizer, are more likely to lack or avoid using torches or RADIANT, and they’re familiar enough with the cave layouts that they don’t need to see where they are in them. However, they still need to know whether or not their inputs registered as movements.
In a situation like this, players typically bonk against walls to orient themselves, which plays a sound effect. But sometimes you need to make a turn before reaching a wall, so the problem isn’t solved for all cases.
I think it’s possible to use the NES’s smooth scrolling in caves, while still keeping a limited visible area.
The process is essentially the same as full-screen smooth scrolling, but instead of updating characters that are just off the edges of the screen, we’ll update them right outside of the player’s lit area, and try to hide them so that the result looks clean.
This is a little different for horizontal and vertical scrolling because of the PPU’s limitations.
This process uses black sprites on the left and right of the lit area to cover our tiles while they’re updated. This is a pretty common technique for full-screen horizontal scrolling, where the left edge of the screen is masked using a PPU feature that does precisely that; and the right edge is covered by sprites.
When the player moves left or right:
Since the hero is typically the only sprite visible while in caves, sprite limitations are unlikely to be a problem. The only other example I can think of is that the princess is probably also a sprite in the swamp cave. The Dragonlord at the bottom of Charlock is also a sprite, but that area isn’t dark; it’s a full-screen fully-visible area.
This is the same process as horizontal scrolling, but we can’t use sprites to obscure the characters being updated, because there’s a limit of 8 sprites per scanline. However, it’s possible to update the X scroll position between scanlines, which games often use to achieve a status bar that stays in position instead of scrolling with the rest of the screen. We’re going to use that to display an empty part of the nametable for the areas where we’re updating the characters during a scroll.
First, we need to ensure that the nametable is empty (all black characters) at Xscroll + 32, so that when we swap over to it, we won’t show anything. This only needs to be done when entering the cave, because we will never have any reason to draw anything in that space while doing other cave stuff.
Then, during a vertical move, we need to do this on every frame:
As with horizontal scrolling, we’ll need to update the incoming and outgoing tiles during the scroll, but this is also as usual during a vertical scroll; we’re just doing it near the lit area rather than at the screen edges.
Split scrolling can cause some artifacting/jitter as the scroll position might not get updated before the next scanline starts to be drawn, but since we have just empty black space at the start of each scanline, I don’t think the artifacting will even be visible.
Although I think this process will work, I haven’t actually tested it. My primary concern is that we don’t have enough time to update the incoming characters before we need to show them. I think it would be unacceptable to delay a tile movement to update those characters before the animation, because this would make continuous movement (eg. holding right for 2+ tile movements) jittery as it would need to pause on each tile.
I’m also not sure if we would leak palette changes into the lit area during scroll.
It’s possible that this solution would interfere with the UI and battle view, but I don’t think it will because none of those can happen during a scroll, and when the hero’s position is aligned with the tile we don’t need to do any work to scroll at all.
In existing full-screen scroll implementations, games ensure that the characters immediately off-screen are ready for the next scroll. If we did that, we’d need to maintain the X scroll split and the “hiding” sprites at all times. I think this would solve the problem with having enough time to update characters before the scroll, because we can update them during the scroll instead – just like games already do for full-screen scrolling.
This would definitely cause interference with the UI. To mitigate that, it might be acceptable to clear all of our scroll machinery (our hiding sprites and pre-drawn characters) when we need to show UI, and restore it when the UI disappears. This would probably add some delay to UI appearance and removal, but I think that would be acceptable as the UI isn’t particularly quick to begin with.
Today I updated Jekyll, which I use for this site, and fixed some problems with URLs that had affected this site ever since I created it at the start of 2016.
I switched from the BlackDoc theme to Midnight with some customizations (mostly, simplified). I’m not especially experienced with HTML or CSS/SCSS so I limited myself to simple changes only.
I think the URL problems were caused by some bad assumptions in some layout files; possibly assumptions I had made, I’m not sure. The result was that the RSS and Atom feeds had URLs with too many slashes, such as https://mrb0.com///
. This was caused by two things in my _config.yml
:
url
was https://mrb0.com/
with a trailing slash that I’ve removed.baseurl
was /
, but should be ""
.However, when I fixed both of those things, only pages in the root of the URL were properly-styled, because the layout files used baseurl
to reference the CSS resources (and probably others); eg. <link href="style.css">
, which now resolves to style.css
instead of /style.css
.
Ultimately, I decided to switch to the Midnight theme after seeing Shamus Peveril use it on his new site.
There are still a few style tweaks I’d like to make, but I’m happy with the site so far. Syntax highlighting works in code blocks; I’m not sure it did before. I’m not sure I ever tested it!
subscribe via RSS