porting Adios To The Nintendo Switch Entertainment System

Couple years ago, I handled the port of Adios, the game about the pig farmer who doesn’t want to dispose of corpses for the mob anymore, to the Switch. It took a week. The Switch is weak as piss, so this is always a little bit of a pain, but the port ended up looking visually pretty good and runs at a solid 30fps, usually at the full 720p in handheld mode. Sometimes it has to dynamic-res to a lower res, but it’s usually not noticeable thanks to Unreal’s temporal upsampling.

I really wanted to hit 60fps on the Switch, but ultimately the the necessary visual sacrifices wouldn’t have been worth it on a game where you aren’t twitch-reacting to anything and where the nice art is a lot of the vibe, and the vibes are a lot of the whole thing. Responsiveness did benefit a lot from Unreal’s Low Latency Frame Syncing, and much as some folks hate it, enabling motion blur helped a ton with keeping camera rotation from feeling juddery at that awful 30fps.

The worst thing to deal with was memory. It’s a small game, but everything’s in one pretty big level, and it’s statically lit, and there are multiple times of day, so lightmaps are a substantial memory cost. On the other hand, it wouldn’t have been worth lighting it dynamically, because the static lighting also carries a lot of vibe, and saves a lot of render time. The lightmaps did need to be downrezzed a lot though, which fortunately you can do in Unreal without having to rebake the lighting.

Every texture in the game was also drastically reduced in resolution, which again, is easy to do per-platform on Unreal, but I did have to spend a lot of time assigning texturegroups so that it wasn’t done indiscriminately – landscape textures and characters stayed reasonably high res at 512, small inconsequential objects got as low as 64, more important objects were more like 256, and any normal maps were crunched even harder (since they mainly informed the static lighting at build time).

A lot of memory and GPU perf was also clawed back by mass-LODing every single mesh in the game, which sounds worse than it is; I have a tutorial about it. I also removed convex collision from every mesh, since that too costs memory, and collided per-poly with the simplest LODs instead.

I also ended up using Unreal’s extremely dated Precomputed Visibility System to squeeze the most perf out on the Switch. This is an old system made specifically for Infinity Blade a long time ago, which will have had a similar set of issues.

I did some other work on Adios before it came out for PC/Xbox, mostly dejanking. At the time it had no real lipsync – just some facial expressions and looping “I am talking” anims. I had no time to do a real lipsync (or you know I would), but I got the jaw flexing with the wav amplitude, which makes a massive difference, and it’s still a little more sophisticated than Half-Life 1’s lipsync because that “I am talking” anim is still playing and giving us some flex in the lips, even if it’s functionally random.

Another eleventh-hour dejank was that when the character you spend the whole game with interacts with anything, he teleports into position, then plays an animation. This looked pretty rough, but there wasn’t time to make any real changes to how it worked, so I just smoothed it out by interpolating his mesh’s transform on tick, from what it was last tick to the desired position. He still teleports, but now his body takes a second to catch up.

If there’d been time/money for it, the game would have benefited from a lot of character tech-anim stuff that would have been fun to do: better eyes, facial anim, lipsync, proper blending and layering – but I think the character’s “performance” still comes over surprisingly well.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *