Progress Update
tl;dr reworking handling and going deep into race balancing
First, a few smaller progress updates before going deeper into a topic:
- Buoys now can be passed/failed. I haven't worked out the penalty for a buoy miss just yet but I've gone with a "simple" line segment collision with a line segment extending out from either side of the buoy. This is working well but I don't have a great visual representation of either the hit or miss of this just yet. Very likely a solid speed penalty for a miss, and max number of misses allowed.
- Adding a finish line and basic lap times. I am using the same line segment collision detection on the finish line to reset the lap timer. While tuning (more below) I found I needed some real times to compare against, so built just enough to have lap times.
Deeper dive into handling and racer balancing
What I've spent the most time on recently is creating and tuning the different racing profiles, which lead into re-working some of the handling basics.
To set the stage, I'd like to have 3 riders with different handling profiles:
- Profile 1 - Average across the board: fairly responsive handling, decent accelerationg and top speed.
- Profile 2 - Very high acceleration and tight/responsive handling, trading off a lower top speed.
- Profile 3 - High top speed, but loose/sluggish handling. Should be tough to navigate most courses.
I had previously (and, honestly, always) put some work/thought into the handling of the jetskis, outlined in my post above. However I found while pursuing these profiles, that I was still missing something.
I wound up re-working my "grip" physics, which is how much slippage there is compared to the desired direction. A zero grip would be a jetski sliding in one direction on ice, while spinning like a top - aka 100% slippage, the desired direction is never applied.
I previously had a version of this that "sort" of worked, but as I teased apart the profiles I realized it wasn't correct. Not going to go into details here but previously I was approximating the loss of grip by pushing along the X axis. At small numbers this felt okay but when I decreased grip further the result was way too much horizontal momentum applied, which doesn't make sense when the thrust is always from the back of the jetski. The new approach looks and feels more accurate and can easily be dialed up or down while still making sense (though at some point, very low grip doesn't make sense in the real world).
While tuning Profile 3 - my thought was I could just drop the (new & improved) grip until the handling felt sluggish enough. But, the result of the low-grip profile wasn't sluggish handling, but more felt like I was handling something on ice, instead of in water (though - ice level?). It just felt slippery and not "sluggish". It was hard to handle but not in a fun or realistic way. (It didn't feel like the handling of the original wave race).
Introducing "roll"
After lots of trial n error, (and replaying the original wave race 64), I realized I was missing an entire aspect of handling, something I am going to call - roll.
Explaining roll by way of example.
Let's say a jetski is holding a solid right hand turn, and the player quickly pulls the crank solidly to the left:
- Tight roll: the jetski rolls rapidly to the left and almost immediately changes direction in response to the crank.
- Loose roll: the jetski takes some time to start turning left. Even though the crank is pulled left, the jetski will still continue right for a moment, gradually straightening out, and finally getting to the desired left direction.
A loose roll introduces a lag in the controls, and requires some future planning by the player.
Roll is not a substitute for grip, in fact being able to tune both independently can yield some really interesting results. For profile 3 - low grip and a loose roll is starting to feel very right.
Visualizing these concepts across the 3 profiles using some lines. Explaining from the bottom to top:
- The bottom line is showing the exact rotation of the crank.
- The next line from the bottom is visualizing the amount of slippage (ie low grip). Having this line be vertical would be zero slippage.
- The next line (second from the top) is showing the desired direction to apply to the jetski per tick. This line is just a linear relationship to the raw crank value, they move at the same exact time. This is how all my handling was working, previously.
- The top line shows the final change in direction per tick applied to the jetski. When there is a loose roll, this line will follow/lag the line just below it.
Here's what I have for Profile 3:

Note how the top line follows & lags behind the line just below it. There are moments where this line stays on the opposite side of the crank, but then smoothly catches up to match the desired direction. This is the "loose roll" in action, and really creates that sluggish feeling. Being late to turn for a buoy is punished at this tuning.
In sharp contrast, here is Profile 2:

Notice how the lines all pretty much stay locked in. There is virtually no lag or roll, and there's only a little slippage. A little tougher to see but also a high acceleration, this profile pretty much follows the crank directly (but has a lower top speed).
Finally, Profile 1, a balance between the others:

Can see a little slippage and a little roll. It still feels like a jetski, takes some planning to handle, but isn't punishing.
For fun, showing an even more exaggerated/silly Profile 3, even less grip and looser roll, just to show off the concepts and what is possible, not meant to be a final playable profile:

CPU/AI Handling
With a new grip, and a new "roll" concept, I then started to apply these to my CPU racers.
Selecting one of the racers for youself, you will then race against the other 2 profiles. The AI for the CPU racers do not use the exact same physics, though there are overlapping concepts. In short, the AI looks for the "next" buoy and applies some smoothing/maths for how to turn towards that buoy. This works great since the AI can get knocked around, either by you or by each other, and they'll always stay on course, and even compete for similar race lines. I will likely write more on this some day.
Balance
Now, the big challenge ahead for me is: balance.
I'd like playing with each of racing profiles to be somewhat competitive, with profile 3 ultimately rewarding high-skill, though with maybe a tight course to give an edge to other profiles. I'd also like the AI to be competitive with each other.
To measure the balance, I am running lots of practice laps and comparing times, and observing the CPU racers race with each other, tuning, and trying again. It's a very manual process thus far.
Getting the profiles to balance for the human player is tricky, but I feel like I am already sort-of close.
Having the CPU balanced is proving to be conceptually much harder. Having Profile 2 vs Profile 3 for example - the AI's handling being very reliable & perfect, profile 3 just rips. I am starting to introduce more counter-weighting specific to the CPU flavor of the profiles, but, it is time consuming. I have a handful of more ideas in this space, and will likely be focusing on it for a while, since it's a very, very core part of making this an actually playable game.
On the upside - the game is actually fun to play, even when not perfectly balanced! I've been very pleased with the AI - seeing one AI pass another then pass back is satisfying. So, hopefully I can find something that "good enough".