Input lag (and general update)
Added 2019-11-26 19:59:19 +0000 UTCSo, first, here's what birb has been doing:
We got lilac breasted rollers in, and downy woodpeckers too, so that's cool. This month also saw the beginning of a new level, the office! It's pretty neat, has some killer lines, it's got a second side with a bowl that you have to ramp up and over to access. I'm of course decorating it in appropriate art, and it's generally looking pretty cool aside from that big dumb blue ramp I gotta replace with something more appropriate. We also showed (and were revealed as a Game Pass day 1 game) at X019, so THAT was fun. BTW no that doesn't mean we're Xbox exclusive... more on that later. We also showed at Day Of The Devs!
Oh and birb learned to dab, apparently. Still can't floss tho, sorry :(
Also, if you missed it, we did the stand-alone birb dress-up game SkateBIRD x Jazz Mickle's Pro Cap Wearer Do A Spoopy Combo. It's pretty neato! Also functions as a test of the customization system we'll be integrating into the main came, so it was double-handy.
... now let's talk about input lag in Unity:
Initially, I used a report-type input system in SkateBIRD. What that means is my ControlBoard function, in its Update(), reported the input it read to the ApplyMovement component, via functions on ApplyMovement that looked like this:

Simple, right? Logical? But here's the rub. Actually two rubs:
1.) I wasn't specifying execution order. If ControlBoard happened to run after ApplyMovement, it would have meant that ApplyMovement would have always been applying last frame's input.
(and more importantly)
2.) Almost all of ApplyMovement takes place in FixedUpdate. Meanwhile, ControlBoard runs entirely in Update. That means there's potentially significant lag between when ControlBoard hands input across, and when ApplyMovement uses that input in the next fixed physics frame. It gets even worse and worse, the lower your framerate drops. You'll probably see beat patterns emerge, depending on FPS. It's bad.
So what's the fix? Well, the naive approach is to duplicate your input-reading code into ApplyMovement, but hold on there cowboy, "input" means different things depending on who is riding this board. If it's a player, you're putting your ReWired/InControl/whatever logic in there to read direct from a gamepad or keyboard, but if it's AI, that hooks into their steering logic.
As such, you've got two main options:
1.) Inheritance. Build some kind of ControlBoard parent that defines virtual GetInput functions, and overload them. For the record, I hate this, because inheritance structures force you to pile a lot of not-super-related object types under a shared parent, because you need to call a handful of functions generically. It does work though, and it's simple.
2.) Interfaces. Define an interface that says anything reporting IControlBoard must provide a suite of GetInput functions. Now you reference ControlBoard via that interface, and there you go. Now the thing on the other end could be making calls that directly grab input, or they could be asking the AI how it wants to steer, or whatever else. You don't care. All you care about is you're getting the frame-precise input where you need it.
So now my ApplyMovement, instead of reading those twistInput/steeringInput/balanceInput values that were set at some point in the past, does this:

... and tada! That totally fixed my input lag. Turns out it was noticeable even when running at 60fps. Stuff just feels that bit sharper now. It's nice!
Anywho, $3+ tier folks get a dump of all the actual sources, but that's the gist. Have fun!