AI Players in Scraps currently use a navmesh to work out a path from where they are to where they want to go. Unity comes with a built-in NavMesh system which is really nice and easy to use, until you want to do anything fancy. I’ve been trying to wrangle some better meshes out of it.

It feels like the NavMesh support is one of those Unity features that had enough work done on it to look awesome, but not quite enough to be great to use. You can set some parameters:

And then tell it to auto-generate a mesh based on all your static (non-moving) geometry. Here’s an example on my SandyBridge map:

Using that generated mesh (the blue area), you can then simply ask it to calculate a path from one point to another, and it’ll efficiently calculate the route. Now your vehicle (or other entity) can avoid hills etc and get anywhere effectively.

Except not really.

Entities can path anywhere within the mesh, and since they’re always finding the shortest path, they’ll often hug the edges. That path behaviour is unchangeable. You can’t say “try to go down the middle.” So the above mesh is actually too generous with its available area. A vehicle pathing on the bridge often falls off the side, while a vehicle pathing near the edge wall or an obstacle can get stuck on it. It doesn’t help that scraps vehicles can be all different sizes, but the mesh must be baked to one specific size.

I can increase the Radius setting to bring the navmesh in, but that introduces another problem: The navmesh won’t return a path – not even a partial one – to a target that isn’t somwhere in the mesh area. Interestingly there is a path status called “partial”, but it never seems to happen. Maybe it only happens when you use Unity’s built in nav agents thing (which I don’t use)? You might say well, maybe there’s something to at least get a point on the mesh closest to a given point, like they have with ClosestPointOnBounds for bounding boxes? Then at least you could path to there instead, then go straight to the target from there? Nope.

So say you’re on the mesh and the AI is on the mesh and they’re chasing you, right? And they have a nice multi-point path to you that goes around a hill. But then you drive off the area covered by the mesh. Now the AI recalculates – suddenly there’s no path! So it has to just drive straight at you, right over the hill.

The navmesh pathing is awesome when it works. You can even link different parts of the mesh and weight them to balance when they’re chosen, like here where I told the AI it could do this sweet jump on the DustBowl map but only if it was a major shortcut:

You can also have different layers, with different weights and exclusions, so I can say “vehicles can drive on the hill layer if they have x or more engine power” or “only use the hills if it’s this much faster than going around.”

So I figure the best thing to make this work is to make sure the whole map is covered with navmesh, but there’s a normal section, a hilly section, and a usually-out-of-bounds section just for chasing targets in crazy places. Then AI will be able to path anyway, but usually will only go in good places.

But the terrain can’t be split up into layers. And you can export a generated navmesh to a 3D model and cut it up there (I wrote a script for it), but you can’t import it back in – only generate another mesh from the first mesh, which is like photocopying a photocopy.

Using two separate NavMeshes and some 3D model hacking in Blender I added a hills layer:

But there’s still lots of empty space, and I need to fill the rest with like an “out-of-bounds” NavMesh so that things can get a path.

Can I just put a big flat plane underneath and generate a mesh off of that to fill the gaps automatically? No! The mesh has to line up nicely with the other mesh layers or it won’t join up. You can use “off-mesh links” – if you want to manually place a million of them. Trying to get different layer meshes to join up is an art in itself.

Oh yeah, and if your modified mesh doesn’t line up well with the actual terrain, pathing won’t work either. Objects have to been within a few metres of the mesh vertically, and that parameter can’t be tweaked. I understand you have to allow for stuff like the over-and-under the bridge above, but I’d love an “automatically path using the closest mesh” option. Maybe I could use SamplePosition to get the y position of the mesh instead of where the vehicle is an get a path based on that…

Anyway, I managed to hack together a system for filling the gaps in my mesh with another mesh that could be the out-of-bounds mesh. But it’s a terrible process that could replace the preliminary Mensa test in terms of mental leaps required. The process sucks, and it still gets weird gaps and things in it anyway.

That isn’t even everything but this post is too long already. Right now I’m working on a script that will export my terrain already cut up into separate meshes based on slope; Then I can generate the different layers I want based on that. But I’m sure that’s also going to have issues when I try to generate a navmesh from it. One day I’ll probably have to throw out Unity’s built-in solution and use another one – preferably one where I can edit the source!

Thanks for for following Scraps’ tortuous development. :)