On Wednesday I finished up the art for my prototype milestone. These suspension fasteners were the last thing left between the subframe and the wheel studs:
The next step is taking all my art content and getting it set up with the pickup and snapping system I have already posted about. For VR, it’s best to do as little as possible in tick events. Current VR headsets run at 90 frames per second and future headsets my run at higher framerates. For that reason, I built all of my functionality to work using Begin and End Overlap events. Basically, when car part type objects intersects another car part object it executes the system of communicating between parts to find out what is or isn’t installed, and then runs the logic to allow install or removal of the part when the the correct criteria are met. This seemed to work well in testing but when I started implementing my content I quickly noticed the status of what parts were installed, allowed to be installed, and allowed to be removed were not being updated reliably. This manifested itself as parts that said they could be removed when they should have been captive, or the game erroneously preventing installation. My game is essentially a whole lot of pieces trading and checking yes/no values. Figuring out where the systems were breaking down took me a few days and these were the major causes:
Other overlap events interfering with overlap events that control part install/removal
I stopped using overlap events for pickup since it wasn’t precise enough (I detailed that one of the other posts). When the player pulls the trigger to pick up an object I use a sphere trace instead of an overlap. I was still checking overlap of a capsule collider in order to set the hand status to “can pickup” which is a subtle hand animation and a recoloring of the pickup indicator to show if an object can or can’t be removed or picked up. I had this capsule on it’s own collision channel and the parts had extra collision boxes on a matching channel. I had thought having separate channels would prevent any interference. In retrospect, the event is On Overlap, not On Overlap of Channel. Any time there was unintended overlap event from this capsule collider the execution loop for snapping and updating variables would get disrupted. Depending on the shape of the collision volumes and way the parts were being held, this problem may or may not have manifested which made figuring out what was happening confusing. The solution I came to was to replace the capsule collider with a trace at a regular interval (every .2 seconds works well)
Only tracing for a single object on overlap:
When two parts overlap I do a sphere trace that is about a meter wide to get references to nearby parts. When I set this up I accidentally used simple sphere trace. Unreal has two categories of traces. A simple trace which only returns the first actor it hits and a multi trace which returns a list of all the actors that the trace intersected. In testing I didn’t notice the mistake because I was only working with a few objects at a time and the actor it returned happened to be the correct one. Switching that out for a multi sphere trace allowed me to loop through a list of actors and get information from all of the nearby actors. Like the last issue, this one presented itself intermittently depending on position of all the actors in the area.
Updating variable AllowRemoval on overlap doesn’t work:
This one seems obvious in retrospect but took me several hours to figure out. When the overlap event begins, I get references to nearby objects and check the necessary objects to see what is or isn’t installed. For installation, I check to see if the parts it attaches to are currently installed along with any specific criteria I decide (does the player have access to it? Is it realistic or practical to allow install?). For example, if the player installed a coilover shock in the car without a spring in it, I’m not going to allow them to install that spring until the shock is removed from the car and the top hat is off of the shock. AllowRemoval works the same way, I check nearby objects and decide if the part is captive or should be allowed to be removed. After the part is snapped in place, I change the part’s status to Installed. Other parts check this installed status when their overlap events occur and the system seemed to work well. The issue is that for AllowRemoval this doesn’t actually make sense.
The example that was giving me issues: A front upper control arm must have bushings installed before it can be installed in the car. Also, the bushings can only be installed, or removed, when the control arm is not on the car. If the Bushings are each checking the control arm for Allow Removal, and the control arm is snapped into the car, that check will not happen until an overlap event is fired. When the bushings were last overlapped, the control arm wasn’t in the car, so their AllowRemoval status was set to true. When the control arm was snapped in place, the bushings didn’t get a new overlap event so they didn’t have the correct status. You could remove them but then not reinstall them. Also if you waved another car part over them they would suddenly have the correct status. This didn’t show up in my initial testing because as I mentioned earlier I had that capsule collider attached to the hand which generated a whole bunch of extra overlap events and masked the issue. To fix this I am setting allow removal at regular intervals, not as part of the overlap event loop. On event play I do a delay of a random float between .1 and 2. After the delay I start a timer that calls an event every .2 seconds which updates the AllowRemoval variable. The random length delay is to make sure I’m not updating 500 or 1000 objects at once on the same .2 loop, instead that small bit of compute time is spread out evenly in that .2 second window.
None of these issues were particularly difficult to fix but they way they interacted with each other made figuring them out challenging. Because they were intermittent, it was hard to tell where one issue started and another began. When it seemed like I knew what breaking the game, the fix didn’t do what I expected, or the debug messages seemed to be firing without a clear reason. The takeaway for me is to test my systems with more complicated content that replicates how the game will actually work and don’t assume that a system is only broken for one reason.
I am moving on to implementing these systems with all of my art content. This means I am making hundreds of copies of the child class BP and editing the details for each part. I did some cleanup and color coding to make that process quicker: