Уроки Unity3d - Скрипт FPSWalker

Для просмотра любого скрипта Unity, вам нужно открыть его в редакторе скриптов. Для этого нужно выбрать скрипт в окне проекта (Project), а затем дважды кликнуть на его значке (или нажать кнопку Edit, в Inspector-е), чтобы открыть скрипт для редактирования.
На PC, редактор скриптов по умолчанию называется Uniscite. Это автономное приложение, которое позволяет вам редактировать различные форматы текстового файла, JavaScript и C # пример двух таких форматов.
Вы можете использовать и другие, удобные для вас, текстовые редакторы, для написания скриптов Unity.

Открытие скрипта.

Выберете объект First Person Controller в окне Hierarchy, затем кликните на имени скрипта в компоненте FPSWalker (Script) в Inspector, строка выделится синим цветом:
Фото
Таким образом, скрипт в окне проекта (Project) выделиться желтым цветом (см. следующий рисунок), чтобы помочь вам найти его. Откройте его в редакторе скриптов.]
Фото

Windows PC—FPSWalker в Uniscite.

На PC, скрипт FPSWalker откроется в редакторе скриптов по умолчанию UniSciTE:
Фото
Закрепим полученные знания о скриптинге, разобрав скрипт FPSWalker:

Объявление переменных.
Как и большинство скриптов, FPSWalker начинается с объявления переменных в строках 1-6:

JavaScript:
var speed = 6.0;
var jumpSpeed = 8.0;
var gravity = 20.0;
private var moveDirection = Vector3.zero;
private var grounded : boolean = false;

В строках от 1 до 3 объявлены public переменные скрипта, которые будут использоваться в дальнейшем, как множители. Все три переменные имеют значение с плавающей точкой, поэтому это будет тип данных float (так как это простой пример скрипта от Unity Technologies, не у всех переменных определен тип данных). Строки 5 и 6 private переменные, поскольку они будут использоваться только в пределах скрипта. Private переменная moveDirection отвечает за хранение текущего направления движения игрока как Vector3 (X, Y, Z координаты). Vector3.zero - краткая форма для написания Vector3 (0, 0, 0).
Private переменная grounded имеет тип данных boolean (true или false). Эта переменная используется, для отслеживания стоит ли игрок на земле (поверхности), с тем чтобы позволить движение и прыжки, которые не были бы разрешены, если игрок в воздухе (то есть, если они в настоящее время прыгает).

Хранение информации движения.

В строке 8 начинается функция FixedUpdate (). Как и о функции Update(), о ней говорилось ранее – FixedUpdate() вызывается каждый кадр с фиксированной частотой кадров (called every fixed framerate frame).
Функция FixedUpdate() выполняется в диапазоне строк 8 - 27, таким образом, мы можем предположить, что все команды и условные операторы в пределах этой функции будут проверены каждый кадр.
В книги вы можете иногда заметить одну строку кода, разделенную на две, это сделано из-за нехватки места, объедините эту строку в вашем редакторе.

Первый условный оператор if в функции выполняется в строках 9 – 18 (комментарий разработчиков удален):

JavaScript:
if (grounded) {
	moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0,
	Input.GetAxis("Vertical"));
	moveDirection = transform.TransformDirection(moveDirection);
	moveDirection *= speed;
	if (Input.GetButton ("Jump")) {
		moveDirection.y = jumpSpeed;
	}
}

Все команды и вложенный условный оператор if (строка 15), будут выполнены, если переменная grounded будет равна true, т.к. ворожение в строке 9 – if (grounded) - можно записать следующим образом:

JavaScript:
if (grounded == true) {

Если переменная grounded истинна, производится три действия над переменной moveDirection (строки 11-13).
Во-первых, переменной moveDirection назначается новое значение Vector3, в котором Х = Input.GetAxis("Horizontal") , Y = 0, а Z = Input.GetAxis("Vertical").

JavaScript:
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical"));

В этом примере Unity Technologies использовало ключевое слово 'new' в качестве префикса для Vector3, при присвоении значения
переменной moveDirection. Сделано это для более простого преобразования кода из JavaScript в C #. Однако, это не является обязательным в JavaScript, поэтому вы не увидите использования 'new' в других примерах из этой книги.
Но что делать команда Input.GetAxis? Она возвращает значение между -1 и 1 в зависимости от нажатия горизонтальных или вертикальных клавиш, по умолчанию ими являются:
• A/D или Влево/Вправо — горизонтальная ось.
• W/S или Вверх/Вниз — вертикальная ось.
Если не нажата ни одна из перечисленных клавиш, Input.GetAxis будет возвращать 0. Если нажата клавиша Влево Input.GetAxis("Horizontal") вернет -1, когда Вправо вернет 1.

Иными словами, строка:

JavaScript:
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical"));

присваивает переменной moveDirection значение Vector3, где X и Z основаны на нажатиях клавиш, оставляя при этом Y равным 0.
Далее, в строке 12 наша переменная moveDirection вновь изменяется:

JavaScript:
moveDirection = transform.TransformDirection(moveDirection);

Здесь мы устанавливаем moveDirection в значение, основанном на TransformDirection компонента Transform. Команда TransformDirection преобразует локальные координаты XYZ в мировые. Так в этой строке, мы берем координаты XYZ moveDirection и преобразовываем их во внешние координаты. Вот почему в скобках после TransformDirection указана наша переменная moveDirection.
И под конец, в строке 13. умножим moveDirection на переменную speed:

JavaScript:
moveDirection *= speed;

Т.к. speed это public переменная, и мы можем редактировать ее значение в Inspector-е, а умножение moveDirection на public, пропорционально изменяет XYZ значения переменной moveDirection, следовательно, мы можем регулировать скорость передвижения персонажа, не изменяя скрипта. Это происходит потому, что полученное значение moveDirection, используются далее в скрипте для перемещения персонажа. Перед завершением условного оператора if(grounded), есть еще один вложенный условный оператор if, в строках 15-17:

JavaScript:
if (Input.GetButton ("Jump")) {
moveDirection.y = jumpSpeed;
}

Этот условный оператор отслеживает нажатие клавиши Jump (прижок). По умолчанию, прыжок (jump) назначен на пробел (Space bar). Как только эта клавиша нажата, Y составляющей переменной moveDirection присваивается значение jumpSpeed. Поэтому, если переменная jumpSpeed не была изменена в инспекторе свойств, moveDirection.y будет установлен в значение 8.0.
Далее в скрипте, когда мы будем перемещать персонажа, это резкое изменение от 0 до 8.0 даст эффект прыжка. А как же наш персонаж возвращения на землю? Объект нашего персонажа не имеет компонента Rigidbody, поэтому он не будет контролироваться силой тяжести физического движка.

Вот почему в 21 строке мы уменьшаем значение moveDirection.y:

JavaScript:
moveDirection.y -= gravity * Time.deltaTime;[code]Обратите внимание, что мы  не сразу опускаем персонажа  на землю,  и не просто отнимаем gravity  от moveDirection.y, т.к. это приведет  к нежелаемым эффектам,  а мы вычитания переменную gravity умноженную  на команду Time.deltaTime.
Умножение любого значения  в пределах функций Update () или FixedUpdate ()  на Time.deltaTime (время  в секундах, затраченное  на заполнение последнего кадра), избавляет вас  от зависимости основанной  на частоте кадров.  И так, написав:
[code]JavaScript:
moveDirection.y -= gravity * Time.deltaTime;

мы фактически вычитаем значение силы тяжести каждую секунду, а не каждый кадр.
Перемещение персонажа.
Moving the character.
Как говориться в комментарии на строке 23, строки 24-26 отвечают за движение персонажа.
Вначале, в 24 строке объявляется новая переменная controller и определяется ее тип данных CharacterController. После чего, при помощи команды GetComponent(),
переменной присваивается ссылка на компонент Character Controller:

JavaScript:
var controller : CharacterController =
GetComponent(CharacterController);

Используя GetComponent(), ы можете получить доступ к любому компоненту, прикрепленному к объекту (к которому прикреплен скрипт), просто указав в скобках его имя.
Теперь, когда у нас есть ссылка на компонент Character Controller, мы можем получить доступ к его параметрам, атак же использовать функцию Move, для перемещения объекта.
В строке 25 мы и происходит перемещение персонажа. Результат движения помещается в переменную flags:

JavaScript:
var flags = controller.Move(moveDirection * Time.deltaTime);

Функция CharacterController.Move принимает в качестве параметра Vector3, для это мы используем вектор moveDirection умноженный на Time.deltaTime (что бы скорость была метры в секунду, а не метры в кадр).

Столкновение с поверхностью.

Переменная moveDirection получает значения, только если логическая переменная grounded истинна (true). Так как же мы определяем, на земле мы или нет?
Сollider нашего персонажа (это Character Controller), как и любой другой collider-ы может обнаружить столкновение с другим объектом. Однако в отличии от стандартных collider – ов, Character Controller имеет четыре различных вида столкновения описанных в CollisionFlags. К ним относятся следующие:
• None
• Sides
• Above
• Below
Они отвечают за проверку столкновений, с определенной частью collider-а, который они описывают - за исключением None - это означает, что столкновения не происходит.
Эти флаги используются для установки нашей переменной grounded в строке 26:

JavaScript:
grounded = (flags & CollisionFlags.CollidedBelow) != 0;[code]Выражение может показаться сложным,  но это просто сокращенный способ проверки состояния  и установка значения  в одной строке.
В скобках мы используем логическую операцию - побитовое 'и' (&), что бы определить соответствует ли результат нашего движения flags значению CollidedBelow:
[code]JavaScript:
(flags & CollisionFlags.CollidedBelow)

Побитовое 'и' (&) выполняются для каждой пары бит своих операндов.
Если наш Character Controller действительно столкнулся нижней частью, результат выражения не будет равен 0. Что мы и проверяем дальше, используя операцию сравнения 'не равно' (!=). Следовательно когда наш персонаж на земле grounded будет равен true.

Команда @Script.

Функция FixedUpdate() заканчивается в 27 строке, и остается последняя команда в этом скрипте:

JavaScript:
@script RequireComponent(CharacterController)

@script команды используются для выполнения действий, которые обычно необходимо выполнять вручную в Unity Editor.

В этом примере, функция RequireComponent заставляет Unity добавить компонент, указанный в скобках, если объект, к которому прикреплен скрипт, не имеет данного компонента.
Так как наш скрипт использует CharacterController в коде, необходимо обязательное его присутствие в объекте.