Unity3D → Создание автоматической турели

Это моя первая статья про unity, который я стал изучать не так давно - около года назад. Тема разработки игр меня очень заинтересовала и захватила, так что теперь это стало моим основным хобби. Unity3D я считаю хорошим инструментом для создания игр. На просторах интернета содержится масса статей и обучающих роликов по самым раличным темам, мне тоже захотелось поделиться тем, чему я уже научился. В этой статье я хочу предложить свою реализацию компонента управления турелью. Турели, защитные башни, пушки - являются неотъемлемой частью множества игр в жанре Tower Defence, scroll шутер, стратегия. Поэтому считаю полезным иметь такой компонент у себя в запасе, так как он может быть использован в большом количестве игр.

Идея реализации компонента очень проста - турель периодически проверяет появилась ли цель в радиусе обзора, если появилась, то осуществляет разворот к цели и ведет цель, пока та находится в радиусе обзора. Сразу перейдем от слов к делу.

Для начала нужно создать саму турель, в примере рассмотрена турель, построенная из стандартных примитивов, которые доступны в unity. К турели нужно подключить готовый компонент, который можно скачать на github - TurretController (код компонента содержит подробные комментарии, так же есть демо-ассет с готовой турелью) На скриншоте ниже представлена иерархия составных объектов турели.

Несколько слов о принципе работы. Турель может находиться в одном из двух состояний: Idle - состояние покоя (по умолчанию) и Atack - при нахождение цели турель разворачивается к цели и ведет её, пока та не покинет радиус видимости или пока не появится более ближняя цель. Компонент TurretController имеет следующие настройки:

  • Turret Head - ссылка на объект. На скриншоте это turretHead - башня турели, которая поворачивается к цели, может вращаться только вокруг оси Y.
  • Turret Gun - ссылка на объект. На скриншоте это turretGunAxisRotation - орудие турели, может двигаться только вокруг оси X. Этот объект является пустым, центр которого расположен там, где проходит ось вращения орудия, сама же видимая часть орудия является дочерним объектом - turretGunModel.
  • Enemy Tag - тег, который имеют объекты, являющиеся потенциальными целями для турели, например, тег Enemy.
  • Vision Radius - радиус обзора. Если объект с тегом, указанным в Enemy Tag, будет от турели на расстоянии не более, чем это число, то турель автоматически наведется на этот объект.
  • Rotation Speed - скорость разворота турели в градусах/сек.

Поиск цели происходит в корутине FindClosestTarget, который отрабатывает 1 раз в секунду, в принципе этот период работы можно сделать тоже публичной переменной, на данный момент это число зашито в код компонента. Переключение состояний турели реализовано в виде простейшей FSM (Finite-state machine - конечный автомат, статья на вики), основанной на корутинах. На данном этапе в реализации не хватает собственно стрельбы по цели, но это будет рассмотрено в следующих статьях - нужно время. На последок еще раз ссылка на сам компонент с комментариями к коду TurretController.

Комментарии

Как я понял тут без update да? То есть что бы скорость вращения была фиксированной нужно использывать ienumerator? Просто я невидел где у тебя поворот происходит и сунул в fixedUpdate. весь день гуглил и нишыша

Код снабжен комментариями... Поворот осуществляется при помощи Quaternion.Slerp.

да я сделал такой же FSM и все норм стало, а в update не катит

да да я конченый в плане изложения мысли, имел ввиду не в каком месте кода а вопрос почему в update не работает ы

щас все включилось так шо забей

Отличная турелька вышла только в одном месте код лучше оптимизировать таким образом

  1. protected virtual IEnumerator FindClosestTarget()
  2. {
  3. while (true)
  4. {
  5.  
  6. // С помощью этой строки турель будет отыскивать коллайдеры только в радиусе обзора не набирая всякий мусор вне его.
  7. Collider[] colliders = Physics.OverlapSphere(transform.position, visionRadius, targetMask);
  8. Transform closest = null;
  9. float distance = sqrVisionRadius;
  10.  
  11. foreach (Collider col in colliders)
  12. {
  13. //Находим расстояние между турелью и предполагаемой целью
  14. Vector3 diff = col.GetComponent<Transform>().position - transform.position;
  15. //С точки зрения производительности быстрее сравнить квадраты расстояний,
  16. //чем делать лишнюю операцию извлечения квадратного корня
  17. float curDistance = diff.sqrMagnitude;
  18. //если найдена цель в радиусе поражения, то запоминаем её
  19. if (curDistance < distance) // Если целей множество берём ближайшую
  20. {
  21. //Ближайшая цель, попавшая в радиус обзора
  22. closest = col.GetComponent<Transform>().transform;
  23. distance = curDistance;
  24. }
  25. }
  26. target = closest;
  27. //Следующий поиск цели будет осуществлен через searchTimeDelay секунд
  28. yield return new WaitForSeconds(searchTimeDelay);
  29. }
  30. }

Согласен, спасибо за дополнение!

Добавить комментарий