Intro 

I suffer from an affliction many programmers and game developers can sympathize with: We tend to have so, so many ideas and nowhere near enough time to execute them. I'm toying with the idea of making a blog talking about random ass concepts of the above variety, while merging design, programming, and rendering topics. If anyone wants to implement this scatterbrained mess, may god have mercy on their souls. At the very least, I hope it's a fun read.

This idea came from a remark from a designer friend of mine while we were discussing the soulslike games, something to the effect of "Y'know what? Souls games have the gameplay of a Playstation 2 game with better graphics". He was more right than he thought, having said that a year or two before the release of the Bloodborne PS1 Demake, which I will always take the opportunity to share.

But, both the above planted a brain worm that I couldn't shake; what might happen if you pushed it even further? Is a soulslike game even possible on earlier hardware? Say, the SNES?

What is a Soulslike?

Obviously seminal genres mean different things to different people, so I'm going to oversimplify here as a way to define the goals for this thought experiment. I think genres are composed of tropes, so I’ll list a few important ones here that I think any soulslike game would require.

  1. Combat that rewards skill, rhythm, and spatial understanding

  2. Complex world maps that allow progress to unlock shortcuts or alternate routes

  3. Misanthropic lore that puts the players struggle into a larger context

  4. Core game loop of attempting to progress to a checkpoint, either failing, returning, or unlocking the next stepping stone.

What can the SNES do? 

Not much, honestly. That’s kind of the fun of the thought experiment. It’s specifically designed for 2D sprite-based games. For example, the background rendering hardware takes a map of tiles and the locations they map to, and draws them on screen using a palette.

There are some additional tricks that aren’t apparent in the system. You can set the hardware to several modes, Mode 7 being the most infamous and directly related to what we’re talking about today. Simply put, it allows the linear transformations of the background [1]. By changing settings for every scanline, it also allows affine transformations, like those in camera projection transformations [2]. This allows for a crude simulation of a 3d plane, similar to Mario Kart or Pilot Wings.

Mode 7 in F-Zero

In addition to background layers, the SNES hardware is also designed to support drawing sprites to the screen. These are also drawn from a table using a palette, and given several attributes, like position and priority [3]. 

Pixel data and palette data combine to form the final sprite

The SNES can show up to 128 sprites on screen. Those sprites can have up to 15 colors + transparent, and they can be up to 64x64 pixels. There can only be 32 sprites shown on a horizontal scanline at a time.

What Does our Souls Game Look Like?

Since I think it’s important to retain the three dimensionality of both the combat and the world exploration, I feel the game should at least attempt to break out of the 2d hardware a little. Another important part of the games is the situational awareness that the third-person camera affords.

I find that concept of a screenshot really help communicate the intent of what the game might look like.

As far as tone and mood, obviously it should be dark and brooding. For fun and just to pick something, I’ve settled on a biblical, angels-and-demons theme, set in a world destroyed by their war. More on the lore later. The souls games do a really good job at dividing the game into iconic, recognizable sections. Castle corridors, dripping caves, haunted moors, and barren wastelands are all on the table. Here’s some concept doodles illustrating some of the locations.

How the Hell do we Render These?

So, the SNES doesn't have native 3D support, but we’re circling around the concept of a 3D game - we’re in trouble, right? Well, only sort of.

Before 3D acceleration hardware (e.g graphics cards) became common, games such as Wolfenstein 3D and Ultima Underworld made do with limited processors, rendering the game directly using software. We’re going to adapt the concepts they used for those games - and we know these things are totally possible, because we’re able to see them in action with SNES Doom [4]. However, this uses the Super FX chip, and I’d like to avoid (hypothetically) using that if possible, so we’ll focus on techniques that aren’t reliant on rendering lots of polygons.

StarFox uses shaded polygons and on occasion texture mapped polygons, but requires the use of the Super FX chip on the cartridge.

We’ll start by talking about the techniques used in Wolfenstein 3D and Super 3D Noah’s Ark [5]. They use a grid-based raycasting renderer. The algorithm for drawing the screen is fairly simple, as follows [6].

Consider a map that is a grid of either floor or wall blocks. For each horizontal pixel in the game, shoot out a ray line into the world, and calculate how far it travels before hitting a wall. Save that distance number and also where along the wall it hits. 

Next, draw a vertical strip of pixels, the height of which is a multiple of the distance the ray for that column traveled. For example, a far away wall should draw a short vertical bar of pixels, and a nearby wall would draw taller. 

You can enhance this by using which wall was hit to look up which texture should be drawn, and by changing the color to draw based on the distance, giving a fog or fade to black looking effect.

Intersection calculations only need to be done on grid boundaries

This technique is possible on the SNES as demonstrated with Super 3D Noah’s Ark, but it also produces uninteresting, repetitive square maps. With just a little bit of adjustment, I think we can tweak it to still be performant, and to display more interesting maps.

First, let’s add a conceptual height to each box. This is a value that adds to the vertical strip of pixels in addition to the distance-height scaling mentioned previously. However, it’s important to only consider this for the upper half of the screen, and to clip the vertical strip when it touches the “ground plane”.

This would stretch the pixels vertically by 2, but I don’t think it’s a big deal for this sort of aesthetic.

This technique works fine as long as the player can’t get above or below the pseudo-polygons enough to look at them obliquely, but since our player and camera are going to be glued to a constant height, this is not a problem.

The other issue is that of the grid. As mentioned, this produces uniformly similar maps that are uninteresting, and since souls games are sustained by complex map design, we need to break that grid. 

Doom uses a technique called Binary Space Partitioning, where the walls to render are pre-calculated per each room (‘sector’), and the walls of the room the player is standing in are drawn first. Then, any doors or windows that link this room to another are filled in recursively, as long as the camera has a view of them [7]. The drawback of this technique is that it is both memory intensive (having to store the pre-calculate sectors and connections), and it is computationally intensive, requiring the use of the Super FX chip onboard the cartridge.

We’re going to use a lower-fidelity version of this approach. Consider a room that can be represented as a list of lines that forms a convex polygon. Each line can either be a wall or a portal to another room.

We’ll assume we know what room the player is in, and the direction they’re facing. To draw a room, we cast a whisker ray from the left-most pixel of the virtual camera, and iterate all of the room’s lines to find an intersection. Do this again for the right-most pixel. This gives us the bound indices, and the lines between those bounds are the only ones to raycast against in order to draw them to the screen. In fact, the line the previous ray hit and the immediate left and right lines are the only ones needed to test for each new collision.

As we iterate the vertical bars, I would also go from the edges of the screen inward - drawing the right and left most pixels first, and ending at the center of the screen. This will become apparent why in a moment.

Portals present a unique case. If we cast a ray that intersects a portal, we re-cast a whisker ray using that new room as the list of lines. If we draw from the screen edge, inward, we can pause this side of the image and wait until the other side “finds” the same portal as we do, and cast another whisker ray on the other side to re-establish the bounds to iterate. Note that this will work if and only if the portals are a single line flanked by two walls, enforcing the case where a portal strictly connects only two sectors. Also, limiting this portal depth to only one would be prudent. Drawing the fog-color for the portals in connecting rooms would probably look fine.

The green portal plane wouldn’t ever get drawn, it’s just to illustrate the process.

Disclaimer: Since I haven’t actually done the legwork of implementing this on hardware, I have no idea exactly how (non) performant this would be. My guess is that it’d probably be possible on hardware with some compromises, maybe having to sacrifice texture mapping, fog effects, or walls having different heights. Possibly all three. We would probably also consider halving the vertical and horizontal resolution of the 3D effects, which would speed up rendering significantly. For the sake of having fun graphics in the mockups, I’m just going to assume we get to keep those features, and can render at full resolution, and proceed onward.

From there we can start to have some fun. It’s nigh impossible to draw things like round cylinders and spheres, so I’d recommend the tried-and-true method of using camera-facing sprites to enhance low-poly graphics. Things like the caps of castle towers and roofs of huts, can be added with this method. Other world objects like the player, enemies, trees, and items will also be drawn to the screen this way. (Note: All of the mockups of the game in this blog were rendered in Unity, but strictly followed the rules of the SNES and the limitations described above)

Note that the tree and spire sprites are rendered in world-space, and are therefore much lower resolution. The player sprite would be rendered in screen-space using the hardware supported sprites, allowing it to be much higher resolution.

We can also pull some other interesting tricks. For the floor, we can render out a tilemap using the Mode 7 technique described above. For an exterior, we can scroll the background tiles to line up forming a horizon skybox. For interior scenes, like for castles and caves, we can mirror the floor technique to create a ‘ceiling’. We will have to keep the wall heights all the same for this perspective trickery to work, however.

The pixel art for the player sprite turned out really good and took a while, so you’re going to be seeing it a lot.

Combat Design

To figure out our design needs here, we’re going to start with how Soulslike games play, and work back from there. 

First, to pay off the player’s timing skills, they have long windup and cooldown animations when attacks happen - both for the player and the enemies. This presents a problem for our imaginary console; long animations means lots of frames, and as depicted in the mockups above, we also have a relatively large player sprite (78 px by 88 px). To mitigate these limitations, we’re again going to have to cut back and approach it strategically.

There’s probably a more optimal division, but this was by hand.

For the animations, to store them, we can use a lower bit depth for the images than the SNES natively uses. The console hardware natively uses a 4 bits per pixel, giving 15 colors + alpha. If we reduce the color down to use at most 8 colors per sprite, we can use 3 bits per pixel, and convert when writing to the sprite memory. This does potentially waste the other 8 colors of that sprites palette, but this can be recycled as a different sprites palette. In fact, this can also give us more palettes to work with. Heck, if we were to push it to 4 colors per sprite (2 bits per pixel), we could get 4x the sprites in ROM with 4x the palettes. However, this might result in bad looking graphics, so all the sprites in the example mockups use at most 7 colors + alpha.

There are also some more tricks that can give us more visuals for our memory. We could write tools that identify exact and very close sub-sprites (8 px by 8 px tiles), and simply reuse those when drawing new images to the screen. Again, having fewer colors means these are more likely to occur. This is similar to how the wide array of animations were implemented in Aladdin [9] and by hand in a smaller scale for the NES game Micro Mages [10]. I haven’t found anything confirming this, but I suspect it’s also how large sprite games like Street Fighter 2 manage to fit on the console.

Giving the match algorithm a threshold rather than requiring a perfect match would probably look good enough, too.

Combat design would also have to contribute to saving resources. We would limit the player to fighting one, rarely two enemies at a given time for a location. Fortunately, the structure of the souls games readily lends itself to this, which would reinforce the deadliness of each encounter. We would also probably have to limit the total number of enemies in the game, to further save on memory. To mitigate the feeling of reuse, the enemy’s AI would have to be a primary focus of the programming for the game, so that each would feel like a unique and difficult challenge every time they were encountered.

The other aspect of souls games that needs to be respected is the 3-dimensionality of the combat. Dodging, ducking, and simply moving allows the player to gain tactical advantage. Calculating 3D collisions can be extremely computationally expensive, but I think it can be done in such a way that can easily run on hardware.

The first advantage we have is that we’re likely fighting only 1 or two enemies, so our sword/spear/axe need only check if it’s colliding with those, and nothing else. We can express the collision test as a single point, defined as 3 numbers representing the x, y, and z elements, and the collider as a axis-aligned rectangle defined by 2 points, each with an x, y, and z.

But wait! Players and enemies in dark souls can’t jump! We can probably reduce the collider  hitbox to be expressed as a x and z width and depth, and then a 2d point with a height. And - what if the hitbox is assumed to be square? Then we can remove the depth, leaving us with a 4 byte definition for a box. This might make the collision test inefficient, though, so we might end up wanting to keep the 6 byte hitbox.

So, when the player swings a sword, we look up the pre-authored 3D position of the sword based on the frame of animation, and position it in a world space relative to the enemy hitbox, using as much integer math and cosine table lookups as possible. Then, we test to see if that point is inside the hitbox. If it is, we can tell the player that a hit has occurred, play reaction animations on both the player and the enemy, and deal damage. Since the most expensive part is the transformations, testing multiple points along the swing of the sword to simulate continuous collision detection might be a good idea that would be fairly performant.

A poor man’s continuous collision detection.

From there, we can add in crouching and rolling to the hitbox by lowering the height at runtime, and iframes by marking the player as invulnerable. If we end up using the 6 byte hitbox, we could even implement a jump, raising the lower-bound corner of the hitbox. 

This gives us a relatively expressive combat system - low swings that must be dodged (or jumped), high swings that must be crouched under, and other shapes like slanted or vertical swings that must be identified and moved away from accordingly.

The hard part is making tools to author all the different points to that the weapon would be at.

Controls

  • Right-bumper and Left-bumper to rotate the camera around the player

  • D Pad to move the player relative to the screen 

  • A to interact, and heavy attack

  • B to light attack

  • Y to duck, Y + D Pad to roll

  • X to use equipped item

  • Start to open the in-game menu

  • Select to change equipped item

Asset Production

In the era before cgi became cost effective, creating 3d-looking assets was a huge undertaking, especially for large animated sprites. The toolchains for assets were usually custom for each game, and professional tools weren’t widespread, cheap, or accessible.

If I were tasked with directing a game like this, I think my asset pipeline would be very inspired by Doom and Mortal Kombat. Since there would need to be multiple angles of each animation, I would set up an array of cameras around a subject, and then pose them, and take many pictures at the same time to capture the view from each angle.

For humanoid characters, I would probably recommend actual humans with costuming, much like as mentioned previously, Mortal Kombat. The player character could equip armor sets and have their appearance change, but only the entire costume, not each piece individually. This would also allow simple recoloring of the armor by using different palettes, giving even more variation.

Finish him!

For the non-humanoid monsters and possibly even for some of the 2d planar sprites, like trees, I would actually turn to terrain- and miniatures. For Doom, they actually sculpted some of the monsters in clay around wire armatures, and then posed them and captured them on a turntable to digitize them from every angle. However (I haven’t found a source for this) I suspect it wasn’t wildly successful, because about half of the monsters are either drawn from hand or kit-bashed out of other digitized monster parts. Either way, this would give the game non-human demonic characters with flailing limbs and bizarre forms, and provide really detailed props like trees and wells and bushes.

I didn’t have time or the motivation to do the above for this blog post, but this is a really cool way to create assets for old games that might actually be possible. Theoretically, one could also 3D render these back in the day with a Silicon Graphics workstation - much like how Donkey Kong Country was made [11], but that’s not quite as fun, is it.

Lore and Gallery

Look, we all get carried away. Here’s a big lore dump for this imaginary game, both that which would take place before the game, and the events that take place during the game. Peppered in are some mockup screenshots of the game. Hope you enjoyed reading this as much as I enjoyed writing and imagining it!

Eternal War

In the second age, the Divine War began between the Demona of the Underrealm and the Angels On High. Generations of humanity were born and died not knowing if it would ever end. The cycle churned the earth to mud and tore at the gristle of the world, devastating cities, corrupting rivers, grinding down the very mountains that clawed the darkened skies. The godly strength wielded by both sides gutted the world, cutting dungeons deep into the earth, and raising holy strongholds that pierced the continent like barbs.

Caught in the middle, humanity cowered in the fields and beneath their thatched roofs, praying for the mercy of a quick death at best. None believed the conflict could end; it simply was.

Annihilation

None alive know what tipped the scales of balance, but gradually the Demona gained ground. At the Gilded Keep, during the final battle, the Archangel Cassalia sacrificed herself with a dark magick, annihilating the keep and the surrounding armies. The 6 Demona Kings, greedy and impatient in their impending victory, fell to the fiery inferno. However, the other Archangels, the final bastion of Angels, and scores of the Demona legions were destroyed as well.

Men peeked tentatively from their shelters, finding only the battered armor of Angels and mangled corpses of the damned, and cautiously took their first steps into the light of a new era. Crops were planted in earnest, and the sun swept golden hills glowed with new, if wan, light.

Vitality

Centuries after the end of the war, rumors of the return of demon kings or archangels are still exchanged in taverns after too much ale. Humanity struggles and people are starving, but there are more born every year that survive the winters. Occasionally, Demona are sighted skirting towns and haunting roads, feasting on the unwary travelers flesh, but for the most part all is peaceful, if uneasy. 

Enlightenment

You are an experienced fighter of demons, and you’ve been summoned to Tarnis, a village near the ruins of the Gilded Keep. You’ve agreed to come after the village scraped together enough gold to convince you to come help. As you arrive, you hear tales of a Demona Prince, a rarer and more devious variant that has a propensity for organizing larger covens and commanding minions.

You delve deep into the ruins of the keep, protecting yourself from the local fauna, ancient Angelic traps, and the occasional lowly demon, until you reach a sanctum far below the loam outside.

You behold the golden body of an Angel - the first seen in living human memory. She has clearly been tortured, and the tormentor, the Demona Prince Z’lek moves quickly to eviscerate your intrusion. Blade flashes against bone and claw, and the creature falls twitching and writhing in it’s own ichor.

You free the Angel, who names herself Ailas, and she tells of the rebirth of the six Demon Kings. She begs of you to slay these reanimated carcasses, and promises the eternal ecstasies of divinity in exchange for your devotion to her. 

King Hunting

Your travels take you to flooded tombs in fetid swamps, to barren desert temples, to deep underground where the air ripples with the heat of the planet’s womb and the ground glows beneath your feet.

Each of the Demon Kings falls beneath your blade in turn. Skittering malignant spiders, Corpulent oozing giants, and festering demons of fire - it matters not. You take blow after blow, rending armor and cracking helm, but you persevere on, knowing Ailas and eternity await you.

The final Demon King is deep within the depths of hell itself. A glistening red beast, like bone bathed in blood, it slashes and claws, leaving you broken and eviscerated. You slay the creature, but only barely, and as you collapse from weariness next to it, you hear it gurgle. It asks why you have disturbed the balance, why you would favor the Angels on High? For, it continues, with none left to protect humanity, there is none to stop the Angels from finally enslaving all mankind.

It’s eyes roll back and black blood seeps.

Veritas

You limp back to the Gilded Keep, clinging at wounds that refuse to close. Pushing open the door to the throne room, you see Ailas atop her restored place, resplendent and bared in gold. She offers a hand to you, and asks one final question - will you join her? Or will you fight and slay her to take the throne for yourself, and for humanity?

Further Reading

[1] https://www.youtube.com/watch?v=3FVN_Ze7bzw

[2] https://www.youtube.com/watch?v=K7gWmdgXPgk

[3] https://www.youtube.com/watch?v=57ibhDU2SAI

[4] https://doom.fandom.com/wiki/Super_NES

[5] https://en.wikipedia.org/wiki/Super_3D_Noah%27s_Ark

[6] https://www.youtube.com/watch?v=IhMMK3QLxSM

[7] https://www.youtube.com/watch?t=822&v=HQYsFshbkYw&feature=youtu.be

[8] https://twobithistory.org/2019/11/06/doom-bsp.html

[9] https://www.youtube.com/watch?v=kOnUITJqRQQ

[10] https://www.youtube.com/watch?v=ZWQ0591PAxM

[11] https://www.youtube.com/watch?v=vTBnzCb6jMM