This past month has seen the least development time on the project of any month since I started this blog. Still not zero, but the progress I have made is not very flashy. December will be more fruitful, and the project is still alive.
So, instead of information, this time I have a request. If you have a favorite star system, real or fictional, make a comment telling me what it is. If I can find enough information about it online I’ll recreate it in the game and post pictures in the next update.
Last time I talked about tighter coupling of gameplay logic to the core simulation. A deeply connected and equally important effort has been uncoupling the game display and that simulation. Over time some simple, easy first-effort implementations of features have given the user interface direct access to the core simulation data. The interface obviously needs some way to get that data to display anything, but full unfettered access can lead to trouble and rigid code that is hard to update later. A lot of my work since the last post has been me finally pulling off that band-aid, cutting off access that the user interface has completely and fixing everything that breaks. I believe that’s pretty well finished, and everything works now.
In addition to clearing away that technical debt I’ve been able to get some important simulation features in place, the first fruit of which is engine recognition of barycenters. As previously discussed when talking about adding binary stars to the level editor, a barycenter is the point around which a pair of objects orbit. Strictly speaking all cases where we would say one object orbits another are actually two objects orbiting a shared barycenter, but if one of those two is significantly more massive than the other the barycenter and the center of the more massive object are so close together that it the difference can be ignored.
When two objects are similar in size however, and assuming that no outside forces affect their motion, then both move noticeably around a single empty point in space. You see this in binary stars, or more rarely in binary planets. Pluto and its moon Charon form such a binary system, and some have argued the earth and moon ought to qualify too.
While it’s been possible to set up that structure in the level editor for months now, there’s been no ability to see them while actually playing the level. Now there is! Below is a snapshot of a binary star system under this function.
The trajectory-line drawing code doesn’t know how far forward to draw the lines in this case yet, and is still figuring it as if the heavier star were stationary, but that’ll clear up in time. You can still see that the secondary star(Naanlil) is orbiting around the barycenter, instead of the primary star(Anlil). The other limitation at present is that it doesn’t have a good way to detect appropriate places to put barycenters or a means to have level objectives refer to them. That is in the cards, though. The systems that allow this will also provide a framework for working with Lagrange points more richly.
About Objectives Again
Last time was talking a lot about the partially finished work with objectives. Now I do have a functional level with those systems, testing objective chaining, duration, and alternate conditions. Take a look!
This also shows the greatly expanded information in the objective display section. That’s subject to plenty of revision, but should remove a lot of guesswork at what you’re supposed to do. In time more visual signposting will be worked into the main rendering itself, but having the written version of the objectives should make it a lot easier to learn what those visuals mean.
Now seems like a decent time to share one of the tools I use to keep track of my plans for ASR. So, below is my high-level to-do list, made with the wonderful Graphviz tool.
Unfilled are things that aren’t implemented at all yet, blue are things I think are probably complete, and light blue are things that are functional but I expect to have to do more work on. Of course this list shouldn’t be seen as set in stone, things may be dropped from it or added to it, but that’s the plan at present.
A final note, I’ve seen a big uptick in spambot activity here getting past my existing filtering. AApologiesin advance if I miss approving a comment in the sea of noise.
At its heart Atomic Space Race is a puzzle game. Puzzle games live and die on the puzzles they present, and there must be room for some complexity if the game is to have any staying power. One form of complexity is in giving the players additional tools. While I do have some ideas for that, it’s not a long list. Another major form is in what you’re tasked to do. To date the objectives in a level, or track, in ASR have been relatively simple, always taking the form of getting within a set distance from an object at some point in the level’s set duration. This has been a good start, but I’ve wanted to open up more options there. To that end I’ve rewritten objective logic and handling to that end, with a number of aspects.
The new system allows the designer a choice between the objective being to have your distance above a set value instead of below. This could be used for disallowing approaches too close to an object, or directives to escape an object.
The old system only allowed objectives of the form ‘meet this requirement at least once’, the new one also supports ‘meet this requirement once and then continue to meet it’, which can be used to impose additional requirements on the shape of a course after meeting the objective.
The new system allows objectives to be chained, so you can require they be completed in a certain order. An example use of this is a mission where you need to flyby the moon, then return to the earth. Approximating long multi-stop cargo trips also presents itself as an option. An objective can be valid before or after the objective it is dependent on.
Objectives can have a time limit that they must be completed within, and if they are a link in a chain objective that time limit can be relative to the completion time of the parent objective. Objectives can also have a duration, where their conditions must be met for at least that long before being considered complete. This could for example complexify a round trip objective by requiring you to spend at least one orbit’s worth of time around each destination. Then you need more burns than just a simple flyby.
A related change is that levels will now be run for a stretch of time after their ‘finish line’, definable by the level editor, to allow levels where part of the challenge is to get your course in a state that remains stable without active correction for a ‘cooldown’ period.
The kinks are still getting ironed out on all the possibilities here, but most of the pieces are in place. This has led to some restructuring both in my level editor code, which happens every time I touch it. It’s also seen me move the entirety of the objective handling code from the unity layer, where it was uncomfortably intertwined with the UI code, and into the underlying engine layer with some carefully chosen parts exposed to that UI.
I’d previously wanted to keep the engine layer as gameplay-agnostic as possible, but I’ve come to the conclusion that most gameplay needs tighter coupling with the simulation than is healthy for other parts of the program to have. As I intend to have a unity-free, ‘headless’ version of the simulation that can do various gameplay supporting operations(level baking, solution verifying) and some of those need a concept of level logic to properly function. The rewrite and tighter connection to the simulation has also fixed some issues with the old system not always detecting objective passage if the player ship was moving sufficiently fast, while still performing plenty acceptably.
With luck next time I’ll have some levels that take advantage of this new system to show off! I’ll likely implement delta-V caps(aka fuel limits) for levels as well to put a bit more pressure on level solutions, at least on a trial basis.
A quick followup on the game jam mentioned in last month’s post. Despite some difficulties with my own energy level throughout, I felt I did quite well at stretching my boundaries with the game I made, doing some sprite work for the first time and approaching the structure of the code in a different way than I typically would. The game I made in many ways mimicked the economic model of Supreme Commander, and I was very satisfied with how much of that model I was able to put together in the time available. The game fell down somewhat on presentation, not adapting well to varied resolutions nor explaining it’s mechanics well. I’ve found that people who are already familiar with Supreme Commander have a better chance of getting hooked to some degree. As always with Ludum Dare, an imperfect game, but a great learning experience.
Lastly, I want to thank everyone who has filled out the tester sign-up lately. I’m holding off on the next wave of testers until I get the next major UI change in place so that I’ll have some fresh eyes and hands as well as people who’ve learned how the game plays already. However if you want to hang out and chat with myself or other interested people on the public portion of the discord server, this invite link will take you there.
Previously all objects were drawn as simple dots no matter the zoom level. For the largest parts of most courses this is quite sufficient, but when you get to the interesting bits near planets it can become important to see where the space ends and the ground or sky begins. At present there is still no collision with the ground, but object size is now stored and, if viewed closely enough to visible, displayed. I’ve found it provides a nice reference point for scale when you get close to things and the curve of large orbits falls away.
Here’s some looks at familiar locations in the solar system.
Beyond that, I’ve been able to refine some aspects of UI responsiveness and resilience based on tester feedback, as well as iron out kinks in my build preparing scripts. Nothing very exciting, but the game plays a little better as a result now. Reminder, if you’re interested in testing you can still fill out the form.
Finally, this weekend I’ll be participating in the 42nd Ludum Dare, a 48 hour game jam. It starts at 5pm central time(GMT-5), about 4 hours from time of writing. In the past I’ve found it to be a very valuable exercise. I will be attempting to stream my efforts with it via my twitch channel, and if that for whatever reason proves impractical I will be updating through my twitter, if you are interested in following my progress. When it’s done I’ll edit this section as is appropriate.
It is common advice to test your game as early as possible and keep testing it constantly throughout development, with as many fresh eyes as possible. I’m sure it’s very good advice, but it’s hard to follow when starting from zero in terms of following and budget, especially the fresh eyes part. I’ve gotten a few friends to test earlier versions of Atomic Space Race some time ago, but it’s time to cast that net again. If you want to be involved I’ve set up a signup form here. I’d prefer to coordinate tests by means of a Discord server, but if that doesn’t work for some interested potential testers I’m open to other ideas, and the form has a place to suggest. The comments section here works for suggestions and discussion too.
Currently I’m building versions for Mac OSX and Linux as well as windows, but don’t have enviroments to test them myself.
One of the challenges with testing is drawing the line on when enough has been implemented to push it out the door. There’s always one more thing you want to do before it’s ready, especially when there are large parts unfinished.
Many things have been advanced a little, but only a few item have come to fruition since the last posting. One is a basic options menu, presently just a color option and some volume controls. The other is sound and music for those options to control. Sound design and music production are areas I have no expertise in, but there’s some good resources out there. In particular I’d like to highlight Gravity Sound who has produced several tracks I’m using in the current build, and has plenty of other good work I’m not using.
Another challenge is minimizing the amount of repeated work every time you need to release a version. I’ve got a build-and-package script from when I made the Atomic Space Tools builds, but that was at least one computer and several adjustments of the file structure ago. My ideas about proper package structuring and naming conventions have also evolved, so I’m revising all that before getting myself locked into anything.
Lastly I’ve moved the project from Unity 5.x to Unity 2017. Constantly moving up versions isn’t a great idea for an ongoing project, but there’s a few behind the scenes features of newer versions that I’d like to have on hand, and 2017 is the basis for Unity’s current Long-Term Support version that promises to get stability and compatability updates for a while without the major feature changes of the ongoing verison, so I made the decision to make the jump to that rather than Unity 2017. This time at least it was a rather painless update.
Again, if you are interested in participating in testing, check out the signup form. First testers will probably get given links within the next week.
Back in News #3 and the subsequent video I talked about reference frames. As this update builds on that idea, I’ll recap. It is often useful for course planning to draw the universe as if something that is in motion isn’t. If you draw the solar system from the reference frame of the sun, the course of the moon makes a wobbly spiral around the course of the earth, which isn’t very useful for flying from the earth to the moon. If you draw the solar system from the perspective of the earth, then the moon makes an orderly circle that’s much easier to deal with. The sun also makes a circle around the earth then! And the other planets make weird curly paths.
Incidentally, these kinds of weird shapes are related to the various complicated systems people came up with to explain the motion of the planets in the sky when they thought the earth was motionless. In any case this relatively simple form of reframing the view can be quite useful for many kinds of courses, but there’s another step further beyond that’s useful, the rotating reference frame.
Consider the Lagrange points. To recap them as well: For every sufficiently massive object in a circular orbit around a star or planet these five points of relative stability exist, three along the line between the two bodies, two along the orbit of the smaller body at a 60 degree angle to that line. These locations have been used for space missions both completed and proposed and have influenced the locations of large populations of asteroids, so they’re worth consideration.
If you draw the motion of the earth-moon L-points from the perspective of earth you get circles. If you draw them relative to the moon, you get circles. Neither of these are great for helping you see how your course relates to these points.The solution is to draw the universe as if neither is moving. You create a rotating reference frame where the universe rotates around your primary object once for every orbit the secondary makes. (The implementation for ASR actually just rotates the universe so the secondary is always to the direct right of the primary, but the difference is probably only significant for notably elliptical orbits) This has the following effects:
The secondary appears to stay motionless, if it’s orbit is perfectly circular. Otherwise it’ll wobble around a bit.
The Lagrange points appear stationary too, plus a little wobble as above.
Objects orbiting the primary or secondary will generally have recognizable orbits rather than arcane curls
Objects interacting with the Lagrange points will have quite interesting curls!
If you look at diagrams of the Apollo missions where you get a figure-8 like structure with the ship circling around a static earth and moon, this is an example of a rotating reference frame. I have found that planning similar courses in Atomic Space Race is a lot easier with this tool available. Without it need to either rapidly switch between reference frames or do a lot of scrubbing along the timeline to determine you approach your target after tweaking a transfer burn.
The same advantages manifest when dealing with courses that interact with Lagrange points. A great example from outside of the project is this animation of the motion of asteroids influenced by Jupiter’s Lagrange points, produced by Petr Scheirich. If you drew those all those courses in a normal, sol-centric non-rotating frame you’d just have a huge mess of orbits overlapping Jupiter’s, but in the rotating frame you can clearly see the structure emerge.
If you want to see this in motion in-game, particularly with examples of Lagrange-interacting orbits, here’s a video I made of that.
This post goes up close to two weeks behind when it should. Sorry about that. I will try to get the next one out in a little under a month to wind that back. That said, the development since last update has been largely invisible. I’ve mostly been doing more under the hood improvements that pave the way for other features, as well as code cleanup and planning. No pictures this time, but I did bring some words.
Investigating Level Baking
For context, I will give a quick refresher on the architecture of the game; when you start a level the motion of everything in the system is simulated forward as fast as possible and stored in memory. Thus, when the player changes their planned course, the motion of the other objects doesn’t need to be resimulated, only the motion of the ship does. It stands to reason then that the next step is to simulate the system once when the level is created and save the positions to disk rather than memory. This would ease the load on lower end machines and make practical more complex levels than would otherwise be viable.
That opens another can of worms, though. If freed from the need to simulate them at runtime, highly demanding systems such as ones including the sun, Jupiter, and Io for multiple Jupiter years start sounding like things you might want to do. But in the present state, that’s not possible. Holding that much state for Io in memory at once isn’t possible at the resolution needed to keep Io stable.
It would make sense then to simulate it at a high enough resolution to ensure stability, then save out a lower resolution set of points that can be interpolated between. The conceptually hard problem then becomes, for me at least, finding a general way to measure error in this process to ensure the right number of points can be saved. For instance, from a far enough view Io’s motion around the sun looks just like Jupiter’s, but if that’s all that’s saved then we’ve got a big problem. The primary way that I’ve come up with to best deal with this need for context would probably slow the simulation down, but if we’re pre-baking the levels anyway that’s acceptable up to a point.
Picking the right way to do the math on the interpolation should be less difficult, but I want a way to measure any error it introduces to ensure that I’ve done it right, and that leads us right back to the same question again.
These problems are ones I ground my brain against for a while, then put back on the shelf for the time being since it wasn’t getting anywhere and there are some other ones that yield more immediate returns in game-ness.
Tutorials and more abstract levels
Which brings us to the next point, tutorial levels. I’ve some design on how to introduce concepts in their smallest possible steps, which is important for something like this, and I want them at least partially realized before I hand this off to any testers(which hopefully will happen soon.) Getting those from idea to level has needed some expansions to the types of objects and data the level editor can handle.
I thought that would be the hard part, and while it was tedious it turned out that I’d left myself a surprise in the code. Quite a few parts of the simulation, and the game on top of it, had been built with the unexamined assumption that there’d be at least one object present with mass. It’s a fair assumption for any full blown levels that emulate a physical location, but some of the tutorial levels break that rule. I had to go on a small safari through the code base to whack all the moles that one surfaced. Now that works, but I’ve got a good chunk more work to do on replacing the rather bare-bones objective definition and evaluation code to do before the tutorials are really done.
Parts of the capabilities I’m building here will likely also go towards making levels with non-physically-founded features similar to those in some science fiction universes. Because seeing how that would work out is fun.
Finally, a somewhat fluffier matter! Back when objects were identified by name, the player’s ship had to be named ship always. Now it’s set up so that in the level editor it can be named anything, and a very low hanging fruit is to rename it from a list of options(later on I mean to let the player pick a name of their own if they’d like, too). I’ve made a short list to pull from of my own, some with personal meaning, some of historical spacecraft, and some with sci-fi meaning.
If you have anything you think would be at home in such a list, feel free to suggest it in the comments! Though keep in mind that in the case of sci-fi sourced names I’d be more inclined to include names that make sense when separated from their source. For instance, Enterprise may make most people think of a particular property first, but it’s been used for real ships many times(and it’s in the list of space shuttle names, so it’s in anyway). ‘Galactica’ on the other hand is pretty married to its property, so it’s not in. But if you think it really belongs, feel free to suggest it anyway!
This month has seen a host of small improvements piling up, some of which are invisible code changes. While any one may not make much of a visual splash, they add up to the game being in a better place to move forward than it was a month ago. I’ll start with the more visible ones and then get to the code digging.
Font Choices and Title Design
When it comes to the look of a game, fonts a tricky thing. Using the defaults for the engine or graphics package can subconsciously look cheap or lazy. Picking something distinctive is good, but you have to make sure it’s readable in your game without being confusing or straining. Add in the thousands of font options out there and picking a good font can be trying. Here’s just some of the fonts I looked at when trying to pick one.
You get a bit more room to be bold in titles and logos than general user interface, but I ended up using the same font family for both. Getting it all in the game has helped the look along subtly, but significantly to me.
Also visible in the above screenshots is a new edge-of-screen glow to really get that retro screen look going. The backdrop for the game isn’t a pure black anymore either, though it’s close. This will probably need to be user-tunable with options eventually, much like the general bloom, but I’m rather taken with the effect. All together the game is looking a lot different than it did a year ago or even three months ago, and rather for the better I think.
Bouncy Objective Indicators
Harder to show off but just as important, I addressed a nagging visual issue with objectives. With celestial distance scales a perfectly reasonable objective that is no trouble to hit may be so small as to be invisible when viewing the whole level. For instance, if you fly from Earth to one of Jupiter’s moons, then when you are looking at both Earth and Jupiter you won’t even be able to see the particular moon you’re after, let alone the objective zone around it. This makes objective indicators bad at helping people understand the objectives at a glance, which is most of their job. My solution is that objectives now have a minimum visual size. If you zoom out far enough that they should be smaller than that limit they will stop shrinking.
Naturally, that reduces their effectiveness at helping you refine the course, as now it can look like you’re meeting the objective, since your course appears to cross the circle, but you aren’t because the circle is being drawn larger than it should be. To help address that if the real objective is smaller than the displayed one the circle now animates. At present it bounces in and out to indicate that you need to get closer. I also tried scrolling the texture, and may turn that on for some testing builds in the future to see how players react to the different options.
This project is one I’ve been working on, to varying levels of intensity, for quite a bit longer than this blog has been up. I’ve developed a lot as a programmer in that time, and sometimes I realize that what seemed like a good enough idea years or months ago is holding things back. This month I attacked a pile of these problems that have been sitting around for a while.
If this gets too dry, there’s a few screenshots of other new things in the next section.
Object Identifier Rewrite
For something outside the simulation(like the GUI, or the drawing code) to get information about an object, one of two things is needed. Either the outsider needs far too much access to the internal structure of the simulation(see thrust IDs below), or there needs to be an identifier the outsider can ask for information with. Originally, I decided that I should just use the name of objects as the identifier. They need names anyway, so why not?
Well, two reasons. One is that passing around text chunks and comparing them to each other is not the cheapest option computationally. This hasn’t been a huge performance drain, but when ID comparisons happen thousands of times per second then it’s a problem worth addressing. The second reason hasn’t been a big issue for the simulation but has cropped up in the level editor where I repeated the mistake. If for some reason you change the name of an object, you’ve suddenly caused chaos for everything that referred to it. If I happened to make an objective involving an object in the level editor and then changed that object’s name it would cause errors that required opening the level in a text editor to fix
That’s all fixed and more resilient now. Everything is referred to by ID numbers everywhere that matters, and unless someone hand-hacks a level file to have duplicate identifiers all should be good. While I was in there I made a few other changes to the data structures and how they’re searched that resulted in measurable performance gains. There’s always room for more of that, of course!
Another one that’s been waiting a while. Translating the huge scales ranges of space into computer graphics has challenges. The way computer games typically store positions(single-precision floating point numbers) has limited accuracy. If your numbers are all close enough together this is plenty fine, but if you start to get towards the far ends of their range they lose resolution and errors develop. This is fine for most cases and the technology used for games is heavily optimized around it. Unfortunately for space you have to deal with quantities that are so tiny(such as the force of gravity on Pluto) and distances that are so huge(such as the position of Pluto) that this breaks down.
Atomic Space Race deals with this by doing all the math at a higher precision, then converting to single-precision floats only to feed into a unity scene for drawing. Previously, this meant just converting the numbers and then scaling them down to fit inside a range floating point number’s range, then moving a camera around the resultant scene. This is doing things in the wrong order. Oops.
Since we convert then scale, things at the extremes of what floats can handle are still mangled on their way to the scene. Well, not anymore. I’ve rewritten large chunks of the display code so that now the camera is entirely stationary as far as unity is concerned, and positions from the simulation are scaled and moved before being converted to single-precision floats
The result of all this is a bit slower than the old way, unfortunately. Doing any math before converting to single-floats will always be slower than doing it with them. And along the way I centralized the reference-frame logic in such a way that it broke optimizations I made to orbit-drawing code earlier, making some more work for myself in the future. But the new way is much more resilient to extreme circumstances, adapting to them perfectly rather than relying on me to tweak some magic translation constants in the vain hope that a set of values existed that would work everywhere. It also opens some doors for more advanced reference frame manipulations in the future, which are badly needed for certain puzzle types.
Above I mentioned that letting things have too much access or knowledge about the internal simulation was bad, and this is a good example. I had a few persistent bugs in thrust editing. Whenever you selected or edited a thrust in the GUI, it was essentially saying to the simulation “Give me the first thrust” or “make this change to the third thrust”.
Well, what happens if you have a burn at T=1000, one at T=3000, and one at T=4000, then you change the third one to happen at T=10? It’s not the third one anymore.
This is something that can be managed with enough effort, but it can also be managed by just giving every thrust a unique ID number and having the UI communicate to the simulation using that instead. This is now done and works much better, squashing several squirrely interface bugs at once. It’s also just plain better design in general, which may pay off in the longer term.
After all that was done I rewarded myself by taking another look at binary stars. Back in ATOMIC SPACE NEWS #006 I talked about having gotten them into the editor but not quite sorting out how to get them from that into the simulation properly. Turns out the way I was mathing the starting velocities of the stars left the pair with significant net momentum. They orbited each other properly, and the planets all orbited where their stars should be properly, but the stars were zooming off due to imbalanced momentum and as a result distorting all the planet orbits. Got that sorted yesterday and already gotten a few cool systems roughed in.
An alternate, stable version of the above system in motion.
I’ve been hunting for good music and interface sounds for the game lately, and think I’ve got a few good candidates. Integrating them into the game has some implications that I’m not sure I’ll sort out by next month, but we’ll see. The above clip includes one of the music pieces I’m considering. Let me know what you think of it!
User interface/user experience is important to any game, even though some games manage to limp along with pretty bad interfaces. The Atomic Space Projects in particular will most likely live or die on interface, presenting as many aides and visualization tools as possible to make the alien and complex problem of orbital mechanics more approachable.
The interface of Atomic Space Race has been a slowly growing pile of elements shoved into random corners of the screen as they’re implemented, to just get things on the screen. That’s been productive but makes for a mess that’s hard for people who aren’t me to navigate. And even if you know where everything is, you need to cross the entire screen constantly when doing common things. That’s entirely no good.
So here you can see the reorganized user interface. For the most part the functionality is the same as the old, but things are a lot saner. I got tired of the grey look, so while I was at it I splashed some color on the interface.
This is by no means the final form of the user interface, either in function or look, but getting it to testers has shown a big step up in usability.
To cap this off I’ve put together an updated narrated video, since the old one didn’t have the bloom and newer UI.