Astral Traveller and Procedural Generation
ProcJam is next week! The chillest jam with probably the most hair-tearing subject matter: Procedural Generation.
While the Jam itself doesn't start till next week, part of its appeal is that you can really start at any point before the jam and submit anything you've been working on.
The Last two years I've submitted something made for other jams that also used Procedural Generation, as well as an entry that I made within the time limit. Two Entries a year! I know. I'm mental.
First was Tradum, made for Low Rez Jam in Pico 8 and includes a procedural galaxy to explore and trade in. That year I also made Castle Modnar, a procedural platformer/dungeon explorer. Both of which were fairly small games, without much in the way of depth to them. Such is the way with quickly made games.
The year after I made Seaborn, which used Tradum's generation, but focused on turn-based combat and a Pirate theme. And Catseye, which was an attempt at making a reverse-database. One that holds no records, but generates them when you search for keywords. I still want to expand on Catseye some day and make a proper game with it.
But this year I've decided I'm going to pool together all the disparate generation systems I've been working on, or with, into Astral Traveller. Think of it as "80 Days, in space!" but with poorer writing and 200% more references to Prog Rock.
The aim of the game is to get back to Earth in time for "Exodus Day". Along the way you'll encounter all sorts of people and aliens, have adventures and generally be at risk being this guy more often than not:
At least, that's the plan.
For the past month or so I've been bringing together a bunch of procedural systems just to show off, really.
The game includes the following procedural systems that I'll be going in to a bit of detail about:
- Galaxy Generation
- Inter-system Transport generation
- Procedural Text Generation (thanks to RANT)
- Alien Language Generation
Generating a galaxy was one of the first things I did in procedural generation with Tradum.
Astral Travellers system is very different from Tradums. Astral Traveller's system uses the following parameters to generate a spiral galaxy, rather than the clump that Tradum had:
The number of stars is determined by the Star Density and the Threshold variables. Star Density is how much of an angle it increases per step, so a lower star density means more stars, and Threshold is the Perlin noise threshold for determining if a given point will be a star.
Scale is the value positions are multiplied by when fed into the Noise generator.
Jitter Scale is the thickness of each of the arms, and determines how far off the center of each arm the generator can look for stars.
Arm Start Distance is how far from the core of the galaxy each arm will start, and Radius is how far from that position the arm will stretch out to. Turns is the maximum number of full rotations the spiral can make. Each spiral will make 75-100% of that number of turns. This makes the galaxy look slightly more irregular, and allows more places for arms to come close to each other, which is important for actually being able to make travel links between arms.
The only values that the generator cares about are the X,Y and Z coordinates of the star. Z is determined by distance from the core and scaled by the radius of the galaxy, making the core about 10% of the thickness of the radius.
So you can see how having slightly different variations on the turn size merges some of the arms together, and brings each arm close to at least one other arm at various points in its spiral.
The main aim of the game is to get to Earth, by means fair or foul. The fair means are the transportation links each star has. After the galaxy has been generated, it goes through each system and finds all systems within a set radius and begins setting up transport links. Setting how often they happen and at what time of day, then using this to make a Saturday and Sunday service (Sunday has reduced service, naturally), how fast the shuttle is and working out how long the journey will take.
This is done as part of the star systems 'inflation' procedure. Which also includes setting things like the name, and the owner of the system. There is a second pass of inflation whenever a systems details are brought up, but this is flavour text with no real impact on gameplay otherwise (I'll get more into that in the next section).
Once the links are created it's then possible to build a graph of the galaxy and traverse it with a pathfinding algorithm such as A*.
For this game I used A* but with a different Heuristic than the Manhattan distance, or just the direct distance. Instead it uses the Radial Distance and will attempt to remain at the same radius from the center as its destination node. Well, I say that, it didn't quite work out like that. The radial distance on its own led to just as much overhead as just using Manhattan, as it would prefer to go back to the beginning and search there than if it were only one hop away from its target. So I used a hybrid of Manhattan and Radial. 25% Manhattan and 75% Radial. It's not guaranteed to find the shortest route. In this case, 'distance' is actually travel time, and pays no attention to if you had to wait a day for the next shuttle, or even if you had enough money to pay for the journey. So it's at best a guide for the player more than anything else. Smart players should be able to find alternate routes, and if they're short on cash will probably have to.
Procedural Text Generation (RANT)
RANT is an interesting tool I discovered several years ago, and is still in development. It's a system for writing procedural text in a kind of query language. I'm using it in Astral Traveller to generate system names, and to generate the system flavour text.
Here's one of the RANT Programmes I've written to generate system flavour text:
And this outputs something like this for New Tulsa Alpha:
The Name, Designation and Co-ordinates are generated during the initial inflation, and not by that programme.
RANT has been a great tool, but its query language is at the same time really simple, but also frustratingly complex when you want to do anything extensive.
Generating some random names is simple, as shown below, but as above, that script took me the best part of a day to get right.
A previous version of this generated one of my favourite place names: Aberdeen-in-the-Face. It wasn't intended, but it was funny. to the point that added 'Face' to my geography table.
Speaking of tables, RANT needs a dictionary in order to function properly, and this project has added a bunch of custom tables for it to pull stuff out of.
For example, the previously mentioned Geography table
In order to get a line from the Geography table you'd simply write <geography>. If you wanted one that could go with 'X-on-the-Y' you'd ask for <geography-onthe>, and the whole thing could be <places>"-on-the-"<geography-onthe>
It's great when you get into it, but it doesn't always do what you think it would, and the documentation lacks examples of some of the more complicated functions, or combining complicated things. I managed to muddle through and get this working.
I plan on using RANT when making the actual game part of Astral Traveller (so far it's just a bunch of systems munged together), in order to give the encounters you have along the way some flavour. Each encounter will be hand written, but might, for example, have the description of the area be different, or some incidental detail changed.
It also took a while for me to get RANT working on Unity WebGL. While it works great in Editor and Standalone as a plugin, when exporting to AOT Compiled platforms (like WebGL and iOS) it gets... confused. It uses a lot of reflection in it that the AOT Compiler misses, so I had to add this monster somewhere in the project
Alien Language Generation
This in itself could have been a Proc Jam entry. I've been working on this for a while now, and you can have a go at a web version here.
It has three parts, Language Generation, Font Generation and Translation.
Generating the language is fairly simple. It takes a list of common phonemes and picks around 20 of them to make up the aliens vocalisation library. It then assigns each one a single ASCII character. You end up with two tables, one for creating text, and one for creating translitterations.
Creating the Font is harder. The Font Generator has a series of sprite tables with similar looking parts. I have 4 tables, Basic, Runic, Ancient and Oriented to chose from.
From the ASCII table it can then generate a font based on a set of sprites. Each language can have a set of 'base' sprites that all characters must use at least one of, and the rest are added on to the top. This leads to characters that look similar enough to possible be the same language.
Unfortunately, it's very difficult to get a proper font-creation script to work at runtime in Unity. Using Unity's built-in font class I can get it working, but line spacing is always 0, so it can never multiline. Which is no good. I tried creating a font at runtime using TextMesh Pro, but ran into issues there. That's why in Astral Traveller I just have a single font I hand-made rather than generating one on the fly as I'd like to.
The rest of the functions work, and each galaxy, and each alien language, will map unique letters and phonemes together. They'll just so happen to have an identical set of letters to use.
Now the hard part begins. Actually making a game out of this assorted mess of systems.
Wish me luck, and I'll see you all in Proc Jam.
Incidentally, an early version Astral Traveller is up here.
Get Astral Traveller (WIP)
Leave a comment
Log in with itch.io to leave a comment.