Разрабатывая игру City Massacre я тоже столкнулся с этой проблемой. City Massacre является зомби-шутером, основным обитателем которого являются зомби, а основное занятие игрока - это их уничтожение различными способами.Игрок путешествует по уровню, выполняет задания, проходит ключевые точки, а попутно отбивается от орд зомби, которые лезут на него с разных сторон.

Однако во время тестирования я обнаружил, что находятся игроки, которые занимаются обеганием зомби, для быстрого достижения ключевых точек и прохождения уровня. Т.е. по сути они пробегают весь уровень до зоны эвакуации не делая ни единого выстрела. Зомби их атакуют, но потом переключаются на союзных ботов и битва остается позади, а игрок спокойно бежит дальше. Вроде все бы ничего, но хочется сделать чтобы игра была хорошей, а не просто бегом по пустой карте.
Помимо этого, зомби которые отстали, строили очень длинные маршруты до игрока, что очень влияло на производительность. А еще новые зомби не появлялись, т.к. старые еще не были уничтожены. Вот сколько проблем разом.
Я начал думать над решением этой проблемы, как вариант, можно было бы всю карту разбить на зоны и для перехода из одной в другую сделать обязательным сражение с врагами. Решение очень даже годное, но слишком часто его использовать не вариант. Хотелось найти элегантное решение, которое аккуратно решает проблему спидрана.
В результате я пришел к выводу, что основная проблема - это то что все действие игрок пробегает мимо и сражения, как и противники остаются позади. Исходя из этого я сделал небольшой трюк, который постоянно держит игрока в центре всего происходящего.
Для этого я добавил врагам проверку на расстояние до игрока, которая делается несколько раз в секунду. Если проверка показывает, что игрок слишком далеко, то зомби просто уничтожается и тут же появляется в ближайшей невидимой области по пути следования игрока. Если хотим решить проблему спидранов кардинально, то вместо одного можем сделать появление 2х, а то и 3х зомби в случае срабатывания такого триггера.

Вторым шагом решения проблемы стал перехват игрока в случае его бега. Для этого я сделал небольшой расчет будущего положения игрока, рассчитанный исходя из его текущей скорость. И отправил зомби на перехват. В результате они бегут игроку наперерез и атакуют его. Если игрок отступает спиной вперед и отстреливается, то часть зомби будут стремиться обежать его и атаковать со спины.

Для реализации понадобилось к конечной точке для NavMeshAgent добавить скорость игрока в виде Vector3, умноженную на время.
В коде выглядит примерно так:
Синтаксис:
Используется csharp
Vector3 velocity = Target.GetComponent<Rigidbody>().velocity;
float time = 1f;
SetDestination(new Vector3(TargetPosition.x + velocity.x * time, TargetPosition.y + velocity.y * time, TargetPosition.z + velocity.z * time), 1.5f);
float time = 1f;
SetDestination(new Vector3(TargetPosition.x + velocity.x * time, TargetPosition.y + velocity.y * time, TargetPosition.z + velocity.z * time), 1.5f);
1.5f - расстояние до цели на котором останавливается NavMeshAgent
Таким образом ситуация сильно улучшилась. Теперь когда бежишь по уровню, зомби начинают действовать более агрессивно, преграждать путь, забегать за спину, выбегать из-за угла навстречу и т. д. Главное появилось ощущение наполненности уровня происходящим. Работу этого нехитрого метода можете посмотреть в игре City Massacre. Надеюсь что статья была вам интересна!
Посмотреть поведение зомби на примере можете в игре, буду рад обратной связи!
Скачать игру на itch.io: https://citymassacre.itch.io/city-massacre-download