We're excited about how Spire is turning out. Recently, we gathered together to merge the progress we've made independently in the last few years. Lexie has been building custom lighting and pathfinding systems; Terence has been working on the level generation; Woodley designed enemies and various game objects.

Lighting

We went through several changes to our lighting style over the years. Initially we were experimenting with a tile-based approach, where each tile is lit uniformly, as a throwback to text-based roguelikes. This looked great on very clearly defined tiles, but on more organic chunks of land, like grass and dirt, it was a little strange looking. We also couldn't quite find a good way to light non-tiles, like props and enemies, in a way that would look good with tile lighting. Over time, we started leaning towards higher fidelity textures and models, which looked better with a more natural lighting style.

We couldn't get the results we wanted with Unity's lighting, especially without sacrificing performance. Also, Unity's systems are not well suited for procedural environments, since a lot of features are unavailable during runtime. As a result of this, Lexie ended up writing a custom lighting engine that handles large numbers of dynamic volumetric shadow casting lights, as well as baking lighting at runtime using light volumes. It's able to dynamically build out light maps and volumetric data for our procedural levels, allowing for great looking shadows and radiosity at a higher framerate than Unity's system.

Pathfinding

Similar to the lighting system, we faced challenges with Unity's built in system for pathfinding. It doesn't allow for baking out data during runtime, so it is incompatible with procedurally generated levels. Our system allows for enemies to traverse any environment created by our system, with the ability to jump to and between ledges, find alternate paths that take the enemies width into consideration, handles destructible obstacles, and even accommodate flying enemies.

Enemies and props

As we've been building up the roster of game enemies, we're figuring out how the designs will synergize with each other so that you'll have interesting combat situations, instead of them just running at you and attacking. Our goal with the enemy AI is to force the player to think strategically and to take advantage of the advanced movement mechanics that emerge from using items and weapons in creative combinations.

The levels are starting to feel alive now that we're adding props to the world. Statues and pillars stand in fields of swaying grass and glowing mushrooms, and bookshelves and candles line the walls of decaying interiors. The challenge is not only in placing them in aesthetically interesting ways, but in novel ways that will hopefully surprise the player and feel fresh every time.

Level generation

The goal of procedural generation is to give opportunities to the player to achieve a genuine sense of discovery by finding areas never seen before, as well as to provide an unlimited source of content. We always felt that most existing procedural games seem to fall short on the first aspect. They tend to use one of two techniques: shuffling up pre-made areas, or randomly constructing geometry in hopes that it creates interesting layouts. The first technique loses its magic fast, once you start seeing the same areas repeated over and over; it feels like the same world, just jumbled up. The second technique gives you interesting bits mixed in a wasteland of cold, inhuman algorithm; it feels luck-based if you get something interesting.

Instead of these methods, we are taking a first principles approach to procedural generation. The system emulates what level designers are considering at each step, starting from a high level view of the overall arc of intensity for the whole tower, to the placement of each voxel block in the world. The details are better suited for it's own article, but for now, an interesting aspect of it to see is its physical constraint solver system in action.

This is just a simple example of a very basic room. After some room features are generated, their location in the room is determined by their relationship to other features and their impact on gameplay. For example, jumping platforms need to be a certain distance from each other, and important focal points need to feel like a central focus of the room. Catwalks should flow into other pathways, and hallway exits should be aligned to their most prominent axis. We built a physical solver to ensure all these constraints are met, all while adding a bit of chaos to the system.

A bright future

Spire has come a long way, and the game is finally starting to take form. We're four years into development now, mostly focusing on building out the technology that makes the game possible. There are a lot of interesting systems and designs in the game that we're excited to talk about in more depth as we finalize them.