Spline-based dynamic Conduits
You’ll note the previous station environments are gone.
I started fresh because this new conduit system was complicated, and needed to be fleshed out in isolation before I tried to bring back the previous modules.
Had some vague plan to bring the satellite form stations back eventually, but I had a lot of design changes in mind, and was finally learning not to do rework for every new feature.
This… was the feature that broke me. I would not recommend attempting real-time, spline-based mechanics unless you are absolutely sure you know how. When it doesn’t work, it does so in extremely interesting ways.
Initially conduits were just an item that could be used on wall areas of some modules. This would toggle on the visuals for conduit mesh on the wall, which I had manually author per module. Naturally I felt this did not work very well with the concept I was aiming for and decided to tackle a different method.
Ok, I think I need bullet points to properly explain what I was doing, and why it went wrong.
- It needed to procedurally generate conduits between powered objects, and a power source, which required pathing across multiple modules.
- ‘Pathing’ was a convoluted, multi-step process.
- Starting at the unpowered target, it walked up the parent tree until it reached the room (module) and moved sideways along the module connections, until it got from the module with the ‘powered object’, to the module with the ‘power source’.
- Because it didn’t just need to know which module to find next, but also which point on which wall to find, I had to make a second layer to this: conduit pathing.
- Conduit pathing had to be built on a network of points, and the best way I could figure out how was to add dozens of spheres to the blueprint of each module. The points were parented to each other in sections, but I couldn’t do that at branching points (So many branching points).
- So, they would perform a one-time trace for overlapping spheres, and save a reference to them. That was the node network.
- Thankfully I only did that one time, but it created a significant hitch.
- To get an unbroken line from a power generator to a powered object, it first searched through the modules until it found one with a power source, and then through the previously generated conduit node network to build a conduit path.
- If it found the desired next module it would make a major checkpoint, and keep going forward.
- If it found a branch point in the node network it made a minor checkpoint and tried one of the branches.
- If it found a dead end, it would walk back to the last checkpoint and try again. If all options at a given checkpoint were exhausted it would step back further, and try THAT checkpoint.
- This was done for every powered item.
- The first few would typically travel the entire way, however when a new path encountered a successful path, it would split that line into two and spawn a junction point for all three lines to link to.
- This all caused considerable delays in world generation.
- Because pathing was randomized, it was difficult to diagnose issues. I didn’t know about Seed randomization yet. So when I tried to fix a bug I just had to guess, and if I never saw the bug again, it was fixed.
- There is also player interaction with the system. For a long time the spline conduits were made up of a number of points that defined the various bends. A player could pick up either end of a conduit, and it would trail behind them from the last ‘point’ on the line.
- Later on I changed this to allow the player to ‘Pull’ on the line and drag it off the wall like a piece of cooked spaghetti.
- The spline meshes were updated from start to end, however you could pick up either end, so the visuals did not organize correctly in the reverse order.
- My solution was to flip the order. Which ‘worked’, but revealed that the curves it generated were not identical in both directions.
- The conduit also kept track of how far each point was from each other, so it could define a maximum length. If that length was reached, the line wouldn’t extend further.
- This feature more or less worked except for a few bugs which managed to extend the maximum length.
- To avoid issues like the conduits passing through walls, I made it trace from the previous placed point, to the end, that you held. if something blocked that trace line it couldn’t go through it and stopped.
- This worked pretty good for a while, but caused considerable issues if confronted with a slight lip or edge.
- To combat this I tried adding a ‘temporary point’ to add that bend. It would attempt to recover being pulled through an edge by tracing along the failure point until it was unblocked, and then creating an extra, ‘temporary’ point that was not tied down, and would get removed, if the trace ever failed to find the edge.
- I quickly found that while one bend helped, it quickly needed a second and third bend.
- It was entirely possible to drag the conduit around a cylinder, or through a maze and would require potentially hundreds of temp points.
- Additionally, sometimes the bend point missed a trace and caused it to pass through a wall.
- Because the ‘pull’ system needed to keep you from dragging lines through walls, once it clipped into something, it was permanently stuck there.
I think I gave up here.
Throughout the lifetime of this feature there were considerable problems in how the links connected and how they visually displayed. Most of the things mentioned here had at least one massive headache at one point or another.
I think I was afraid to throw out bad work and start over, because I figured I’d just end up with the same thing. Probably true. I didn’t have the experience to know a better way.
I know it can be done. I’ve seen some fantastic rope/cord mechanics in games, and though I don’t think it could be remotely easy, it is definitely possible, and clearly fun. I probably wouldn’t attempt it again though.
Atmosphere Visualization — Oct 5th, 2019
This was an experiment using post-processing and custom stencils to visualize atmospheric density and the temperature in the module. This video doesn’t show much of that, because I ultimately scrapped the concept, and didn’t bother to record it!
In its most complete version, I had air in the rooms tinted orange (hot) or blue (cold) that was supposed to be layered against each other and the correct color would be seen through a doorway. As you approached the doorway it would fade into the other, and at some point, swap. I had a really cool prototype for a camera vector/position based wipe effect that lined up with the doorway so you couldn’t see the swap.
The issue I was running into was that I had to index doorways by closest, update them constantly, and feed that information into a limited list of layers in the post-process material. It would inevitably be prone to running out of list space, and it couldn’t determine which doors were actually needed.
The worst part was I couldn’t figure out how to get the doorways seen through a doorway to be the correct color. You can see my attempt at it in the video. Sometimes there’s a second layer color on some of the doorways, but it was limited. I had it setup to set the value of a material collection color tied to an index, so each color had to be a specific line in the post process material. I also couldn’t figure out how to get more than two layers, and I was seeing third, forth, and fifth layers as potentially necessary. This exponentially increased the resource draw on this system to an unusable degree.
Initially I thought it was just an issue of adding indexes, but I found that custom stencils will layer over each other and add their values together (index 1 and 2 is now 3. index 3 and 5 is now 8.) It was a nightmare to debug.
Besides which, the way this post-process material used depth as a factor in the start and end of a doorway. Think of it as thick fog. So a second level door had to be behind the first, and lerp in that order.
Considering that this would only really be used when doors were shut and immediately after opening to equalize pressure, it was both something that couldn’t be fudged, and wasn’t really worth the effort. Not pursuing that concept was one of my saner moments.
Power Drills and Bolted Panels
The issue that I was trying to solve with bolts was that big objects were way too easy to pick up. I’d designed item pickup so it would be quick and easy, but a simple misclick could cause a massive object to just fly right at you.
I’d tried a few solutions.
Locking, which was just a button on something that set it to not be picked up. Useful for some things, but there were issues telling at a glance, if it was locked or not. There were other buttons that were also toggled, and also lit up. Additionally, as a rule I had decided that lights turn off when power is out, so that had to go.
I eventually added ‘charged pickup’ on all items, which basically meant: you hold down the button, it would lift up from the wall, and once a threshold is reached, it would release. This had the added bonus of clearing any overlapping collision volumes. Or, you stop/look away, and it will settle back. I was considering making free-floating items consistent with this, but I didn’t have a good plan for that yet.
Generally this worked fairly well, but there was an issue where the visual effect of the item lifting off the wall could move the item outside the trace area. This was based on the player camera so it was not always present. I think the solution was for the trace to offset slightly to counter this.
It was a good addition, but some things should be solidly locked down.
So I added bolts.
This added a few components to many of the large items and a new tool. This built on yet another kind of grid (larger spacing) with a different list of items. If you wanted the panel off this wall, you needed a power drill and a battery.
It wasn’t a perfect system though. The bolts were small, and hard to aim at. I had made their target area much larger than their silhouette, which helped some, but if another bolt was close by, they could easily overlap. The issue with a physics-based movement is that every move has a little momentum, so the place you meant to click had already drifted past. This was relatively minor, but constant, and you start to feel it.