Process 1: Creating Infinity
A Compelling Notion
In my experience artistic ideas manifest in one of two ways:
- Bottom Up
- An artist has acquired a set of technical skills through time and practice. With these technical skills in hand they identify some process or combination of techniques which might yield interesting results. The artist then goes about exploring that space.
- Top Down
- An artist has acquired a set of intuitions and aesthetics through experiencing life and ingesting other pieces of art. With these in mind one day an emotion or thought bubbles up into their being and the artist realizes it is interesting. The artist then goes about exploring that space.
Though it may be tempting to think that the second is superior, especially since art is largely thought of us as being a practice which articulates emotion, I actually find both to be useful forms of creativity and have used both to good effect. With that said the central premise of Recursive Ruin, that of an infinitely repeating world contained within itself, came about top down in one of those half-dreaming moments of delirium soon after waking.
I imagined being in a space and seeing that exact same space before me, but in miniature scale. I stepped forward and lifted an object in the miniature scale and the object at my scale moved along with it. I have no idea why I thought of this.
It was a cool idea, one I hadn’t seen done before (this was before Manifold Garden was announced, which has a similar but not identical conceit). Certainly I have an unhealthy obsession with recursion and feedback, and I’m drawn to mandelbulbs and fractals, so there’s plenty my mind drew from. The mixture of being in the space and manipulating that space at a different scale seemed to speak to me. So great, a cool idea. But is it just a cool idea?
Not Just a Cool Idea
The problem with top down ideas is that they don’t come prepackaged with how to execute them. Instead you have to explore how best to manifest the idea. This is a process and where you start is often not where you end. This process can take a long time and a lot of effort. Given this it’s sometimes best to fake the idea first, to see if it really has legs. Then if it seems to work conceptually you can go about trying to make it actually work in practice. Some people may call this prototyping, but I tend to think that true prototyping should be functional. You can decide for yourself what to call it.
To test the infinite world idea I decided to create a simple scene comprised of whatever I had laying around, and then simply copy and paste that scene at increasingly larger and smaller scales. The scene consisted of a block platform to walk on, a Cthulhu-esque mesh my brother sculpted for fun, a cube, and some stairs. Walking around the space, as primitive as it was, convinced me that this wasn’t just a cool idea. The concept had several things going for it:
- It was immediately grokkable what was going on:
- Hey the world repeats!
- There were immediate gameplay ideas:
- I could move that small cube around.
- It was striking visually and emoted something:
- What a strange and interesting place…
- It implied a manner in which to construct itself:
- Build a world made to surround itself.
- It made me want to explore:
- I want to keep walking forever! I’ll always end up where I began...
Astute readers will recognize this last thought as a “Strange Loop,” a concept created by Douglas Hofstadter, and I myself had it in the forefront of my thinking as soon as I was walking around in that space. The idea is that there are some hiearchical systems which exhibit an interesting behavior whereby traveling in one direction along the hierarchy ends up arriving at where you first began. The Möbius strip, video feedback loops, and successively transposing keys in western music theory are some examples of this concept. The infinite space idea did this as well. It’s a lovely concept which has all sorts of interesting connotations thematically and philosophically.
So there was plenty going on with this idea, plenty to explore.
For Real This Time
Ok, so now what? How to actually create this idea. How does one go about creating infinity? There were a few paths that one could take:
- 1. By Hand
- Like the fake version, but with code that ties the repetitions together. Simple but restrictive and would require a lot of copy+paste every time there was a level update. There’s also the question of what happens were I to jump down into another repetition?
- 2. Algorithmic Geometry, Naive
- Create an algorithm that takes a scene and procedurally repeats that scene at each repetition as new geometry in the game. This would be done with a presupplied matrix which would define the transformation between repetitions. Were the player to move between repetitions the system could simply destroy and create repetitions as need be.
- 3. Algorithmic Geometry, With Pools
- As above, but rather than creating new geometry on the fly when we move around, instead we create pools of geometry which is activated, deactivated and transformed as required.
- 4. Real-time Procedural (AKA Demo Scene 4 Lyfe)
- Instead of fucking around with creating, pooling, and reclaiming geometry in a standard game engine we define all of our geometry procedurally at run time. This procedural geometry would work much like how the demo scene creates their visual works, and would use a transform matrix to create the repetitions at different scales in a simple and direct way. Our physics and collision system would also need to be aware of this repeating transform.
Option 1 was clearly the worst of the bunch, being somehow clumsy technically and artistically, and was never seriously considered. Though option 3 was more complex than option 2 it was not much more complex, as pooling is a pretty standard technique, and it seemed to offer only upside. Option 4 is very tempting as it is quite elegant, and I’m a sucker for elegant solutions. That said option 4 would likely require a custom engine, and I felt like that was probably unfeasible given that I was already spending extra programming time developing my own programming language for audio and music (see the next blog entry for that story…). So, option 3 won.
Here's a very early prototype demonstrating this technique.
The idea works! Of course everything is grey boxed and looks like a weird 90's game about Ikea furniture. A ton of work went into making everything pretty (a topic for another blog entry) and this is what that scene looks like today:
Deeper, and Deeper Still
Ok, so we have a solution that works well for rendering and collision, and which doesn’t require us to create an entirely new game engine. But this only handles the scene geometry, what about gameplay logic for the objects in our game? After all the initial idea was all about manipulating things. The realization came that each object did not exist on its own but instead existed as a network of objects with an instantiation at each repetition in the world.
These networked objects would behave in concert with each other: If the player picked up a cube at one depth, all the cubes “networked” to that cube in the other depths needed to reflect this and move in concert with it. The fun came with the realization the player might interact with objects outside the player’s immediate repetition. We needed a way to keep all of this organized and to properly communicate to all the objects in their respective networks, taking into account differences in transform.
To codify this I re-framed the repetition concept into a concept I called “depth” which was defined in two ways for every object in the game:
- Absolute Depth (adepth)
- This is the number of repetitions inward or outward, from the absolute starting depth, that the object belongs to. If the player traveled inward 10 repetitions and picked up a cube, that cube would have adepth 10. If they traveled outwards 20 depths from there and picked up a cube that cube would have adepth -10.
- Relative Depth (rdepth)
- This is the number of repetitions inward or outward from the player’s current depth that they are standing in. Thus if the player picks up a cube which is at the same depth as the player it has rdepth 0, if the player picks up a cube which is 1 depth inward that cube has rdepth 1.
While seemingly pedantic having this sort of fractal coordinate system made coordinating and propagating changes amongst the networks of objects more organized. This system underpins much of the game play systems in the game and is what allows for these sorts of coordinated game play interactions:
A Scanner Actor at rdepth -1 detects the player standing at rdepth 0, while a Scanner Actor in the same network at rdepth 5 detects a cube sitting at rdepth 3. Scanner Actors prefer closer targets to further, but also prefer cubes to players. The Scanner system as a whole decides that the cube is the better scanning target, and the entire networked system of Scanner Actors turn, relative to their own rdepth transforms, to look toward cube and activate their powering systems.
When exploring the space of an idea you will often happen upon ramifications for the idea that you had not originally considered. This is an interesting point in the process and one of the most fun. It’s a bit like a mystery, as you are teasing out what all the pieces mean in a greater context.
The idea that you could move objects around at different depths was in the original idea, but once I codified more how to do that and what it meant I was confronted with a few questions related to objects physically simulated objects which could move across depths. So, what happens when:
- I throw a cube into another depth?
- I pick up a cube from another depth and drop it in a different one?
- I pick up a cube and then carry it with me across depths?
- I try to pick up a massive or super tiny cube?
- A cube is extremely offset from its “origin” depth as to be giant or tiny?
- There is some interaction between objects which are depth “asymmetrical” (i.e. an object which exists at some depth(s) but not others, like the player).
For each of these I aired toward the answers that seemed to give the most gameplay depth and consistency. We ended up with these answers:
- The cube will physically simulate moving through the space. When it comes to a rest it will be “adopted” by the new depth it is in and transition to a size appropriate to the new depth’s transform.
- As above however the cube should maintain its current form while the player is holding it, and only be available for depth changing once the player lets go and the cube is in a rest state.
- As above, but we should make sure that the cube I’m holding maintains its size even as the rest of the world around me shifts in scale when I make a transition across depths.
- We’ll put an rdepth limit on cubes you can pick up, which elegantly prevents shenanigans.
- We’ll put in place a depth offset limit. Should an object be too far offset from its original depth (making it gigantic or microscopic) we’ll immediate adopt it to its current offset depth and resize it to the appropriate size.
- We treat the game world as a logical “OR” of all symmetrical and asymmetrical entities across all depths. So even if things aren’t present at every depth each object at each depth will interact as if it did.
Justified Hierarchies of Power
These formed a set of rules which defined the behavior for moving objects. It’s obvious that the objects in this world behave quite differently than normal objects. It became apparent that with behavior this complex the simple network of game objects concept wasn’t enough to coordinate and organize these moveable game objects.
To solve this dilemma I represented physically simulated game objects as Hierarchical State Machines (HSM’s). The objects receive certain events such as:
- Transition Depths
Each state in the Hierarchy would respond to these events differently and handle them appropriately. These states included:
Finally the last bit of magic involved combining these HSM’s with the game object networking. This enforces that each object in the network is in the same state at the same time. When one of the objects in the network receives an event, such as hitting the player, that object forwards it to the HSM system which then processes the event in the context of the object’s current state. The ramifications of that event, including transitions to different states, are then propagated throughout the entire object network.
Later Work (But Not Infinite Work)
The game continued to develop in this way, and there was quite a lot to unpack and explore, all extending out from that one initial idea. Very meaningful systems and themes that came about from this included:
- Altering the depth transform during gameplay (Shifting)
- Offsetting the depth transform during gameplay (Shrinking)
- Developing a story around wanting to escape into a placid infinity.
So altogether, quite the successful idea. With all of that said, it’s important to recognize that not all ideas are this successful. Many ideas, if not most, don’t make it out of that initial phase of scrutiny. A bad idea gives little or even nothing back when you ask something of it. A good idea should be one where each time you scratch the surface, each time you ask a question, you get more back from it than you put in. That’s how you know there’s something there.
As I’ve gotten more experienced I realize more and more the importance of finding deeply arable ideas, of holding ideas to greater initial scrutiny. It turns out most ideas range from bad to mediocre and you can waste a lot of time trying to squeeze blood out of a stone by trying to make a mediocre idea work. But when you hit the really good ones, it can be hard to stop, it gushes forth. I live for those good ideas.