Physics Tooling
I’m working on developing a custom physics system that will ultimately power a neat mech thing. As part of that process, I built a tool to store and replay different phsyics test setups. It has made things way easier!
I’ve called this (very creatively) the Physics Test Case Tool. Its records an initial setup and series of player inputs in engine, and replays them. I also extended this to play multiple test cases next to each other. It sounds (and is) simple but it’s proved invaluable in a number of ways, which I’ll go over before explaining how it works under the hood.
First, it lets me test code changes for complicated movements without having to make the movements every time. When it “records” a test case it only saves the initial state and inputs, leaving the rest to be driven by the physics system. This allows me to change the code and see the results for that state and input, without having to reset and re-input everything. It also lets me step through a case frame by frame for smooth player input. I can spend way more time actually working on problems, and see what I need much faster.
Second, it lets me see broad results quickly. After creating a case that is not behaving how I want it to, fixing the physics system for that case is only the first step. After that, I need to check that my changes haven’t broken any other aspects of the physics. Because the outcome I’m looking for isn’t a specific deterministic result, I can’t do strict unit tests. I want everything to look vaguely believable, and now I can check the whole range of situations that were in a good state before the change to make sure that nothing crazy has happened. I can also spot adjacent problems that have unexpectedly been solved by the latest changes, although that is somewhat less common.
Third and perhaps most importantly, this tool has transformed my workflow from one big step and into two small approachable steps. When I started, the only step that I had was “make the physics more better,” which is rather difficult. Now, I’ve got two steps:
Make a test case that’s a little janky
Improve the code to make it less janky somehow
Small difference, but this far easier. Step 1 is essentially just playing around until something weird happens, which is one of my favorite things to do in games. Step 2 is a concrete and constrained programming task, which is one of the best kinds of programming tasks. And, it usually leads to discovering some bit of logic that might also be problematic, but now instead of falling down a rabbit it can be safely put off until I get back to Step 1, which I’m now already ahead on! At no point am I worrying about what I should be doing next, or daunted by the huge task of “solve physics” ahead of me. I did not think this would be as huge a deal as it is.
Implementation
Creating this thing was not particularly complicated. Each test case is a collection of three assets: a prefab, a scriptable object, and an animation clip. The prefab stores the initial state, including exactly one PhysicsTestCaseRunner script, which handles assigning the animation clip and sending the name of the test to a canvas as a label. The scriptable object holds references to the prefab and the animation clip, as well as the name and a description and any metadata that I might want to throw on there in the future. The animation clip stores an animation of the Transforms on the objects set for recording, although adding additional things to record is fairly trivial.