A look at the programming behind a workable jump for the code junkies in the audience
In order to make for an enjoyable experience for the player, Mutt must jump precisely 10 units high, every time the player jumps. We have blown up our old jump mechanics in favor of a new way of approaching this. Our existing code mostly worked, but it varied slightly between jumps. In most cases it was a negligible difference, but every once in a while it would make it impossible to jump to the desired platform, causing frustration for the player (since Mutt was not doing what they would expect). In order to fix this, the first thing we had to do was reliably recreate the problem…
Recreating the Problem; The not-so-good way:
One way to do this would be to simply run the game, try to jump on a platform repeatedly, and tweak the code until it works. The problem with this is that it’s incredibly time consuming and it’s not all that reliable. It’s very easy to think you’ve fixed the problem, when you haven’t.
The Better Way:
A better way would be to attach a script to Mutt that prints out the height at every frame. In code form that would look something like this:
With this we can get the exact heights as we jump and we can see if it reaches the max height or not, then iterate on the code until it works. The problem with this is that we still have to play the game ourselves, jump around just to get sample heights, then switch back to the code to try things. This is still a time consuming way to iterate on the code, and there is still a risk that we won’t fix the problem if it only occurs 1 out of every 50 times we jump.
The Even Better Way:
It would be even better if we could run automated tests to do all of this for us. Fortunately, Unity released their test tools package to assist with precisely that. Unfortunately, there’s no built-in method for simulating input, which is what we want in order to do a full integration test. So the first thing we had to do was stop using Unity’s Input class directly, and create a wrapper object that we used instead. It looks a little something like this:
So now, instead of calling the input class directly like this:
We use the instance of our wrapper:
This now allows us to use NSubstitute to stub out things like GetButtonDown and make it always return true, making the rest of the game think the user has recently pressed a button every frame. For our test, we needed to fake input for the jump button, so we did the following:
From there, using Unity’s Test Tools package we were able to write integration tests to test jump heights. The gist is that, using faked input, the test would make Mutt jump repeatedly while watching how high he jumped each time. Once that was setup, we could tweak the code until he finally consistently reached the correct height!