Как заставить вертолет эвакуировать игрока с уровня?

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

Цель была крайне простая изначально: сделать так чтобы игрок подходил к зоне эвакуации, а там его бы ждал вертолет. Игрок бы в него садился и улетал с уровня.

Однако после более детальной проработки вопроса оказалось такое решение скучным в плане интереса - т.е. просто подбегаешь и улетаешь, нет драмы нет азарта.

Поразмыслив, решил усложнить логику работы зоны эвакуации:

  1. Входим в зону и вызываем вертолет
  2. Ждем его и сражаемся с зомби
  3. Побеждаем босса
  4. Прилетает вертолет
  5. Отстреливаясь от зомби вбегаем в него и улетаем
Как заставить вертолет эвакуировать игрока с уровня?

Сразу расскажу об одной хитрости: после пункта 1 никакой вертолет никуда не летит, т.к. время его прилета вполне себе точное, а вот сколько времени мы будем сражаться с врагами неизвестно. В итоге начинает лететь вертолет только после пункта 3.

Теперь, когда разобрались с логикой в общих чертах, приступим к реализации самого вертолета. Итак что мы знаем про вертолет?

  1. Он летает - значит должны крутиться винты
  2. Есть маршрут полета - должны быть точки через которые вертолет пролетает и место где он приземляется
  3. Вертолет очень заметная штука - должны быть столбы пыли и ветра в месте приземления
  4. У вертолета есть двери - значит они должны открываться
  5. У вертолета должен быть пилот

Начнем реализацию по пунктам:

1. В нашей модели вертолета винты должны быть отдельно от основной модельки, чтобы можно было их вращать. Если вдруг они приклеены к модели, то отделить их можно в такой программе как Blender.

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

[SerializeField] Transform rotor1; [SerializeField] Transform rotor2; private void FixedUpdate() { RotateRotors(); } void RotateRotors() { rotor1.Rotate(0, rotationSpeed * Time.deltaTime, 0); rotor2.Rotate(0, 0, rotationSpeed * Time.deltaTime); }

2. Маршрут полета представляет из себя массив обьектов типа Transform, которые мы создаем в редакторе Unity и расставляем как нам нужно на карте. Затем через [Serialize field] добавляем в наш скрипт. Таким же образом зададим вертолету скорость полета. При снижении эта скорость уменьшится в несколько раз. Предполагается, что весь маршрут вертолет летит с максимальной скоростью, а последние 3 точки проходит медленно, так как садится. В случае со взлетом делайте наоборот. Для обеспечения плавности движения используем фунцию Lerp. Переменная arrived будет отвечать за текущий статус полета, а onStartFlight пригодятся еще для его старта. currentPoint - текущее расположение вертолета.

[SerializeField] Transform[] flightPath; [SerializeField] float flightSpeed = 30; onStartFlight = false; arrived = false; int currentPoint = 1; private void FixedUpdate() { if ((!arrived)&&(onStartFlight)) { Flight(); } } void Flight() { if (currentPoint < flightPath.Length) { float distCovered = (Time.time - startTime) * flightSpeed; float journeyLength = Vector3.Distance(flightPath[currentPoint - 1].position, flightPath[currentPoint].position); float fractionOfJourney = distCovered / journeyLength; transform.position = Vector3.Lerp(flightPath[currentPoint - 1].position, flightPath[currentPoint].position, fractionOfJourney); transform.rotation = Quaternion.Lerp(flightPath[currentPoint - 1].rotation, flightPath[currentPoint].rotation, fractionOfJourney); if (Vector3.Distance(transform.position, flightPath[currentPoint].position) < 0.2f) // if arrived to next point { currentPoint++; startTime = Time.time; else if (currentPoint == flightPath.Length - 2) { flightSpeed = flightSpeed / 10; } } } else { arrived = true; } }

3. Пыль - очень крутая и важная вещь для вертолета. Включаться она должна когда вертолет заходит на посадку, в нашем случае после подлета к последним 3м точкам машрута. Сама пыль - это ParticleSystem из стандартного Unity ParticleSystems Asset. Через [Serialize Field] добавляем префаб пыли в наш скрипт. Теперь при подлете создаем его экземпляр в точке приземления. Точку для создания эффекта пыли тоже зададим через обьект [Serialize Field]. Вызов скрипта произведем дополнив скрипт функции, приведенной выше.

[SerializeField] GameObject dustEffect; [SerializeField] Transform dustEffectPoint; //код функции выше else if (currentPoint == flightPath.Length - 2) { flightSpeed = flightSpeed / 10; CreateDustEffect(); // <- здесь вызываем функцию } } } else { arrived = true; } } void CreateDustEffect() { dustEffectObj = Instantiate(dustEffect, dustEffectPoint.position, dustEffectPoint.rotation) as GameObject; }

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

Теперь через [Serialize Field] добавим их в наш скрипт. Через переменные Vector3 (x,y,z) добавим координаты закрытия и открытия. Самый простой способ узнать координату - поставить дверь в нужное положение и посмотреть координаты x,y,z в редакторе Unity в разделе Transform у двери. Сам процесс открытия реализуем с помощью функции Lerp.

Звук открытия тоже важен. Добавим к двери компонент AudioSource. И к нему добавим звук открытия. Я использовал звук открытия раздвижной двери из бесплатных звуков в интернете. С помощью функции Play() проиграем звук в нужный момент

Как заставить вертолет эвакуировать игрока с уровня?
[SerializeField] Transform doorLeft; [SerializeField] Transform doorRight; [SerializeField] Vector3 doorLeftOpen_pos; [SerializeField] Vector3 doorLeftClose_pos; [SerializeField] Vector3 doorRightOpen_pos; [SerializeField] Vector3 doorRightClose_pos; [SerializeField] float doorsSpeed = 0; bool isDoorsOpening = false; bool isDoorsOpen = false; private void FixedUpdate() { if (isDoorsOpening) { if (!isDoorsOpen) { OpenDoors(); } } } public void OnOpenDoors() { if (!isDoorsOpening) { isDoorsOpening = true; OpenDoorsAudioPlay(); } } void OpenDoors() { float distCovered = (Time.time - startTimeDoors) * doorsSpeed; float journeyLength = Vector3.Distance(doorLeft.position, doorLeftOpen_pos); float fractionOfJourney = distCovered / journeyLength; doorLeft.localPosition = Vector3.Lerp(doorLeft.localPosition, doorLeftOpen_pos, fractionOfJourney); doorRight.localPosition = Vector3.Lerp(doorRight.localPosition, doorRightOpen_pos, fractionOfJourney); if (Vector3.Distance(doorLeft.localPosition, doorLeftOpen_pos) < 0.01f) { isDoorsOpening = false; isDoorsOpen = true; } } void OpenDoorsAudioPlay() { doorLeft.GetComponent<AudioSource>().Play(); doorRight.GetComponent<AudioSource>().Play(); }

Теперь осталось только вызвать наш скрипт открытия в момент приземления вертолета. Для этого добавим вызов функции OnOpenDoors() в функцию Flight() в момент приземления.

else if (currentPoint == flightPath.Length - 2) { flightSpeed = flightSpeed / 10; CreateDustEffect(); } } } else { arrived = true; OnOpenDoors(); // <- здесь вызываем функцию } }

5. Не забудьте посадить пилота за руль, для этого возьмите модельку, ее можно взять бесплатно на сайте mixamo.com. Затем выберите на этом же сайте позу сидя и экспортируйте ее в Unity. Затем после импорта поместите ее за штурвал вертолета

Как заставить вертолет эвакуировать игрока с уровня?

Надеюсь моя статья вам понравилась и будет полезна в создании вашей собственной игры!

Как сделан вертолет в моей игре можно посмотреть тут:

1818
11 комментариев

Входим в зону и вызываем вертолетЖдем его и сражаемся с зомбиПобеждаем боссаПрилетает вертолетОтстреливаясь от зомби вбегаем в него и улетаем

Скучно
Лучше Босс и Вертолет должны появиться одновременно - но игрок должен прорываться сквозь боса к вертолту.
Но при этом игрок не должен знать точную точку прилета вертолета где он должен зависнуть.

5
Ответить

Комментарий недоступен

1
Ответить

Хороший наброс! у меня в игре реализовано похоже, здесь алгоритм для статьи немного упростил. В игре сначала прибегает босс, а пока с ним сражаешься прилетает вертолет, НО он зависает и не садится пока с боссом не разберешься. Еще вертолет при посадке может придавить игрока, если под ним стоять)

Ответить

Я немного не в тему , но что мешает засунуть босса до "Эвакуации" , а саму "Эвакуацию" сделать как в том же мгс V , мол добегаешь до верта и фигачишь зомбей с автомата или минигана

1
Ответить

Здесь описан один из вариантов, на 2м уровне босс встречается и до эвакуации. В игре просто зомби реализованы в виде волн, т.е. ходячих и агрящихся зомбей пока нет, поэтому прорываться через толпу на площади пока не получится)

1
Ответить

В Deep Rock Galactic гасить боссов это отдельная тема, с эвакуцией никак не связанная.

И в итоге - на одних ассетах есть несколько режимов игры. Так что я бы рекомендовал глянуть в сторону DRG (группа пребывает на вертолёте, вертолёт в условной сейфзоне, далее выполняют миссию на местности, отбиваясь от волн и сваливают на вертопрах)

1
Ответить