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.
Demands on my attention outside the project have ramped up this month and will continue to do so, but I’ve still gotten good things done. I’m going to delve a little into implementation details for some of those things. If your eyes start to glaze over, skip to the bottom and I’ve got something more graphical to show there.
One thing I’ve been putting off for a while is taking control of the line colors. When I was first getting a handle on making Unity do my bidding I needed my lines to be distinguished by color but didn’t want the extra work of setting or storing the colors, since I had more important things to worry about. As such, depending on what part of the program you were in, the color of the line was either randomized on load, within certain bounds, or basically a hash of the object’s name.
Obviously control of the colors is something that’d be desirable to a level designer, so eventually this had to change. Once I got the new level editor working, with its basis in proper reflection-based automatic serialization, then storing/loading fixed colors became a snap. Setting them still was a bit of a task, though. I wanted to do that well the first time, which meant first defining what well is. A big part is being able to set the color by either red-green-blue values or by hue-saturation-value. HSV is a powerful tool for making controlled adjustments in particular directions to a color without knowing the exact RGB values of what you’re looking for. The random colors of old lines were done within a certain range of HSV values for just that reason. But at the same time, representing colors by their RGB values is so ubiquitous and useful that forcing one to use HSV instead would be a stumbling block much of the time.
The level editor has object types(‘editor line’ types) that handle displaying and storing different kinds of data, and now it has one specifically for colors. Generally editor lines only handle a single value, and in a sense this does, but it’s a color value rather than a simple number.
Doing all this made me revisit how numbers are entered into text boxes, and I ended up building a slightly better solution than my last one, which I’m switching other parts of the GUI over to a piece at a time.
Handling numbers in the Unity GUI system I am using has always been a bit twitchy. Here’s the obvious way to do it, the way that’s suggested in the documentation I found originally.
Take the number’s value and convert it to a text string.
Feed that text into a function that draws the text box
Take the output of that function and try to convert it back into a number.
If that conversion works, store the number back in the original variable.
Now this is done for every frame. A positive of this is that it effectively prevents the user from entering invalid characters. If the existing value is “100” and I type in “z” the code is going to try to convert “100z” to a number, not be able to, and next frame just display “100” again.
This would work fine if we were working with just whole numbers with small handfuls of digits, but we’re not. For instance the mass of the sun is 1,989,000,000,000,000,000,000,000,000,000 kilograms (roughly, an accurate measure is going to be both constantly changing and be a lot messier). Scientists and engineers got tired of writing all the zeroes ages ago, and gave us many flavors of notation to compress that down into something reasonable. The one we’re using right now renders that number as 1.989e30. So, you try to type this in to a text box, get as far as “1.” and the . refuses to go in. “1.” either is failing to prase back to a number, or is being read as “1.0”, and then getting spat back out as “1” again before you can get the 9 entered. Annoying.
You decide to be clever, and figure out 1989e27 is the same as 1.989e30, and get to “1989”, but entering that E hits the same problem. Finally, you put in “19890” and keep hitting zeros until the game switches it over to scientific notation, and now you’ve got “1.989e06”. Well, you’re almost there! You put in “1.989e306”, meaning to go delete the six next, and the game gets mad at you for putting in a number that’s too big. Finally you give up and just write it out in notepad and then copy-paste it in.
Similar problems arise if you need to enter in numbers that are less than zero. In the past I’ve sidestepped this, in particular for editing orders in gameplay, by just storing the text lines individually and requiring a button to be pressed to try to parse into their values. That’s no good if you want instant feedback, unfortunately.
Ultimately, for the colors, I made a new class to hold the data. How it works is it stores both the textual version of the value and the numerical value itself. Changes to the text string are stored, and attempted to be parsed back to the value, but this doesn’t trigger a recreation of the text string. If anything else makes a change to the numerical value directly, then and only then the string gets recreated. This gets instant feedback when editing things that are going to be graphically displayed, but never obliterates the user’s attempt to render text.
Some similar principles are going to need to be rolled out to order editing in time, though there are some other things that have to happen there. A matter for another time.
The player’s course is drawn with icons representing their maneuvers. However, feedback I’ve gotten on pictures and videos has strongly suggested these icons are easily missed, so I’ve tried redesigning those icons.
Here are the icons used for objects. The right is the generic dot used for everything, and on the left is the sprite for the player’s ship and maneuvers. The bar is to point in the direction of the object. Made perfect sense to me when I made it, but in hindsight I can see how it is not as readable as it could be. So I went back to the drawing board.
Here you see my three attempts to make something recognizably shippy and indicative of direction, while being easily spotted. Ultimately I went with the middle option, the halo makes it easy to find against the glow of the trajectory plots while the wedge still clearly enough indicates a direction. Currently the planets are still using the same fuzzy dot as before, but feedback on that might lead to some arrows being added to it, with care to make it as distinct from the ship as possible.
And speaking of glow, I’ve finally plugged in some bloom, which along with color setting has brought the game leaps closer to my mental image of it. I’ve made a before/after comparison, using a still from last month’s video.
There’s always room for tuning, but I definitely feel like this is in the right ballpark. And if you look closely, you can see that I’ve also added an acceleration cap to the levels at last!
That’s the highlights from this month. Going forward I think I’m on the cusp of reorganizing the GUI entirely, as the current one breaks a lot of my rules for a well laid out interface. You have to cross the whole screen far too often. I’ve got a better handle now on what needs to be on screen than I had at the start, so I think it’s a good time to finally do it.
As of Monday I now feel comfortable dropping the ‘prototype’ label from Atomic Space Race and moving it into ‘alpha’ status. Since the various development stages have fairly fuzzy meanings in the gaming world these days, I think I should outline what exactly I mean by them.
Prototype: A program that tests or demonstrates an isolated example case of the game concept. A complex game might have prototypes for different sections of it, and these prototypes may not run outside a development environment or otherwise be highly inaccessible, but they serve to determine if the idea has any chance of working or not before building all the more complex trappings of a game around them
Alpha: At this stage the project is playable as a game and gives a good indication of how the final game will play. There may be large gaps, and indeed every individual system may need significant work, but you should be able to test the entire flow of the game at this stage and have a viable experience despite the gaps.
Beta: All the gaps are filled in now. Improvements are still possible or needed throughout the game, and some chunks of content may still need finishing, but all the systems should be present and approaching complete. Testing at this stage can hopefully focus on finding out what parts of the game need more improvements than you thought.
The movement to alpha for ASR is marked by the advent of a main menu that stitches all the modes together so that you can move from level to level smoothly. It also comes with score saving and a handful of working levels. The editor, accessible through the same menu, can create fully working levels from scratch, though it’s a bit fragile. I’m starting to get copies of this version out to a select few testers already.
Of course it’s still alpha, so there’s a long way to go. The GUI is as rough and subject to redesign as ever, there are several known bugs, there are still missing systems. Most glaringly thrust and fuel aren’t capped inside levels, which is going to be a fundamental part of levels. That should be my focus in the near term, in additional to general bugfixing and strengthening of the code’s weakest points. Beyond that, a tutorial message system is on my mind, though building a specific tutorial might better wait for the interface to be more final.
For now, enjoy this playback of a solution for one of the new levels.
At the end of last month’s update I talked about being very close to being able to go from editor to gameplay smoothly. That’s working now, which has led to some fun iteration. Before I’d done months of testing and development on a single level, and now I can whip a new one up in minutes. There’s a lot of bumps and bugs in it that I still have to work out, though. Working so long with a hard-coded level in a fixed unity scene led to code that is not structured well for loading and especially reloading.
BETTER LINE SMOOTHING
One change a long time coming that happened this month is line drawing. Previously, an object’s trajectory was drawn by simply getting a start and end time(ideally equal to one orbit in the simplest cases), then picking N points of time evenly spaced through it and getting the object’s position at those times. The problem is that an object only spends equal times at different parts of an orbit if it’s orbit is perfectly circular, if it’s highly elliptical you could run into cases where one end becomes visibly jagged even with high numbers of overall points.
An example of the old system breaking down.
The new system starts out making a set of points the same way as before, then refines the line further. At each initial point it takes the object’s velocity at that moment and extrapolates out an amount of time matching the time of the next point in the set. If the extrapolated and actual points are far enough apart it asks the simulation for another point at the time-midpoint halfway between the existing ones. I tried a few other smoothing methods, but right now this seems like the most reliable way to handle the particularly curly paths that can arise if you’re looking at the system relative to a moon.
This month I did get to put the game in front of a couple friends and watched them come to grips with it. The state it’s in is rough enough that I wouldn’t want to throw it out to anyone that I can’t be there to guide, and that plus the fact that it was being tested by very good friends does mean that the opinions I got are far from perfectly objective, but I still learned a lot! I’ll list a few of the things I learned.
More parts of the racing interface are currently broken than I realized
People want the information those parts would provide without much prompting, so I really need to fix them!
The better line smoothing is still imperfect and needs more refinement.
If you don’t stop them, people will break the speed of light.
People really want to orbit the moon even if you don’t ask them to.
Orbiting the moon requires you to be a LOT closer than people expect.
It definitely gave me some useful information and ideas on what I should focus on next.
Something I’ve finally gotten around to testing this month is Lagrange points. If you’re unfamiliar, I’ll provide a quick overview of the idea. If you have one object of notable mass, like a planet, orbiting a larger object, like the sun, then in most cases a third object added to the system will not be able to keep a constant distance to both of them. It’s distance to either one or the other, if not both, will be constantly changing. However, at least if the orbit of the planet is relatively close to circular, there are five points where the forces can balance out such that an object can be placed there and keep a constant distance to both bodies. These are the Lagrange points. The first three are on a line with the two main objects, L1 between the two, L2 just outside the lesser object, and L3 on the far side of the larger object from the lesser. L4 and 5 sit on the same orbit as the lesser object, 60 degrees ahead and behind it.
Lagrange points are of some note because they’re commonly thought to be useful to a space-faring civilization, and they’re a feature that does not arise in some popular approximations such as the patched conics used by Kerbal Space Program. They should be something that naturally comes up in the simulation, and it hasn’t been urgent that I verify their presence, but with the editor working it’s become pretty trivial to check L3, 4, and 5, so I did.
In this example I made a Jupiter mass object at 1 AU in a circular orbit of a 1 solar mass object and then threw down a bunch of zero mass objects in the same orbit but offset a number of degrees, and named them according to the amount of offset. The A60 point thus corresponds with the L4 point and can be expected to be stable. The other objects don’t match any Lagrange points, so they shouldn’t be stable.
Then I wound the simulation forward 9 years. It might be a bit hard to see in the jumble, but relative to J the A60 is still in its place, while all the other ones have wandered around significantly. That’s what they’re supposed to do, so huge success!
Those are the high points for the last month. For the coming month, I need to focus on polish, and on organizing my internal documentation. The next post consequently might be a bit thin, but we’ll see! There tends to be more to talk about in these than I expect, so maybe I’ll be surprised.
I was feeling down on my most recent progress until I pulled back up News#5 realized just how much I’ve really done in the last month. Last time, I’d just got saving and loading working. A few things have happened since then.
I’ve gotten most of the way to making objects sharing a mutual center of mass, like binary stars or binary planets, work in the editor. There are a few hiccups in saving out final state vectors for simulation, but the path to solving them seems a clear one to me. I’m not going to go down it until some other things are cleared out, because binary systems aren’t a requirement to hit the next milestone I’m aiming for, but it’s definitely on the to do list later.
Here’s a snapshot of a binary system in the editor. It may not be immediately evident at a glance, but the central ‘Nirgal System’ marker does not represent a physical object, but rather the shared center of mass of the stars Anlil and Naanlil. A different icon for this kind of object might be a good idea. The outline of a dot perhaps, rather than a filled one? The main object dot is probably going to get replaced at some point too, so that can wait till then.
An interesting wrinkle that I didn’t realize would crop up before really getting into the math here is that if you’re designing a binary system, the mass and separation are interconnected such that you can only set one of them independently. What I mean by that is that you can have each star be of a specific mass, then set their total separation from each other, or you can set their individual orbital radii and set the total mass of the system. Then the editor will have to distribute appropriate portions of the set total value based on the independent values. At the moment I’ve only implemented one of these two options, the one with setting the masses of the objects independently.
Getting system loading by the simulation working led surprisingly easily into a very rewarding other feature, one button testing. The editor now has a button that will immediately fire off a simulation of the currently loaded system. Seen below, a quick snippet of simulation of the famous[link]Trappist-1 star system
I’ve not yet got it to where I can immediately jump into a test of race gameplay from the editor, but I’m closing in on that, and it’s my next major target.
The current thing on my plate is getting mission goals from the editor into the simulation. While working on that I decided it’d likely help people if the objectives were drawn visibly. Even with all my playing with my test scene I’ve never been entirely certain how close I need to get, I picked the distance for the objectives relatively at random and simply know from experience that it’s not that hard to hit, but neither is it that easy.
So I did that. Here’s an Io intercept, both from normal reference and from Io reference. No other objectives are completed, so you can see the difference in how they’re drawn.
In the future there may be a few different kinds of objectives. So far four major ones have come to mind.
Get within distance X at least once
Get beyond distance X at least once
Never get within distance X
Never get beyond distance X
Maybe there are more, but those are the obvious ones so far. None of them should be that hard to represent in code, either.
That’s most of the month’s progress. Maybe next time I’ll have hit that milestone of going from editor to full playable level. Getting very close!
Last month I said I’d be working towards having multiple levels. That’s led me down a bit of a rabbit hole. To have multiple levels I need a better level file format. That format is going to need to contain various kinds of objects, whereas the existing format only knows how to handle one type of thing. That leads to the fact that the level editor itself needs to be more flexible, and while I’m at it there’s real star system arrangements that the editor can’t support that I want it to. Also it’d make setting up systems based on real data much easier if I could enter in values like distance or mass in various units instead of a single option, so if I’m hacking on the editor I might as well try to do that at the same time.
Some might call this scope creep, and they might be right, but this is all stuff I need to do eventually and they go well together.
Working back up from the bottom of the rabbit hole to the top, the new editor has option selections for each appropriate line to let you choose what unit you want to view/edit them in.
The option list is flexible, I could add or remove some without much effort(though it’d cause some layout headaches, those are solvable). A few familiar units like miles or tonnes might be useful to put in.
I streamlined text entry while I was at it. In the old system you’d put in values, then have to hit a button before they were pushed into the actual data and you could see the results. Now they update as you type. There are surprisingly many moving parts involved in that! The old system does have some small benefits in being able to back out of bad ideas without commiting them, but I’ve some ideas on how I could potentially implement undo, and I think the faster feedback will be a worthwhile trade-off.
The other big change from the existing system editor interface is less visible, which is that the values to edit are not hard coded into the GUI, instead the object being edited tells the GUI manager what values it has to be edited and what kind of values they are, meaning that as I add new object types they can slot in there with minimal extra work and hopefully no special cases. This is a big win for me that’ll hopefully save some time going forward, and bits of it my be re-usable elsewhere.
Back up the rabbit hole another step is saving. Up until now all my saving and loading has been through creating or parsing comma separated value files, essentially a spreadsheet of values with a line for each object and an expected format. Strictly speaking I could extend this to plenty of new objects, but doing so is labor intensive and failure prone, and the resulting files are somewhat opaque when I’d like them to be at least theoretically hand editable. That brings me to serialization, which is pretty much the automated process for doing just that. C#, which is the language all this is being done in, has some standard serialization features. This is a thing I’d tried to make use of long ago, but I was too novice at certain aspects of programming to make it work. This time around it went relatively smoothly, I did have to more or less turn a portion of my data structure inside out to make it work, but that only took about an hour and seems like it’ll have some good side effects down the road. I can now save and load the editor files to an XML format with minimal amounts of special work to prepare for saving or cleanup after loading. Similar to the GUI stuff this happens without me needing to specifically write (much) code to handle new objects types, which will save time in the future. XML is less than ideal for my goals of human readability/editing, so I may look into alternate options, but it does do the job.
I’m still a few steps away from having a full featured level editor. Most pressingly the new logic can not yet convert from the simplified orbital representation in the editor to the actual raw positions and velocities needed for the levels. That shouldn’t be too hard to cannibalize from the old logic, but it hasn’t been done yet. Editing mission objectives promises to be a bit tricky, and definitely needed. Editing mission meta-data(name, description, and so forth) is similarly needed but probably easier. Also on the immediate to do list is support for binary stars or planets, which now that I’ve done everything else I’ve talked about here should be pretty simple. There are a few other loose ends in the editor GUI, and if I’m really smart I’ll build an automated way to convert the old CSV levels I’ve made to the new format.
That’s all for this month! Plenty of words this time, next time I’ll strive to have more pretty pictures too.