AI navigation
While developing a hyper casual game, I stumbled onto a problem of implementing AI navigation. The difficulty is the game has a dynamic environment, where platforms can fall. I've come up with a couple of solutions.
Manual solution
One of the solutions would be placing navigation points for AI, sharing it with all the AIs and having some kind of managing system that tracks all of the AIs and points states, updates states for each of them, and updates the target position for each AI. Sounds complicated, doesn't it? I haven't even mentioned that it will need a human or an algorithm to place all of the points!
Semi-automatic solution
Since the map in the game is roundish, a Random.insideUnitCircle * n function with a predefined radius can be used. It would return a point inside a circle of radius n.
But this would impose four new limitations:
- It would only work for a circular shape.
- The map can only get smaller from the outer ring to the inner one or vice versa.
- It would limit the number of possible positions, because it's linked to the radius around a point.
- It would require some coding to mitigate the 3rd limitation.
- It would still have the same management issues as the manual solution.
Automatic solution
The automatic solution would require setting up Unity's NavMesh system and implementing runtime NavMesh baking.
[SerializedField] private NavMeshSurface navMeshSurface;
navMeshSurface.BuildNavMesh();
public IEnumerator DestroyPlatforms()
{
for (int i = _platforms.Count - 1; i > 0; i--)
{
yield return new WaitForSeconds(_configProvider.MapConfig.DestroyInterval);
_platforms[i].Drop();
OnTileDestroyed?.Invoke();
yield return new WaitForSeconds(.1f);
_navMeshSurface.BuildNavMesh();
}
yield return new WaitForSeconds(.1f);
_navMeshSurface.BuildNavMesh();
}
That's all; then just destroy or deactivate the gameobject, rebuild the NavMesh, and signal all of the AIs to pick a new point to go to.
private void PickPosition()
{
if (!_inProgress) return;
Vector3 randomDirection = Random.insideUnitSphere * _configProvider.EnemyConfig.WalkRadius;
randomDirection += _transform.position;
NavMesh.SamplePosition(randomDirection, out NavMeshHit hit, _configProvider.EnemyConfig.WalkRadius, 1);
_destination = hit.position;
_navMeshAgent.destination = _destination;
}
Notes
You can play it here