26 September 2020

ShipBasher Development Log 10: PewPewPEWpewPewPEWpewPEWpewPewPewPEWpewPEWpewPew

Something I hope will be a draw for ShipBasher is the ability to marshal completely impractical ships that fire entirely unreasonable amounts of ammunition at each other, as I mentioned briefly in the last post.

In pursuit of this idea, I dusted off the GPU bullet system I had prototyped a while back and integrated it into the game over the course of one very late night. In so doing, I discovered that I'd more or less made my computer work with proverbially one hand tied behind its back.

See, like some kind of pro l33t h4x0r code sorcerer, I decided to use a compute shader for processing bullets. A persistent buffer of bullets is formed on the GPU, so that unlike in a normal shader, the results of computations made in one frame can carry over to the next frame - an essential feature when trying to use a GPU to simulate things moving over time.

But like a dumb idiot n00b, I was taking the buffer back from the GPU and sending it off to be made into a mesh object, making a redundant copy of it along the way, and then when it was time to render the frame having the mesh object get sent over to the GPU so that the poor thing could hold it in memory alongside the persistent buffer, essentially causing both my computations and memory usage to be doubled for no reason and, perhaps even worse, bottlenecking my performance by schlepping data back and forth every single frame. Basically the only useful thing the GPU cores were doing was moving each bullet forward a bit, which is such a trivial operation that I probably would get more performance out of skipping the compute shader business altogether and just calculating everything with the CPU like a normal person.

Of course once I noticed and apprehended the scale of this problem, I had to fix it immediately. I tinkered and fussed with my code until I had eliminated all the redundant data processing and made everything way more efficient. Unfortunately it didn't change much as far as the frame rate went, because it turns out that with my setup and its relatively weak GPU, my performance was limited by rendering speed anyway. Nevertheless it sure felt good to know my code was way less stupid than before.

I also made some tweaks to my weapons firing code so that turrets with extremely fast firing rates could fire multiple rounds per frame rather than being limited to one per frame as they had been before, and behold!

Yes I think I know what you're thinking.

 

In practice I doubt I'll include single turrets able to expend ammunition quite this fast (the last one is 20,000 rounds per second or 1.2 million rounds per minute) in the finished product, but the ability for many bullets to be released every frame by all the various turrets that I expect to be active at once is important.

Something else I hope gets noticed here is a big improvement I made to how the bullets get rendered. Now they stretch out along their velocity vectors, much like Unity's built-in Line Renderer, but unlike the built-in Line Renderer, they smoothly transition to point sprites if they are very far from the camera or are viewed from a very shallow angle to this vector, causing them to maintain a round, 3D appearance rather than give away their true nature as flat rectangles. It's not perfectly polished just yet, but I'm pretty proud of what I accomplished with it and think it makes for some nice screenshots (as you may have guessed).

The next problem to tackle is making these bullets actually do something. While it's amusing to watch fountains of bullets pour forth from my gun barrel, they simply float through space until their numbers come up in the pooling system and they start the cycle over again, never having any effect on the world, much like the test bullets not too long ago. This is a harder fish to fry, though: Unity's physics engine, PhysX, and all of the alternate physics engines available, do their processing using the CPU, using data sitting in RAM for all of the collidable objects and their locations - but this new bullet system operates on the GPU, which has its own memory that's separate from the RAM and is alien to the physics engine. I could write a whole collision detection algorithm in a compute shader, or I can find some inexpensive way to roughly predict collisions in there, hopefully for only a relatively small subset of bullets, and then extract some data about those back into the regular RAM so I can use it to tell the physics engine what's going on. It's just as complicated as it sounds, and thus the subject of at least one future blog post.

20 September 2020

ShipBasher Development Log 9: Damage Works Now Except It Doesn't But Now It Does Except It Doesn't But Now It Does

Two Three days after my previous post, I hit a milestone! It became possible to build the game, set it up elsewhere (a different folder or a different PC), and complete a "full" play cycle of loading ships; editing ships; saving ships; and pitting ships in battle with movement, weapons fire, module damage, explosions, and module and ship destruction!

Modules that become detached when their parent modules are destroyed now assign themselves to new debris "ships" (at least when everything works... as with every other part of the game, bugs have been occurring) so that they can properly participate in the physics simulation and in the battle, although in most cases, lacking any AI, they merely drift until something shoots and destroys them.

With all this accomplished, I was about to compile another build when I noticed something wrong with my test bullets: despite my claims that they did damage, they didn't! Lasers had been working fine the whole time, and still do last I checked, but the bullets kept crashing against modules without affecting their HP. I found that I had misinterpreted how Unity handles collision callbacks and was having the bullets shout information about their damage into empty space.
So I fixed it and made bullets do damage again, except they still didn't, and those lasers that were working fine didn't either. Problem with the new code? Nope.
See, my laser code roughly took the DPS, divided it by the frame rate, rounded that number to the nearest integer, and applied that much damage every frame. So my laser with supposedly 1 DPS did, each frame, a damage of 1 divided by somewhere between 20 and 60 (so something like 0.02), rounded to the nearest integer, which was basically always zero. Somehow it had seemed like it was working before, as with all the modules having only 1 HP, occasionally I guess there was a hiccup long enough for the damage to round up to 1 and destroy them - but once I started writing in reasonable HP values like 100, the lasers stopped working so well. Luckily that was a simple fix of setting the DPS to 100 instead. Yes, I have decided that the above failure mode is an acceptable consequence of my code working as designed and that I (and players) will simply have to set comfortably high damage values for lasers. I consider it a small price to pay for avoiding the Kraken by minimizing floating point operations.

The next addition was the beginnings of a system for relative file paths so that the game needn't exist in the exact directory I specify prior to building it. It's going to need improvement later as it was a quick fix not designed for much expandability, but for the moment it's sufficient for allowing me to share builds for eventual beta (alpha?) testing. Of course this doesn't have much of any visual consequences.

What did have visual (and other) consequences was when I decided to no longer have my Editable Data System be responsible for converting editable data between linked lists and arrays based on whether the game is in an editing or play situation. Rather it would always stick with linked lists for ease of editing, and other systems interacting with it would instead be responsible for gathering up whatever data they would need to access rapidly or frequently and then submitting it when done. This, as I feared, messed up a lot of other things, as it turned out that despite my imagined efforts at maintaining encapsulation, the system had still ended up coupled to a bunch of other things in the project. It took most of the day to undo the damage and I kept kicking myself for not backing up the project just before doing this (I have several backups going up to a mere few days earlier, but even more recent would have been safer). Fortunately, eventually it worked despite the very un-helpful debug messages I had made it give me:

Those time stamps aren't even part of the messages - they're an optional feature of Unity's debug console. I had literally built a system to spam the log with empty messages. Hooray!

With that nerve-wracking process out of the way, I was about to recompile the game again when I noticed something wrong with my test bullets... uh, again. It turned out I had misinterpreted how Unity handles collision callbacks, again, and was having the bullets shout information about their damage to objects entirely unequipped to handle what was going on. Hey, at least it was better than empty space this time.

So I fixed that and damage was (supposedly) working again, except that lasers were still way more useful than bullets due to one simple thing: my ships' turrets have terrible aim. They are able to precisely point themselves at their targets and fire with no problem at all, but things move in this game, so by the time the bullets get there, often the target has moved far enough that they miss. Thus I decided that my next order of business was to start incorporating the awesome target tracking system I had rigged up a while back in my test project:

I was actually quite proud of myself when I made this. The turret in the foreground accounts for the velocity of the sphere in the background and fires at a point ahead of it, calculated just right so that the bullets hit it when it gets there. It also makes use of another cool (if I may say so myself) system I had made even earlier, which was a GPU-based point cloud sort of thing that can render absolutely obscene numbers of bullets (or star sprites, as in the background of this blog at the time of posting this entry):

The second image had its colors adjusted to make it easier to see just how many were being displayed - every single one of those little dots in the distance is a bullet the turret has fired, and the engine is chugging along happily at a very high frame rate. This thing can actually handle a larger number of bullets than Unity can handle of mesh vertices (more than 65535) and will thus be a serious boon in a game where I imagine people will be having ships spew entirely unreasonable quantities of ammunition at each other.

Of course, this system was not compatible with the turret system I was using for my weapons right out of the box. I was going to have to move away from the existing (temporary) strategy of having the turrets aim themselves and toward an architecture wherein weapons intelligently aim their turrets based on what the player is trying to accomplish - basically a system for letting the player issue orders to the ship regarding where to fire, so I figured I may as well get started on that. Thus I began building a UI for selecting ships in play mode, selecting targets for them, and ordering them to fire on those targets. Putting the buttons there was simple, but then I had to add functionality, meaning I had to draft a new ship control script and upgrade the way weapons function so that they can match their targets to what their parent ship has targeted (I do still want them to be able to pick their own targets in certain situations).

While testing that out, I came to realize that it would help to have a target practice dummy in the form of a durable ship with lots of inertia. So I built one and then edited its file manually to give its modules especially high masses and unreasonably durable armor. I loaded it up in the game, and then I noticed something wrong with my test bullets. This time they were doing way too much damage because the armor wasn't doing its job! Time to debug some more...

I had mixed myself up on what the design was for my own game. See, I had made it so that damage could come in one of eight types and that armor would resist each of those types differently (except for the first type, which is "magic" and bypasses armor - it's intended for testing (and has served me well thus far in that area) and cases where I would want a special overpowered weapon such as in boss fights). Armor shrinks the incoming damage toward zero based on how close its resistance to that type is to one - so yes, a resistance of one would make a module invulnerable against a given damage type, but I intend to disallow players from giving modules that high a resistance without enabling cheats.

Except I momentarily deluded myself into thinking it was the armor value itself that would shrink the incoming damage like this, not the resistances, so when I gave the test dummy's modules an armor value of 0.99999, expecting them to be nigh invincible, and they were instead popping within a few seconds, I got really confused. As seen above, my efforts to figure this all out involved a lot of calls to Debug.DrawLine and Debug.DrawRay and temporarily having my modules spam the console with messages about what sorts of damage they were receiving. Sadly I didn't think to show it here, but I took some time a few days ago to rig up an editor window for my Editable Data System that shows all of the editable values attached to a given object, and it proved very helpful here in reassuring me that at least the editable data was being handled properly.

Hopefully all this rambling didn't seem too pointless or boring. In short, it's the tale of my increasingly complex game having many possible points of failure and the confusion and frustration (and eventual joy) I experienced in tracking down, analyzing, and rectifying these failures. There are probably a lot of possible lessons to glean from all this, but I suppose one of them is that if you keep up your efforts, building systems for anything from cool visual effects to debugging assistants, chances are it'll pay off later when they all come together. I look forward to showing off more of the player ship control UI and my upgraded weapon system in the next installment.

10 September 2020

ShipBasher Development Log 8: Vision

I figure it's about time I shared a detailed description of exactly what game I'm trying to make here. In short, ShipBasher is a real-time 3D sandbox, simulation, and strategy game about building custom spacecraft out of premade pieces (known as kitbashing, hence the name) and pitting them in battle against one another. I'll expound on each of these facets here in their own sections.

Main Menu 

The intended gameplay experience starts, as most games do, with the main menu. Originally this was a generic list of buttons to enter different environments in the game (i.e. settings page, credits, campaign mode, ship editor) but then I decided to take a bit of inspiration from Spore and have a big 3D galaxy occupying most of the screen, as I have mocked up here:

This is itself a menu in that each little circle represents a playable level. Part of each level's data file will be a position in the galaxy at which it appears. As I intend to allow players to create their own levels and place no limits on how many a player can have, it will be possible to fly the camera through this galaxy to explore different areas of it up close.

By selecting any of these circles, the player can open a preview of the level, which takes the form of a "wormhole" showing the level's background features and a window detailing properties such as the level's name and description.

Playing a Level 

Once a level is selected, or a fresh new one is created using the buttons on the side, it can then be played or edited. There will be separate UIs for playing a level and for editing it. This is a mockup of the play mode UI:

While playing a level, the player can select one or more ships to control. I plan to make it possible to restrict which ships are available for a player to control and which are "enemy" or "NPC" ships. For now clicking any module on a ship will select that module and the ship to which it is attached, and as seen here that module will be highlighted and the ship will have a ring drawn around it.

While a ship is being controlled, a menu will be visible (in this mockup it is at lower right) for issuing commands that affect that ship, such as initiating self destruct. Right-clicking a module on any other ship will open a menu (seen at upper left) for interactions between the selected ship and that other ship, such as attacking it.
The camera can be focused on any ship and rotated around it, but to keep track of objects not in the current field of view, there is a radar display at lower left with a slider to adjust its range.
Each ship may have a small readout next to it showing its current status.

Finally, a few large objects are visible in the background. The distant star and planet are visual effects only and won't affect gameplay, but the asteroid on the right is a physical obstacle players will need to accommodate. I may add levels in which asteroids need to be destroyed, or in which special environmental hazards from distant objects affect ships in the level - for example a pulsar that would damage ships with its radiation. These concepts have yet to be figured out in much detail for now.

Planned but not shown are options for pausing the level or returning to the main menu.

Editing a Level 

Instead of playing a level, the player can open a level for editing, or, in certain circumstances, the player can pause a level in progress and edit it. Editing a level involves a different UI:

As in play mode, any ship and any module can be selected. Different windows exist for editing these or for editing the level itself.

At lower left is a window for editing the properties of the level, such as its name, description, and location in the galaxy. Changing the level's location in the galaxy will alter the appearance of the background starfield, so that a level near the galactic core, for example, will be surrounded with a dense field of yellowish stars. Additional information may be shown such as how many total ships exist and a difficulty rating, which will likely be left to the players to determine but might be possible to calculate.
At upper left are buttons for adding objects to the level, e.g. ships, distant background objects such as stars or planets, or physical hazards such as asteroids. Clicking the button to add a ship will reveal options to either create a new ship (not shown in this image) or open a saved ship from a file and spawn it in front of the camera.
Once a ship exists in the level, it can be moved and rotated, and a window becomes visible for editing properties such as its name and description (seen here at lower center). Additional information such as its total mass and firepower is also intended to appear here. At the top of the ship editing window are buttons for tasks such as copying or removing a ship or for saving it to a file.

Any ship will need at least one module attached for it to function. Visible at lower right is a menu for adding modules to ships. When the player hovers over a module in this menu, a preview window appears, allowing the player to examine the properties of the module before loading it. Once a module has been attached, it can be moved and rotated using transform handles, as shown surrounding the module in space, and a window appears, shown here in the upper right, allowing properties such as its name and description to be edited. I may make it possible to restrict editing of certain properties in certain contexts, for example allowing the armor and damage power of a weapon to be changed but not the price (rather the price would be calculated based on how powerful the module is made via other edits). At the top of the module editing window is a set of buttons for tasks such as copying or removing modules or saving a customized module to a file.
At this time it is not planned to allow the scale of modules to be altered or for any custom 3D modeling or texturing to occur in the game.

Finally, at upper right are buttons for saving the current level, playing it, or returning to the main menu.

Other Features 

As seen here, ShipBasher uses a 3D environment with a third-person camera. Every object in the game is able to move in three dimensions, not restricted to a ground plane, grid, or global axes. The camera can be rotated omnidirectionally so that there is no universal "up" or "down" direction, as is the case in outer space in real life.

ShipBasher simulates in real-time, i.e. gameplay is not based on turns. It will be possible to pause the game, but time dilation, either to slow it down or speed it up, is not planned.

Being a sandbox and simulation game, ShipBasher has no central storyline, goals, or sequence of levels through which the player must progress. I intend to include a number of example ships and levels, and I may decide later to make it possible to restrict some levels until after other levels have been completed, but this is not planned at the moment.

A strategy element arises in how players will go about clearing each level that exists - which ships to include (if the option is available), what orders to give them, etc.

Players will be able, as described above, to create their own ships and levels, save these in files, and share them with other players. I have no plans to make this a multiplayer game, include any online functionality, or set up any hosting servers, so it will be up to individual players to send files to each other and import them into their own games.

Hopefully this clears up any mysteries surrounding what my goals for this game are. I'll be glad to address any questions I haven't answered so far.

ShipBasher Development Log 7: Moving

Updates have been scarce lately! The latest excuse I have is that I spent the last month preparing to move, moving, and then entertaining family members who came to visit. I have a lot of junk, so it took an embarrassing number of trips back and forth to load up a pair of storage units (the small ones were on sale so I saved money eschewing a single large unit) and then unload them.

On topic, I finally got back to work again and have spent most of my time focusing on adding gameplay functionality. The saving and loading system still has a few issues, but I can work around them easily enough that working on the ability to have ships, well, bash each other is feasible once again. As I mentioned in the last entry, long ago I had all this working on its own, but making ships load from files intact and then work is another layer of complexity. I started by tackling the task of making them able to move once again, which of course began with slapping on some engines:


Here we can see the return of the nice pretty modules I modeled way back when (still devoid of proper UV maps) and, more spectacularly, some big changes to the UI. I showed them a little in the previous post but didn't say anything about the topic, which in retrospect I really should have. ShipBasher has had a shift in intended user experience: rather than a separate ship editor and play mode (and possible level editor), I decided to roll them all up into one single "sandbox." The idea is that the player can open the sandbox with a fresh, empty volume of space, construct multiple ships in it, position them, and have the option to save individual ships or the entire level. At any time it will be possible to switch into "play mode" and let the ships fight, controlling one or more as desired, and to pause the simulation to re-enter editing mode. Saved levels could be shared with other players as challenges, in which editing may be restricted or unavailable. In light of these changes, the UI here features a number of windows for editing ships and their modules. I probably will make an entire post about the UI later.

Reintegrating all of these modules into the game meant extending my editable data system to work with custom-built module models and their corresponding behaviors. I decided to make use of Unity's Asset Bundle system, which provides the ability to package up arbitrary assets separately from the game's compiled data and load them during play. I engineered a system to open these asset bundle files, search them for module prefabs and text files dictating their properties, and pass them on to the editable data system so that they could be configured. After much work, I had that modules menu in the lower right working so that it was possible to spawn specific modules and attach them to the ship.

Once that was out of the way, I could get to doing the thing I mentioned back at the beginning of this post - making the modules I had spawned work. This was mostly a matter of trial and error in the form of putting things together similarly to how they were before and then figuring out which steps I had missed. Eventually I had exhaust coming out and the ships awkwardly pushing themselves around:

And once that was done, and I had debugged some issues with the ships completely failing to move in productive ways in favor of impotently drifting and spinning, I slapped together a simple gun turret and, once it was (guess what) debugged, could finally watch with joy as they flung white beads at each other:

Hooray! At last ShipBasher is fully operatio- except no, not only is this not even close but these "bullets" have no ability to do any damage nor even collide with other ships. They just drift through like ghosts until they despawn. But hey, it at least looks like a space battle is going on now, which I consider a milestone. Also visible at the top are "play" and "pause" buttons I threw in. They work in a superficial manner now, but properly suspending the operation of all the different gameplay systems I've made and properly resuming them is a much more complicated matter.

The last and most recent feature I've begun to address is restoring weapon damage, which due to the plans I have for later on I figured would be easier to implement with lasers than bullets. Thus I set about making a laser turret as well. I had already created most of the subsystems this includes, such as the turret and "line beam" components I made available a while back on the Unity Asset Store, so this turned out not to be too difficult, though I did encounter one amusing issue I'm anxious to address:

See the detached modules hovering in the center of the image? It turned out that by allowing my laser beam to damage the other ship's modules, I made it possible to destroy those modules, as the ability of modules to despawn when too damaged was already present, merely unused. This led to a problem because what I hadn't yet done was program what should happen when modules leave their assigned ship, so I started getting scolded in the debug console about ships having zero mass (due to having no modules attached) and modules being unable to figure out which ship was theirs because, due to their parent modules having been destroyed, they were no longer attached to any ship! More amusingly, because I designed ships to use a single Rigidbody component rather than assigning one to every module, these detached modules had none and thus immediately stopped still where they were and became immovable. I think I know what I need to address next.

So yeah, that's the story of me moving in real life and also making spaceships move in my video game.

Typing this up, it became clear to me that I really need to blog about what I'm doing more frequently. I tried dialing it back after like ten posts about the editable data system, but clearly I went too far and have thus had to do a lot of hurried review. I haven't even covered everything I've accomplished since the last entry and will have to make another one to avoid turning this one into a monstrosity.

26 May 2020

ShipBasher Development Log 6: "Fully Operational" is a Meaningless Political Buzz Phrase Apparently

Also despite evidence to the contrary I'm not dead and ShipBasher isn't vaporware just yet. During the three months since my last post, I've been engaged in such activities as acquiring three new jobs, which took up all of my time and left none for development; losing all three jobs due to current events; helping my family move; and fighting an unlawful eviction attempt.

Now I'm finally back to work and it's been long enough, and my codebase is now complex enough, that I've managed to forget how some parts of it work, so progress is off to a slow start. What's more, once again all of my new work has been technical backend stuff like optimizations and bug fixes, so there are once again no pretty pictures to show for it.

 Wow. look at that complete lack of pretty pictures. Wait I'm not a liar! It's just, uh, not pretty.

This (dubiously pretty) picture showcases one of the test ships I threw together to stress-test the ship editor. I had thought before that the system was working perfectly, but then strange things started to happen whenever I loaded a ship with more than a few modules. It turned out that the messaging system I had been using to assemble the ship after reading its corresponding file was behaving unpredictably, causing modules to perform loading operations such as attaching themselves to their designated parents and positioning themselves in varying orders, leading to the ship becoming misshapen. Thus I had to reorganize the loading system so as to put a tighter proverbial leash on the modules, performing each type of operation on all modules before proceeding to the next. In so doing I discovered that the parenting operation, being originally written with the intent that it be used for one module at a time (i.e. the player changes the parent for a single module), was performing a search through all of the modules every time it was called - woefully inefficient when it came to assigning parents for all of the modules at once! The end result was that the test ship shown here (my largest, with 7501 modules total) took - get this - fourteen minutes and eighteen seconds to load completely! Thus I had to write a batch version of this part and, along with a few improvements in other areas, I am now pleased to report that this brought the loading time down to a much more reasonable fourteen seconds. Sure that's still a big delay and instant gratification is preferable, but I think I'm okay with players having to wait fourteen seconds to load a ship with several thousand modules (here's to you, Whackjob and Stratzenblitz75 of the Kerbal Space Program community).

So now that that annoying bit of non-determinism is cleaned up alongside the speed improvements, the ship editor, or at least its ability to save and load ships, is fully operational and reliable, right? At this point I'm no longer interested in making any such proclamation, mostly in light of how I've done that and been wrong at least once before. A small further hint is that a ship, once loaded... doesn't work as a ship. Sure it's editable and looks right, and when saved and loaded again will retain these properties, but I still haven't quite gained a grasp on the functionality I had hand-built in the first "demo fight" build:

It's nothing spectacular. I may even have mentioned it before. In any case, the demo fight pits a single player ship against a single enemy ship in a cloud of small asteroids. Each ship contains one or more functioning engines that properly consume fuel to provide thrust, fuel tanks that supply fuel to the engines, and weapon turrets that can automatically target and fire upon the opposing ship's modules. The player ship is controlled using the mouse and the buttons at top right, and the enemy ship has a simple AI script that chooses destination points based on the player ship's position and directs its engines to bring it to those points.

None of these features are functioning in ships that I load from files, though. I have a number of leads on possible reasons (mistakes in how the modules are configured, oversights during the loading process, etc.) but it remains a nut I have yet to crack and a likely subject of the next development log.

In summary, ShipBasher's development continues as the fully operational ship editor turned out to not be fully operational before, but is fully operational now, except that it still doesn't completely work.

14 February 2020

ShipBasher Development Log 5: Boring Walls of Text

I don't really have any eye candy to show for it this time, but I've met another (relatively minor but still significant) milestone and figured it was time for an update. I have to substantiate claims I'm still working on it, after all xP
Before I stopped to work on Hat Simulator, ShipBasher had just managed to reach a point of functionality at which it was possible for a user to build a ship from scratch, save it into a file, and then load the ship from that file for editing. It wasn't (and isn't) yet possible to load a ship into a controllable state for gameplay, but the editor could make a complete edit-save-load "round trip."
There were issues, however. I was starting to run into a bloating problem with my UI fields having to interact with the module selection script and the modules themselves in order to fill themselves with data from the selected module, to update said module if the data in the field changed (so if a user changed the value for the modules X position, the module should actually end up at that position on the X axis), to save that value somehow (in case it's some invisible property such as the module's HP or description), and to do these tasks in the right format - integers for HP, 3D vectors for positions, text strings for names, etc. As I mentioned in the Hat Simulator devlog, it became clear that I needed an entirely different back end system for all of this stuff.
I devoted two devlogs' worth of development time to designing and constructing this new system, and was so proud of myself that I packaged it up and got ready to sell it on the Asset Store. It ended up being rejected due to some technicalities, and OH BOY did that turn out to be for the best! It worked very well for the very simple environment in which I had been testing it, but a number of bugs and missing features became clear once I tried integrating it into ShipBasher in place of the old system. In fact there was even an awkward period in which the loading part was working mostly properly, but the saving part was so far from operational that the old saving system worked better and so I was (temporarily) using that instead!
Now, however, I am pleased to report that, as far as my tests have been able to indicate, everything is fully functional once again. It's far from ready to share with the public for a number of reasons (notably that there's a high chance that saving and loading is only possible if the user's computer has an R:\ drive!), but it's finished enough that I feel safe proceeding to add new features and to work on other components of the game (such as maybe actually being able to play it). Hooray!
I do still hope to make the Editable Data System available for purchase sooner or later, now that it's been given some much-needed upgrades and it's more clear to me where the documentation needs to be augmented. Feel free to ask questions about it, even to request features you would like to see in such a system. In the meantime, stay tuned for some hopefully exciting and more visually pleasing updates!
Okay I had to include at least one picture, so here are some spaceship concepts I drew hastily.

Oh, P.S. since this is the first post here since these happened: ShipBasher now has pages on itch.io and on Patreon, and I post about it sometimes on Twitter. You know the drill: follow those for updates there. I don't have any tiered rewards set up, but I'm mulling over some ideas and in the meantime suggestions are welcome.

24 January 2020

ShipBasher Development Log 4: The Symmetrizer

Long ago I remember catching an episode of a children's cartoon, whose name I didn't remember but I was able to rediscover was "Cyberchase," in which a group of children had to stop a villain wielding a device that could give and take away symmetry, either making asymmetrical objects symmetrical or vice versa. Why is this relevant? Because I have objects I need made symmetrical, and I imagine soon you will too!
(Thanks to space.com artist Adrian Mann for the image.)
Look at all that symmetry! There appears to be four-fold symmetry in the thrust plate pylons, six-fold symmetry in the darker tanks, perhaps eight-fold (it's hard to tell for sure) symmetry in the lighter tanks, and two-fold symmetry in the front section.
Now if I were constructing a replica of this thing in ShipBasher, currently I would have to add all of those duplicated pieces individually, which is very tedious and maximizes opportunity for errors (anything from a few being slightly out of alignment to accidentally parenting them each to the next one instead of the core, making a big floppy chain). Naturally ShipBasher needs a way to automate this process.
As with many editor features, I looked to my perennial favorites Kerbal Space Program and Space Engine for reference.
Space Engine's ship editor handles symmetry in a relatively basic fashion: modules are duplicated around the ship's central axis, and edits are made in a similarly duplicated fashion. For example you could activate 6-fold symmetry and add a group of fuel tanks, then switch to two-fold symmetry and delete two of them, leaving a group of four. This is surprisingly effective despite its simplicity:
Its limitations make themselves obvious very quickly, however. For example, there isn't a way to create proper four-fold symmetry (or any degree aside from the four options specified in the menu: none, two, three, and six), and the system has no ability to apply to symmetry around something other than the ship's central axis - for example, a cluster of engines attached to a nacelle. Kerbal Space Program manages to handle this much better:
To be fully honest, this is a screenshot of me adding a symmetrical component onto a ship manually by docking it in orbit - but you can do this in the craft editor too, and it symmetrically duplicates groups of objects that themselves contain symmetrical duplicates very reliably. How do they do it?
Well I could decompile Kerbal Space Program and browse the codebase myself, or I could dig around to see if anyone else has done this or if any documentation ever got made on how it's implemented, but so far I haven't and instead have been exploring various strategies independently. I want to deeply understand what the nature of a symmetry system is and why it would need to be built one way or another, so that as I build mine I can make the best decisions possible for my needs. I started by writing up some pseudocode that I thought was fairly sound and rigging it up in Unity:
I wanted to see if I could support getting "as close as possible" to perfect symmetry and thereby allow a bit more creative freedom. I'd previously noticed that Kerbal Space Program had a bit of trouble when one attempted to add modules in one symmetry mode as children of modules in a different symmetry mode and wanted to know if I could build a system to be immune to that issue. At this point it seemed to be going very well - here I have a group of five "thrusters" (small cylinders) attached as best as will fit to a group of eleven "fuel tanks" (medium cylinders) arranged symmetrically around the core (large cylinder). The sliders adjust the numbers of fuel tanks and thrusters respectively, and the algorithm is able to space everything out as evenly as it can be spaced while maintaining alignment between parents and children. Children even get assigned to the most suitable parents out of those available so as to optimize symmetry. I was rather proud of myself.
...But what of those clusters and nacelles I mentioned earlier that Space Engine couldn't handle? So far I hadn't escaped Space Engine's limitation of only allowing symmetry around the central axis. Cue my next thought experiment:
I'm not completely clueless about how Kerbal Space Program handles symmetry. I've read through the ship files (which, happily, are human-readable text) and found that modules ("parts," in this case) contain references to other modules with which they form a symmetrical group. A drawback of this is redundant data: all parts comprising a ship are saved in the file completely, and every one contains a reference to all of the others. Not only is the file much larger and more repetitive because of this, but opportunity for error is maximized. A user modifying this file directly (perhaps trying to fix a notorious docking port bug) might mess up a reference somewhere and, well, summon the Kraken.
I'm thus exploring an alternate strategy for now, as illustrated above, which I'm dubbing "symmetry groups." Modules themselves won't contain any information about their partners in crime symmetry; rather, ships in files will now contain two types of data block, module entries and symmetry group entries. As of the creation of the above image, the plan was for symmetry groups to have two properties: Degree and Members. The degree would be an integer representing how many members would attach to each individual parent module, and the members would be an array of indices pointing to the modules in question. The number of indices listed as members would determine the overall degree of symmetry. Note how, in the first and third examples from top left, the only difference is the number of members in the array. All members would be distributed among the parent modules as evenly as possible while still obeying the degree value: a degree of 0 means to behave as in the previous image, simply spacing modules out radially; a degree of two or more means to space out groups of that number of module, even if the members array runs out after only filling one parent module; a degree of one is understood to mean two-fold symmetry, but bilaterally instead of radially. I imagine this is a bit hard to digest typed out, which is why I made the image to begin with. Hopefully it helps all of this logic make sense.
Unfortunately even this has limitations I'd rather not have in my (or my eventual users') way. As the considerations get more outlandish, they get exponentially harder to explain, but suffice it to say that this system still breaks down if modules need to have symmetry around something other than their immediate parent or grandparent. What if I want a group of nacelles, each of which has a group of thrusters, some of which have radiating fins and some of which don't, but in a symmetrical fashion? It seems like an obscure edge case, and granted, I expect the vast majority of times the symmetry system will be invoked will be for much simpler tasks, but it didn't seem quite obscure enough to ignore. I could quite easily imagine a ship with this kind of structure and thus imagine a player attempting to build one. If that happens and the symmetry system can't take it, it means a lot of tedium and a high risk of frustration and disappointment.
(Actually it just occurred to me that this is pretty close to a description of the Falcon Heavy. I wouldn't want to prevent players from replicating that!)
I'm slowly incrementing the power of my designs, but it remains uncertain whether I'll achieve a "perfect" system or have to stop at some "good enough" point, and if so where that ends up being.

17 January 2020

ShipBasher Development Log 3B: Hat Simulator Development Log 2

Earlier I waxed pedantic about a barebones character creator I'd ended up building as a sandbox for developing the editable data system for use in ShipBasher (and, the way it's working out so far, several other projects with any luck). This is a small update on the work I've done over the last few days.
https://imgur.com/EQpXZKc
Here's how it looks at present.
I'm pleased to report that, at least as far as I've verified in my own testing, the system is now capable of completing a full edit-save-load cycle. What that means is the following:

At lower left is a large text box. This acts as a surrogate for a text file (the system can handle text files or in-game text boxes interchangeably) and contains serialized data that can be typed in directly by the user or generated based on a selected object.

When a character or a hat is selected, as I detailed before, the UI fields set it as their target, depending on whether it is the right type of object: hat fields only target hats, etc. When these are changed and then either the selection is changed or the "Serialize and Display" button is pressed, their modified information is stored in an "Editable" component on the target object.

When "Serialize and Display" is pressed, once all the information is gathered in the selected object's Editable component, the component itself is serialized, with each field being converted into a string. "Normally" this constitutes a key-value pair; each Editable in the scene references a "Field Definitions" object (something new I have developed since last time) that contains a list of all of the keys and the rules for how that Editable should be serialized. A flag can be set so that instead of forming a key-value pair, the first field can simply be the value, in this case the character's name; if so, that value will override the usual behavior and be saved even if it is unchanged from the default value. This mostly helps with human readability.
If the object being saved has any children which are also Editables, they are serialized and added to the saved text. Field Definitions objects also specify which characters to use as brackets to begin and end the data block for each Editable, in this case square brackets, between which all of the hat information is saved. Note that the Field Definitions information for hats does not make use of the required first field feature; in this setup, hats do not have names, even though they can have descriptions.
When the serialized text is complete, the selected character can still be edited as normal, along with all of the other objects. Changes made in the UI will be applied to whatever is selected, independently of the contents of the text box.

When the "Load" button is pressed, however, whatever is selected will have its data superseded by whatever is specified in the text box. Any existing hat will be removed; if a hat is described in the text, a new hat will be spawned and given the appropriate properties. Behold:
Here I have selected the green character, and pressing "Load" has caused it to take on all of the serialized values, i.e. the name and the presence of a hat with "Regular Hat" as its description.

This was all very verbose, but in short this system behaves as one would expect. In short the user can edit stuff, save it as text, maybe edit the text, and then load the text and have it turn back into useful stuff. That complete cycle is what I consider the primary milestone indicating that my editable data system is actually complete and ready to be put to work for real. With any luck I can use it in ShipBasher without it needing any further modifications.
AND LOOK HERE YOU CAN PLAY WITH IT YOURSELF WOOHOO

09 January 2020

ShipBasher Development Log 2B: Dat Booty, er I mean Parsing Text, yes. No silly referential jokes here.

In Part 2 I rambled about this "lexer" thing I had contrived for reading ship files. It is able to read characters from a file, assemble them into "tokens," and pass these tokens, along with some state flags, to a second system called a "parser," which is the main topic for today.
Last time I talked a bit about finite state machines, and the parser is itself a finite state machine that reuses some of the same state flags from the lexer while adding a few variables of its own. Its routine roughly goes like this:
  • The current token should come with a boolean flag indicating whether it is a key rather than a value. If it is a key, store it as the "currentKey" and set the "currentValueIndex" to 0.
  • If the given token is not a key, it is presumably a value corresponding to the current key. This forms a key-value pair that applies to one of three known things: a module, a ship (or ship-like object such as a station or asteroid), or a level. State flags shared with the lexer will indicate which of these is the subject in question.
  • If a module is being loaded: spawn a fresh module if needed, based on the current key, which should be a name for the new module and thus indicate which module template to use; once a module exists, use the current key to determine which value to edit and then set that value on the module, for example its position in the ship. At the moment, all possible keys are hard-coded in a switch statement, but this is likely to change as my new Editable Data System gets incorporated.
  • If a ship is being loaded: as with modules, spawn a fresh ship with no modules if needed, based on the given name; once a ship exists, use the key to fill the correct value, for example its description.
  • If neither a ship not a module is being loaded, then any keys found must apply to the level itself, carrying information such as the level's author.
This is all relatively straightforward compared to the lexer's work, which makes sense since it doesn't have to deal with building strings, streaming data from a file, or interpreting what esoteric symbols in the file constitute words or state machine triggers. It does, however, involve a lot of hard-coded information, causing it to constitute an uncomfortably long file nearly 500 lines long with only a few basic keys included in it. That number isn't such a big deal now, but with a few dozen possible keys for modules and possibly a comparable amount for ships and for levels, it begs re-examination. At least for the moment it runs pretty smoothly:
https://i.imgur.com/N3TMzVX
Click the image or here for a bit more information.
As seen here (assuming the gif loads properly), a file based on the upper ship exists, it is being read by the lexer, the lexer is generating tokens and sending them to the parser, the parser is adding and adjusting modules based on the tokens and which keys and values they happen to be, and finally the lower ship attaches all of its modules together based on which module each of these modules references as its parent, resulting in the new ship becoming a faithful copy of the original. I've successfully put these mechanisms to work in my ship editor prototype, allowing me to build, save, and load a few test ships:
Building using those textured cubes from before I had any proper module models. Since there was no module properties UI at this stage, modules had no properties aside from their positions and default names.
Building using my first generation of module models, albeit still without any sophisticated texturing. Note how the selected module's name and position are represented in the right panel of the UI.
Still to be done is loading ships in some form of Play Mode or level editor so I can get them to move around and pew pew at each other. Look forward to hearing about my steps toward that goal in a future installment.

ShipBasher Development Log 2: Parsimonious Lexicography

This post is out of order because I wrote it and then wasn't entirely satisfied with what I had written, so I left it as a draft for months... Anyway, I left off Part 1 in the midst of a quandary as to what strategy to employ to accomplish my goal of a basic saving and loading system for ships and, eventually, other game files. To, amusingly, paraphrase the infamous Dennis Prager, it's a simple problem to explain but a very complicated one to solve. I needed to teach my computer to do the following:
  • Convert a ship into serialized data in the form of text
  • write the text in a file
  • read text from a file and build a ship based on it. If this all completes properly, that ship will be identical to the ship with which I started.
My choices were to use XML as I had before, use Unity's built-in "JsonUtility" class, import and use some third-party implementation of JSON or some other format, or to homebrew my own system from scratch. Naturally, being an overeducated amateur programmer, I opted for the most difficult of these solutions. Every seasoned programming professional and h4x0r knows that the proper thing to do here is nab something from GitHub or at the very least consult StackOverflow, but nooo, I'm an "overachiever," so without further ado here's my story.
I did a bunch of reading online about what was involved in the science of saving and loading, during which I learned of erudite terms such as "lexer," "parser," "lexerless parser," etc. At first the complexity scared me off and I dabbled in wrangling Unity's JsonUtility, but shortly thereafter I gave up due to the lack of control I had over how it worked - issues such as wanting to only serialize some fields in an object but not others, how to serialize compound types such as vectors, etc. It turned out that what I wanted to make was actually two things, corresponding to two bullet points rather than one:
  • Read text from a file and organize it into usable pieces (often called tokens)
  • understand what the tokens mean and assemble a ship based on them.
These two tasks correspond respectively to the duties of a lexer and a parser. I thus proceeded to get my first lexer up and running:
As seen here, what I had the system do was grab one letter from the file at a time and treat it differently based on a few flags, effectively creating a Finite State Machine. Look at me, using big professional words! Obviously what comes next is over-simplified refresher #45890149021 on what a Finite State Machine is:
A Finite State Machine is a thing that can have any one of a limited (finite) number of statuses (the states) and shift between them based on things that happen to it, including its own actions. Oft-cited examples include vending machines, whose states include "idle," from which inserting a coin shifts it into "waiting for selection," from which pushing a button shifts it into "dispensing," from which it shifts itself back to "idle" by moving some of its mechanical bits around in such a way as to (theoretically) give the user one of its items (even better, the item the user wanted).
My lexer has like ten binary flags now, corresponding to a huge number of possible states depending on how granularly one wants to define a state, so I won't be enumerating them all here, but here's an oversimplified interpretation of what it does:
  • Be in one of several states based on how the developer or user set it up or based on what has happened already. These are determined by which flags are set or unset, as detailed below.
  • Grab a character (a letter, a number, a symbol such as "{", or a whitespace character such as a tab or a line ending) from the file.
  • Change one or more flags if the character is special in some way. For example, if the character is a whitespace character, and the "inQuotes" flag is false, then the current token (word, phrase, numeric value, whatever) is complete. If the token is a "key" such as "entityName," then the next token is expected to be a "value" and not a key, and if it is a value such as "The Friend Ship," then the next token is expected to be a key and not a value, so in either case "isKey" should be toggled... unless a flag such as "inData" is true, indicating that multiple values exist to follow the most recent key, e.g. "0.5", "1", and "9.5" all follow and correspond to "position."
  • If the character is not special, i.e. it's just a letter, number, or punctuation or symbol that isn't one of the symbols I consider "special" for these purposes (for example a period holds no special significance to the lexer), add it to a string (technically I used a StringBuilder, but that's all, well, very technical) representing the current token. As detailed above, the current token will build up until a whitespace character is encountered, unless "inQuotes" is true, etc. etc.
  • When a token is completed, i.e. a whitespace character shows up as shown above (wow such non-linearity much complexity doge) and the current token isn't nothing (or empty), and there isn't a flag set that allows treating of empty tokens as actual tokens under certain conditions (yes there actually is one), the token is sent to the parser to be processed along with a modicum of data about the current state machine flags.
Despite the clumsiness with which I bumbled about explaining all that, I did make all of the code work in a very controlled and predictable manner, which is the important thing in situations like this. As can be seen above, the lexer is able to construct tokens for keys and for values and output these tokens for processing - in the above image, "processing" is simply displaying them on the screen with some formatting for clarity.

Since this has ended up somewhat longer than I'd imagined it would, the explanation of what the parser does shall be in another installment.

ShipBasher Development Log 3: Hat Simulator 2̶0̶1̶9̶ 2020

Months-long intervals between posts and then suddenly two posts in one day?!? No. Maybe. As it stands right this minute, I'm uncertain whether this post will actually be finished and I'll deem it ready to publish before another day has gone by, but I do know that I've started typing it within one day (mere minutes, in fact) of the last time I was typing one. Assuming reality is real and all, that is.
Right, the actual post content...
ShipBasher is supposed to include an editor for ships - you know, so you have something to bash. Actually the reason I'm calling it "ShipBasher" is as a portmanteau based the term "KitBash," which describes taking a bunch of existing parts (provided to you prefabricated or previously created by you) and combining them together into a new thing. This is more or less the point of Legos, though I've mostly heard the term in reference to computer-generated artwork, e.g. a 3D animator modeling a bunch of little greebles and then instantiating and intersecting them with each other to make a big awesome mech or, well, spaceship. This is, in fact, how the spaceships in the original Star Wars trilogy came to be.
In ShipBasher, ships (or stations, or drones, or whatever else) are assembled from a number of "modules" selected from a menu, instantiated, and positioned, not unlike the ship editors for Battleships Forever, Kerbal Space Program, Space Engine, and Spore. I don't intend to support resizing or reshaping of the modules as some of these do, at least not at this time, but I do intend to allow editing of the module instances, something that was not supported in "StarBlast!," the prototype version of ShipBasher (again, no affiliation with starblast.io).
Here's how this editor thingy looks so far:
Whoa! Look at that fancy transform manipulator! Maybe I'll write about that another time.
Some features are obviously still in the works, e.g. module previews and better modules that aren't just textured cubes or boring gray thrusters I made in Blender and have yet to bother texturing, but the important features I planned to include are all at least indicated here. At the top is a UI for the ship to be named and given a faction (and in the future, other properties) and buttons to save the ship to a file, load a ship file, clear the scene for building a new ship, and exit. At left is the menu to add modules, with buttons to switch between module categories (e.g. thrusters, weapons, armor plates). At right is a UI related to the selected module, with buttons to change its parent module, duplicate it, delete it, and delete it along with any siblings assigned to it, and with an extensive list of fields for editing the module's properties, from its name to its position and rotation and even how much heat it generates when it turns on. This UI and these fields within it have been my main concern for the past few days.
There are a few dozen fields already and possibly more in the future, and every single one of these has to correspond to a specific property of the module and perform a similar set of tasks when a module is selected:
- if a different module was selected before, check whether the value in the field has been changed, and if so, compare it to the current value and the default value for the corresponding property of that module
- depending on what the new, old, and default values are, update the assigned property on the module
- examine the new selection and whether the assigned property has a value set
- depending on what the existing value is, display either that value, the default value, or a blank or zero value (depending on the field type) in the field
This is a lot of repetitive functionality that I had barely begun to implement in a rudimentary and very clunky manner so far, so about four days ago I set about building a clean new system for handling them. I started an empty scene in an empty folder in my general experimentation project, and in it I put a few simple primitives and a simple UI with a few fields of a few different types. In the end what I ended up making was basically a character creator, so I stuck with the idea and this is how it looks now:
You can read a bit more about my progress on this here: one two three four five
You can click on any of the three characters to select it, edit the character's properties, determine if it has a hat, and select any hat to edit the hat's properties.
Each character and hat has an "editable" component that stores a number of properties as instances of a "datum" class (this is the singular form of the word "data" btw if you want to sound smart). Each datum contains a value and an index. The index refers to an index in an array of names for the data, e.g.:
{ "name", "HP", "armor", "hasHat", "hiddenExtraPropertyNotShownInTheUI" }
The presence of the name array effectively turns each datum into a key-value pair, which is programmer talk for the sort of information you'd find on a web form: username = "problemecium", password = "••••••••", parkingSkillLevel = 100, isBeingPedantic = true for example. I can make any number of name arrays and have them correspond to different sorts of things, e.g. characters, hats, modules, or ships. Each editable is assigned to a certain name array and to a "default" version of itself that, naturally, contains a default value for every datum named in that array. Having this default allows instantiated modules to not have to store copies of every value, but rather only those that have been modified.
Each field also has an index, which determines which datum it is meant to display and edit. Fields are able to intelligently scan for a datum with the correct index, find the default value if no such datum exists, examine themselves for what form to have that value take (string, floating-point number, etc.), and display that value in the UI. Fields can be linked to other fields, e.g. the armor field shown above, so that players have multiple ways of reading and editing the information.
Each field is also able to independently target any editable in the scene. Thus as seen above, character fields can target a character when one is selected and still correspond to that character even when the selected item is a hat, or vice versa. This actually enables me to do something awesome that I hadn't planned at first: select and edit modules on a ship inside a level that contains multiple ships. I could even pause a level that's being played and then edit values in the modules on one of my ships, for instance refilling a fuel tank or setting a damaged module's HP back to 100%! Naturally I want players to have to enable the developer cheats to do this unrestricted, but a limited version of this functionality could enable them to create, say, a level in which you have a damaged freighter you have to protect because all of its turrets have run out of bullets and the engines can only operate at half thrust.
(Battleships Forever, a major early influence on ShipBasher, includes a mission where you can interact with damaged ships from a previous off-screen battle, as seen here.)
I'm considering releasing this system on the Unity Asset Store if there is enough interest in it, as I have designed it to not be specific to ShipBasher and, in theory, work with any project that involves selecting things and editing their properties. Please do let me know if you think this would be useful in a project of yours or if you see any issues or think there is a feature it sorely needs.
As it stands now, I think this is feature-complete, and with it having passed all the robustness tests I've thought to toss at it, I intend to start incorporating it into ShipBasher. I'm not entirely sure whether to maintain the existing interface design or try something new such as a single editor that handles levels, ships, and modules. With any luck, the next devlog will reveal some exciting progress on that front.

RNGesus is an unruly troublemaker who'll cause you all kinds of grief if you let him off his leash.

"Find Your Car" includes, unsurprisingly, a lot of procedural generation and in turn a lot of pseudorandom number generation. As with my prior article about pseudorandom numbers, I felt like taking a few minutes here to share my experiences wrangling the laws of mathematics to achieve my goals.
A major purpose of this game is acting as a demo for my procedural universe chunk system, particularly its versatility "out of the box." I accordingly designed it with as much modularity as possible and used preexisting utility scripts I'd already written wherever I could. I ended up needing to upgrade a few of these, but in so doing I was careful to keep them generic and thus reusable.
A notable example is my "Swap With Random Prefab" script, which when attached to an instance of a prefab will, once it is spawned, choose from a user-specified list of prefabs, instantiate it in place of itself, and then despawn itself (or, in the upgraded version, an optional "target" object). This has been useful to me in the past for, for example, spawning a placeholder tree and then swapping it with a random other tree to add variety, or having a zombie drop a random item when it is killed. In "Find Your Car," it is used for walls and floors to randomly replace them with a variety of walls or floors, e.g. a floor with a ramp or a wall with a door, when a chunk is refreshed. This way I could construct one template parking garage chunk and then have it adopt a large variety of configurations as it was instantiated throughout the garage.
Some readers may, assuming I'm explaining this well, see the problem already. With this level of encapsulation, the wall and floor instances have no idea what chunk they occupy and thus no connection with its random seed, but they do call upon the built-in random number generator - meaning that the random swaps they perform will be truly unpredictable and not deterministic. The user-facing side of this problem is that a player could leave an area, walk a decent distance away so that the corresponding chunks are unloaded, head back so that they get reloaded, and find that they have regenerated completely differently! There might be walls where there weren't any before, cavernous voids where there had been floor, and the car that had been left comfortably parked in an open space now lodged halfway inside a wall!
Ways to fix this didn't come easily. The most obvious solutions were to refactor all of my utility scripts to use interfaces such as "seedable random" or to move all of the random generation that needed to be deterministic into the chunk refresh function, sacrificing modularity in favor of a complex monolithic algorithm. As may be inferrable from my tone I wasn't excited about either of these. I did find a solution, but it involved sacrificing performance instead (and what I imagine is less than professional-grade code) by creating a helper script that would scan chunks for specific scripts and call non-randomized versions of their swap methods, which it would randomize itself based on the chunks' random seeds and positions - a bit of a midway point between the other two options that I considered a workable compromise.
The reason I bring this up isn't to brag about my hacky workarounds to my own buggy code though. The reason I bring this up is because I learned a valuable lesson and I want to pass it on to everyone else who tries to do something like this: be very careful when dealing with random number generators if you want deterministic results. If you don't make sure that any and all objects using them are strictly controlled so that your random seeds (or states, etc.) are properly enforced, the generators will bite you in the butt with no hesitation and happily run off generating all manner of decidedly non-deterministic, unpredictable values, the end result of which is an unstable game world. Unless that's what you want, keep them under control!

16 October 2019

Find Your Car Development Log 1: Wait What Now?

Any recent visitors to this blog may have noticed that I haven't posted anything in a few months. To oversimplify, I don't pride myself on my time management skills and I've had more than enough on my plate to overwhelm what little skill I do have without adding blogging to the mix.
ShipBasher is still in "active" development, i.e. not abandonware at this time, but I've flitted temporarily to another project.
Have you ever been lost in a parking garage, perhaps late at night, searching for your car? Did you walk for what felt like hours, through seemingly endless levels and zones, all starting to blend together and look the same, and none giving any clear indication whether you were getting closer to your car or just more lost?
While playing with a test build of my Procedural Universe chunk system, I and some of my contacts noted that it evoked a massive parking garage, and before long an idea took shape to capitalize on this in an art game that would double as a more entertaining demo, which for lack of a better candidate I have given the self-explanatory name "Find Your Car."
Originally I considered naming the game "The Interview" for reasons that become evident below, but unfortunately the name was taken by a game actually about an interview.
In "Find Your Car," the player is to spawn in a car (wow!) within an endless, procedurally generated parking garage. The advertised goal at this point is to find a nice parking space, anywhere the player likes. Once parked, the player leaves the car.
Upon leaving the car, the player is alerted that there is an important job interview about to start and must hurry to it, racing the other candidates on the way, which take the form of simple NPCs (i.e. zombies) that chase the player and move toward the interview location, which is an unknown point at some distance away from the player's parking space as determined by the game's difficulty setting (if a high difficulty is chosen, the interview is very far away).
Once the location is reached, lo and behold! The player gets the job immediately - but don't congratulate yourself just yet. In order to get home, you must find your car. This is when the "real" game starts: the player must now wander through the near-infinite parking garage, perhaps retracing steps, in search of the car. The player no longer has to worry about enemies, but will encounter a variety of distractions including the all-too-tropey "scenic vistas," various other cars, and Easter eggs such as perhaps exotic vehicles (how did a train get in here?), the remains of past wanderers who failed to find their cars, etc.
(We ride eternal on the highways of Valhalla! WITNESS ME)
So that's the design. So far a closed alpha build of the game exists, in which there is a fully functional procedural parking garage, basic (if unstable) controls for a car and player character, pop-up messages about goals, and a victory message indicating how long it took to find the player's car.
Still to do are adding "rival" NPCs, all the cool Easter eggs I mentioned above, a bunch of polish, and solving a few playability issues such as bad luck leading to spawning trapped in a small area or being physically obstructed from reaching the interview location and unpredictable generation conditions leading to having to walk for several kilometers to reach the interview location even on the easiest of difficulties... or at the other extreme, finding it right smack next to where you parked:
In this image the interview location is indicated by the brown door in the background.
Did I mention needing a lot of polish? As it turns out, a humongous modular building comprises a lot of meshes and in turn a lot of polygons, which give my pitiable 6-year-old integrated graphics chip a hard time unless I make everything as simple as possible. But if you join my Patreon... At some point, hopefully, soon, I'll be able to treat myself to a more powerful GPU that can handle prettier graphics at this scale.
All the same, whilst playtesting this I was surprised to find how well it captured the mood of my past experiences wandering despondently through parking garages, so in a way the project is already a success.

Next time I hope to have an open alpha (or beta) build available and perhaps do a post-mortem on what I learned in the course of making this, how my chunk system matured during the process, what I might do going forward, etc.

12 July 2019

ShipBasher Development Log 1: So Far

Way back when I was in game development school I had an assignment for which I built a clunky prototype of a game I, for lack of a better name, dubbed "StarBlast!" (no affiliation with the later and much more successful starblast.io). The basic concept was a sandbox in which players could open up a "Ship Builder" minigame, construct a space warship out of a variety of predefined sections, and then switch to either a "Scenario Editor" or the game's Campaign or Sandbox modes to spawn a bunch of warships either of their own design or pre-built and pit them in battle against each other. I even made a cute little trailer for it even though I never made a proper public release, let alone tried to sell the thing:
One of my pet projects, as I've given a cursory mention previously, on which I've worked off and on in the years since then is to rebuild this game with entirely my own assets, more robust code, a more polished general design, and lots of user customizability and mod support.
Here's what I have so far:

It's rather barebones at this point, but it counts as progress nonetheless. I've also mocked up a ship editor complete with the ability to spawn some cubes and move them around (whoa!) and with some pretty buttons to click that don't do anything useful.
There isn't much else to say at this point aside from expounding on the details of the design of the game, but nobody wants to hear about my Totally Original Idea™ with no implementation in sight, so instead I mean to reveal the workings of the game piecemeal over the course of its development logs.
My current hurdle is figuring out what sort of system to use to save and load ships, and eventually other data - XML? Unity's built-in JsonUtility? A third-party JSON library? My own homebrewed lexer and parser? Hmmmmmmm... Expect the next update to involve my answer to this puzzle.

12 March 2019

Procedural Chunk-Based Universe Part 5: Deterministic Pseudorandom Worley Voronoi Implementation with Cellular Spatial Partitioning for Computational Optimization, a.k.a. geeky math stuff

As I've mentioned here and there in the saga of my procedural universe thingy, I made noteworthy use of phrases such as "Worley noise" and "cell noise" and the word "Voronoi," and I noted my intent to disambiguate and demystify them.

To start, and to explain what led me to look into them: I wanted to create a starfield, but with some important characteristics. First, it had to be pseudorandom, i.e. appear random but in fact be deterministic: any given input, such as a random seed, would produce exactly the same output; the upshot of this would be that I could spot an area of interest, leave it to voyage vast distances, and upon return find the same area of interest right where and how I had left it, turning a pseudorandom smattering of features into what in my experience, as a player, was a massive persistent universe. Second, in order to have areas of interest at all, it had to have local structure, which a truly random distribution hardly has at all, let alone to a stimulating degree.
The result was that I had to do some research into the field of pseudorandom noise. This page proved useful by providing a number of reference images of the basic results of various noise generation methods, including the popular Perlin noise and its variations as well as Worley noise and strategies such as "texture bombing." I could not only easily compare these against the result I wanted but compare them against the results my code was producing to see whether I was doing something wrong (or at least different from what I thought I was doing). I ended up settling on this:
The page describes it as "Worley Voronoi f2-f1, Euclidean distance metric." Decoded into more digestible terms, it means the following:
  • Worley's algorithm was used.
  • The result resembles a Voronoi diagram.
  • The terms used in the algorithm were "f1" and "f2," and the result value was based on the difference between f2 and f1 (more below).
  • Distances used in the algorithm were computed as Euclidean distances, i.e. "real" geometric distances in a straight line as calculated using the Pythagorean Theorem.
To start implementing this, first one needs to understand the foundations of Voronoi diagrams. A fun Voronoi diagram generator exists here and illustrates the important concepts interactively, producing images like this one:
Random "seed" points are arranged in space (the black dots). Each point has a colored cell in the diagram all to itself, which represents all positions in space that are closer to that seed point than to any other.
The important feature for my purposes was the edges of these cells: along each edge, points have two seeds from which they are equidistant, and points near those edges are nearly the same distance from two other points - in other words, the difference between the closest seed point (which one could name "f1") and the second closest ("f2") is very small. Worley noise is the pattern generated by taking values such as this difference (or some other relationship between the nearest few seed points) and using them as result color values, probabilities, heights, etc. Worley noise is sometimes also cited as "Voronoi noise" or as "cell noise" or "cellular noise" (due to its production of cells that can resemble biological cells).
The simplest form of Worley noise is of course Worley f1 - just color the result based on how far away the nearest point is. I started with this just to make sure I was on the right track, but it naturally produced suboptimal results - just a pattern of round voids that gradually transitioned into dense areas with distance; so I shortly thereafter set upon trying a variety of computations such as the f2 - f1 technique illustrated above. In the end I discovered that I needed to in fact make use of the four nearest points so as to create a threadlike structure with "clumps" near where multiple cell boundaries intersected.

How I created this structure specifically is somewhat of a brute-force method: the noise values represent the probability that a galaxy could exist at that point. Random positions are chosen in 3D space, the noise value is calculated for that location, and then a random value is generated and compared against the noise value - if the noise value is higher than the random value, a galaxy is placed at that location, and if not the algorithm tries again until it either finds a valid spot or gives up.
The cell boundaries are perfectly straight lines, so with an infinite number of infinitely small galaxies, an unnaturally precise geometrical structure would be visible, but with a more conservative density, the random variation in chosen positions, plus the ability of galaxies to occasionally pop up far from cell boundaries, lent enough variation that I considered the results good enough:
Note how clumps of galaxies form but have diffuse filaments connecting them to one another, and that there are large "voids" with very few galaxies in them.
Now, one might note, particularly if armed with knowledge about programming and algorithm performance, that checking the distances to all of the seed points every time a new galaxy is generated, multiple times or otherwise, is (I think) an O(n²) operation - the number of calculations getting done ("O") is related to the number of items involved multiplied by itself ("n²"). This is generally regarded in the programming community as "very inefficient and you should be ashamed of yourself."
Naturally I did notice the high performance cost when there were a lot of seed points involved, and I saw a need to optimize. As it turned out, my later efforts to convert this starfield into a collection of cubic chunks proved very useful: each chunk could be made to contain only a few seed points and only concern itself with seed points within itself or the regions that would be occupied by its 26 neighbors. The operation retained its O(n²) performance, but dealing with only 27*[a small number, say 3 or 4] = maybe around 100 seed points meant that the performance cost was low, especially compared to the performance cost that might have been involved in implementing other sorts of optimizations.
A drawback from this is that only so much local complexity can exist within any given chunk - 3 or 4 seed points means only 3 or 4 voids or superclusters can be present - but for my purposes this was more than sufficient, especially considering that, should I need more complexity, I can simply add more chunks, and should I need a huge number of chunks, many of them would be very far from the player where only a few galaxies apiece would be sufficient. Programming is often an art of finding a local optimum of what works well enough for your needs without having to be too complicated to build, maintain, and troubleshoot.
Of note is that Worley noise happens to be the same technique implemented in Space Engine, as illustrated above, although with a few differences: SpaceEngineer notes that he "distorted" the results using "FBM (fractional Brownian motion) noise" to raise the quality that little bit higher, and the octree-based structure of the game meant that optimization had to be done rather differently from the simple chunk-based strategy I used. Nevertheless I felt proud of independently discovering and exploiting the same computational principles and creating something that yielded similar results.

Sorry this isn't a real post :C

I've entered graduate school and, as I expected, suddenly become far busier than I had been before, leaving no time to maintain my blog,...