Найти тему

Unity 3D. John Lemon's Jount. Part 11

Part 10 https://dzen.ru/a/Y8BLpxuB_AmQzxx0

Теперь давайте займемся скриптом горгульи.

Чтобы использовать созданный коллайдер-триггер ViewArea, нам необходимо завести логическую глобальную переменную, которая будет отвечать за нахождение кота в этой области. Если кот не в области зрения горгульи, что соответствует началу игры и моменту, когда кот выходит из области зрения горгульи, то переменная равна false. Если кот вошел в область зрения горгульи, то переменная становится равной true, то есть горгулья заметила кота и игра завершена проигрышем. Дополнительно мы должны проверять, что с триггером взаимодействует именно игровой объект кота, а не кого-то другого, например, приведения, бродящего по дому. Поэтому заведем еще переменную для определения персонажа игрока, которая в данном случае будет содержать не весь GameObject, а только его компонент Transform. Это упростит доступ к положению персонажа кота.

public Transform Player;

bool isPlayerRange;

Скрипт представлен на снимке ниже. Обратите внимание, что методы Start() и Update() в скрипте просто свернуты для удобства демонстрации, поскольку не содержат код.

Скрипт
Скрипт

В игре жанра стелс необходимо в первую очередь прятаться от врагов. Поэтому здорово, когда эти прятки реализованы с дополнительными элементами. Например, можно просто поставить горгулью на пустом пространстве - понятно, что кот в таком случае просто не сможет пройти незамеченным. А если поставить перед горгульей какие-то предметы, например, шкаф или высокие часы, то горгулья не заметит персонажа. В этом случае коллайдер кота может попасть в область видимости горгульи, но между ними будет какой-то объект. Поэтому для проигрыша важно убедиться, что линия прямой видимости горгульи и кота свободна и между ними нет никаких препятствий. Поскольку позиция персонажа игрока может измениться в любой момент, эта проверка должна происходить в каждом кадре, то есть в методе Update().

Проверять линию обзора имеет смысл только тогда, когда персонаж игрока действительно находится в пределах досягаемости, поэтому сначала мы проверим, что кот попал в область зрения горгульи и переменная isPlayerRange равна true.

if (isPlayerRange)

{

}

В Unity можно проверить, есть ли какие-то посторонние коллайдеры на пути линии, начинающейся из точки. Эта линия, начинающаяся из определенной точки, называется лучом (Ray). Проверка наличия коллайдеров вдоль этого луча называется Raycast . Лучу нужно задать исходную точку и направление.

Исходная точка — это просто позиция игрового объекта ViewArea, но определить направление немного сложнее.

Направление от игрового объекта ViewArea к объекту JohnLemon равно положению JohnLemon минус положение игрового объекта ViewArea. Но, если мы посмотрим на позицию Джона Лимона по оси Y, то она равна 0. Видеть ноги кота нам не достаточно, необходимо, чтобы горгулья могла видеть центр масс, поэтому к позиции кота необходимо добавить единицу по оси Y, то есть вектор (0, 1, 0), который в Unity обозначается как Vector3.up. Таким образом направление луча вычисляется следующим образом:

Vector3 direction = Player.position + Vector3.up - transform.position;

Теперь у нас есть исходная точка и направление и мы можем создать луч:

Ray ray = new Ray (transform.position, direction);

В этой строку мы создали новый (new) экземпляр луча (Ray), указав ему исходную точку (transform.position) и направление (direction).

Теперь, когда мы создали луч (Ray), мы можем выполнить проверку наличия коллайдеров по этому лучу (Rayscast). В Unity существует множество различных методов Raycast, которые отличаются необходимыми для работы параметрами, но все они имеют один обязательный параметра: им нужно определить луч, по которому происходит Raycast.

Самый простой вариант метода Raycast возвращает логическое значение, которое принимает значение true, когда он что-то находит, и false, когда ничего не находит. Поскольку он возвращает логическое значение, очень удобно помещать метод Raycast внутрь оператора if. Блок кода оператора if будет выполняться только в том случае, если Raycast на что-то наткнулся. Но есть проблема, как узнать с каким коллайдером столкнулся наш луч? Для этого есть более сложный метод Raycast, в котором используется выходной параметр out. Выходные параметры определяются внутри метода, в котором они используются и являются одним из результатов работы метода. В нашем случае метод Raycast не только вернет логическое значение, но и в выходном параметре укажет с каким коллайдером произошло столкновение. Параметр out имеет тип RaycastHit, поэтому нам понадобится локальная переменная этого типа:

RaycastHit raycastHit;

А метод Raycast будет выглядеть следующим образом:

if(Physics.Raycast(ray, out raycastHit))

{

}

После того, как мы выполнили проверку наличия коллайдеров вдоль луча, мы должны проверить, совпадает ли обнаруженный коллайдер с коллайдером кота:

if(raycastHit.collider.transform == Player)

{

}

Метод Update() теперь будет выглядеть следующим образом:

Метод Update()
Метод Update()

Если обнаруженный коллайдер совпадает с коллайдером кота, то нам нужно завершить игру проигрышем. Мы уже создали объекты и скрипт для завершения игры, но он содержит только один вариант концовки - выигрыш. Давайте вернемся к этому скрипту, который назывался GameEnding и добавим в него вариант окончания игры проигрыш.

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

Для начала давайте добавим переменную, которая будет отвечать за группу картинок проигрыша:

public CanvasGroup caughtImageCanvasGroup;

Метод EndLevel() отвечает за завершение игры, но сейчас в нем мы изменяем прозрачность группы картинок с выигрышем. Давайте сделаем входной параметр для этого метода, в котором будем передавать нужную группу в зависимости от того, как завершилась игра. Выглядеть это будет таким образом (жирным шрифтом выделены изменения):

void EndLevel(CanvasGroup imageCanvasGroup)

{

timer = timer + Time.deltaTime;

imageCanvasGroup.alpha = timer / FadeDuration;

if (timer > FadeDuration)

{

Application.Quit();

}

}

Теперь в методе Uodate() вызов метода EndLevel() подчеркивается красной волнистой чертой, что означает ошибку. Это правильно, потому что теперь в метод EndLevel() нам нужно передать группу изображений, для которой необходимо изменять прозрачность. В случае выигрыша, если персонаж дошел до выхода, необходимо передать в метод EndLevel() группу изображений выигрыша, которая связана с переменной exitImageCanvasGroup. Это будет выглядеть следующим образом:

if (isPlayerExit)

{

EndLevel(exitImageCanvasGroup);

}

Определим еще одну переменную, которая будет определять, пойман ли Джон Лимон или нет, причем изначально переменная равна false:

bool isPlayerCaught = false;

Теперь в методе Update() нам нужно добавить еще один вариант запуска окончания игры - это изменение прозрачности группы изображений проигрыша, когда переменная isPlayerCaught стала равна true:

if (isPlayerCaught)

{

EndLevel(caughtImageCanvasGroup);

}

Отлично, но переменная isPlayerCaught изначально равна false и никогда не принимает значение true. А значение true она должна принять в тот момент, когда горгулья "увидела" Джона Лимона. Но это же совсем другой скрипт ObserverController. То есть нам нужно из одного скрипта изменить параметр в другом скрипте. Как это сделать?..

Для начала давайте определимся, что и где изменять. В скрипте GameEnding у нас подготовлен параметр isPlayerCaught, и горгулья в этом скрипте никак не участвует. Но мы можем создать метод, который изменяет параметр isPlayerCaught:

public void CaughtPlayer()

{

isPlayerCaught = true;

}

Этот метод общедоступный с модификатором public, поэтому мы сможем его использовать в другом скрипте, например, скрипте горгульи.

Теперь у нас есть следующая логика: переменная isPlayerCaught изначальна равна false, затем в определенный момент мы вызываем метод CaughtPlayer(), который меняет значение переменной isPlayerCaught на true и в следeющий кадр в методе Update() срабатывает условие

if (isPlayerCaught), которое запускает процесс завершения игры с проигрышем. Осталось определить где и как запустить метод CaughtPlayer(). Запускать мы его должны в скрипте горгульи, поскольку только там мы знаем момент, когда горгулья засекла кота и этот момент у нас определяется условием:

if(raycastHit.collider.transform == Player)

{

}

Чтобы использовать общедоступные переменные или методы другого скрипта нам необходимо в скрипте горгульи определить переменную, которая будет иметь тип, соответствующий названию другого скрипта:

public GameEnding gameEnding;

Обратите внимание на тип переменной, он должен точно повторять название скрипта окончания игры! Это возможно, поскольку скрипт - это такой же компонент, как Transform, поэтому его название мы можем использовать в качестве типа переменной. У этой переменой через точку будут доступны все публичные переменные и методы скрипта, поэтому мы просто обращаемся к методу CaughtPlayer():

if(raycastHit.collider.transform == Player)

{

gameEnding.CaughtPlayer();

}

Скрипт окончания игры выглядит теперь так:

Скрипт окончания игры
Скрипт окончания игры
Скрипт окончания игры
Скрипт окончания игры

Метод OnTriggerEnter() никак не изменялся, поэтому он на изображениях не представлен. Остальные методы, которые изменялись, представлены.

Скрипт горгульи теперь выглядит так:

Скрипт горгульи
Скрипт горгульи

В скрипте горгульи на изображении представлено только одно изменение - вызов поражения в методе Update().

Теперь переходим в Unity и нам осталось создать группу изображений для проигрыша и связать общедоступные переменные с нужными объектами.

Чтобы создать группу изображений проигрыша разверните объект Canvas в иерархии объектов, щелкните правой кнопкой мыши по игровому объекту ExitImageBackground и выберите «Dublicate» в контекстном меню. Это создаст точную копию объекта. Переименуйте эту копию в CaughtImageBackground, а дочерний объект ExitImage в CaughtImage.

В окне Inspector вы должны увидеть, что компонент Image по-прежнему ссылается на Won Sprite. Это единственная настройка, которую вам нужно настроить. Нажмите кнопку выбора кружка рядом со свойством «Source Image» и выберите Sprite под названием Caught.

Создание группы изображений проигрыша
Создание группы изображений проигрыша

Теперь в игровом объекте GameEnding свяжите переменные для групп изображений с соответствующими объектами в иерархии объектов:

Привязка переменных
Привязка переменных

И в объекте ViewArea тоже нужно сделать привязку переменных:

Привязка переменных
Привязка переменных

Проверьте, что при попадании в область зрения горгульи Ваша игра завершается проигрышем, как на видео:

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

Теперь разместите горгулий по своим местам. Горгулью, с которой мы сейчас работали разместите в позиции (-15.2 , 0 , 0.8), а свойство Rotation измените на ( 0 , 135 , 0 ). Задайте ей имя Gargoyle (1).

Перенесите префаб горгульи на сцену еще раз и назовите новый объект Gargoyle (2). Установите свойство Position на (-2.6, 0, -8.5), а свойство Rotation измените на (0, 30, 0).

  • Создайте третью горгулью и назовите новый объект Gargoyle (3). Установите свойство Position на (-4.8, 0, 10.6 ), а свойство Rotation на (0, 30, 0).

Part 12 https://dzen.ru/a/Y8Url3jAUHI6SuH7