Вы находитесь на странице: 1из 72

Целые числа

 byte - предназначен для хранения целых чисел.


Диапазон чисел от 0 до 255, если число будет
большим 255 или меньшим 0 – выдастся ошибка;
 short - предназначен для хранения целых чисел.
Диапазон чисел от -32 768 до 32 767;
 ushort - предназначен для хранения целых
положительных чисел. Диапазон чисел от 0 до 65
535;
 int - предназначен для хранения целых чисел.
Диапазон чисел от -2147483648 до 2147483647;
 long - предназначен для хранения целых чисел.
Диапазон чисел от –9 223 372 036 854 775 808 до 9
223 372 036 854 775 807.
Числа с точкой
 float - для создания чисел с плавающей точкой.
Диапазон чисел от от -3.4*1038 до 3.4*1038;
 double - для создания чисел с плавающей точкой.
Диапазон чисел от от ±4.9*10-324 до ±1.8*10308.

Прочие типы данных


 bool - логический тип данных. Предназначен для
записи истинного (true) или ложного (false)
значения;
 char - тип данных для работы с символами.
Позволяет поместить в одинарных кавычках какой-
либо символ; Одинарные кавычки ‘ ‘
 string - тип данных для текста. В двойных
кавычках можно сохранить одно или множество
слов. Двойные кавычки “ “
Числа с точкой
 float - для создания чисел с плавающей точкой.
Диапазон чисел от от -3.4*1038 до 3.4*1038;
 double - для создания чисел с плавающей точкой.
Диапазон чисел от от ±4.9*10-324 до ±1.8*10308.

Для вызова переменной вы можете обратиться к ней по


имени. Чтобы записать данные в переменную с типом
float или double необходимо после числа дописать
букву f или d соответсвенно.

Как можно предположить, print() содержит


операции, которые выводят строку в панель
Console (Консоль).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HelloWorld : MonoBehaviour {

    // Use this for initialization
    void Start () {
        print ("Hello World");    
    }
    
    // Update is called once per frame
    void Update () {
        
    }
}
print ("Hello World");-выведит в консоль строку с текстом
"Hello World" Тоесть просто выведит в строку текст "Hello World" 
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HelloWorld : MonoBehaviour {
    // Use this for initialization
    void Start () {
        //print ("Hello World");    
    }
    
    // Update is called once per frame
    void Update () {
        print ("Hello World");    
    }
}

Start() и Update() — это две специальные функции в Unity-версии


С#. Start() вызывается один раз в первом кадре существования
объекта, a Update() вызывается в каждом кадре

Transform: компонент Transform задает местоположение, поворот и


масштаб игрового объекта. Это единственный компонент,
присутствующий во всех игровых объектах.

Cube (Mesh Filter): компонент Mesh Filter придает игровому объекту


трехмерную форму, которая моделируется как сетка (mesh) из
треугольнико

Box Collider: компонент Collider позволяет игровому объекту


Gameobject взаимодействовать с другими объектами, моделируя
действие законов физики

Mesh Renderer: в отличие от компонента Mesh Filter,


определяющего фактическую геометрию игрового объекта,
компонент визуализации Mesh Renderer обеспечивает визуальное
отображение этой геометрии.

Теперь добавим в игровой объект еще один компонент: твердое


тело Rigidbody. Пока объект Cube еще выбран в иерархии,
выберите в меню пункт Component > Physics > Rigidbody
Теперь добавим в игровой объект еще один компонент: твердое
тело Rigidbody. Пока объект Cube еще выбран в иерархии,
выберите в меню пункт Component > Physics > Rigidbody
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

 public class CubeSpawner : MonoBehaviour {
     public GameObject cubePrefabVar;

     // Используйте этот метод для инициализации
     void Start () {
         //Instantiate( cubePrefabVar );
         }
    
     // Update вызывается в каждом кадре
     void Update () {
        Instantiate( cubePrefabVar ); 
         }
    }
Выберите объект Ground в панели Scene (Сцена) или Hierarchy
(Иерархия), нажмите клавишу W, Е или R, чтобы переместить,
повернуть или изменить масштаб игрового объекта.

bool bravo; // Объявление переменной с именем bravo и типом


bool (логический)

int india; // Объявление переменной с именем india и типом int


(целочисленный)

float foxtrot; // Объявление переменной с именем foxtrot и типом


float (вещественный)

char сharlie // Объявление переменной с именем charlie и типом


char (символьный);
bravo = true;

india = 8;

foxtrot = 3.14f; // Символ f указывает, что литерал числа имеет тип


float, как описывается ниже charlie = 'с';

string theFirstLineOfHamlet = "Who’s there?";

Квадратные скобки и строки

string theFirstLineOfHamlet = "Who’s there?";

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


квадратные скобки:

char theCharW = theFirstLineOfHamlet[0]; // W - это 0-й символ


строки char theChart = theFirstLineOfHamlet[6]; // t - это 6-й символ
строки

Ключевое слово class определяет новый тип переменных, который


можно считать комбинацией переменных и функций.

Vector3 — очень распространенный тип данных для вычислений в


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

Vector3 position = new Vector3( 0.0f, 3.0f, 4.0f ); // Устанавливает


значения x, у и z
print( position.х ); // 0.0, Значение х экземпляра Vector3

print( position.у ); // 3.0, Значение у экземпляра Vector3

print( position.z ); // 4.0, Значение z экземпляра Vector3

print( position.magnitude );// 5.0, Расстояние экземпляра Vector3 от


0,0,0 другое название для magnitude - "length" (длина)

position.Normalize(); // Устанавливает величину magnitude


экземпляра position равной 1 в том смысле, что переменные х, у и z
экземпляра position теперь имеют значения [0.0, 0.6, 0.8]

print( Vector3.zero ); // (0,0,0), Краткая форма для: new Vector3( 0, 0,


0)

print( Vector3.one ); // ( (1,1,1), Краткая форма для: new Vector3( 1,


1, 1 )

print( Vector3.right ); // (1,0,0), Краткая форма для: new Vector3( 1, 0,


0)

print( Vector3.up ); // (0,1,0), Краткая форма для: new Vector3( 0, 1,


0)

print( Vector3.forward ); // (0,0,1), Краткая форма для: new


Vector3( 0, 0, 1 )

Vector3.Cross( v3a, v3b ); // Вычисляет векторное произведение


двух экземпляров Vector3

Vector3.Dot( v3a, v3b ); // Вычисляет скалярное произведение двух


экземпляров Vector3

Красный, зеленый и синий компоненты цвета в C# хранятся как


значения типа float в диапазоне от 0.0f до 1.0f, где 0.0f обозначает
отсутствие данного цвета, a 1.0f — максимальную его
интенсивность. Четвертое значение типа float с именем alpha
определяет прозрачность цвета типа Color. Цвет со значением
alpha, равным 0.0f, полностью прозрачен, а цвет со значением
alpha, равным 1.0f, полностью непрозрачен:

// Цвета определяются float-значениями красного, зеленого и


синего компонентов, а также альфа-канала

Color darkGreen = new Color( 0f, 0.25f, 0f ); // Если альфа-значение


не указано, оно по умолчанию получает значение 1 (полностью
непрозрачный цвет)

Color darkRedTranslucent = new Color( 0.25f, 0f, 0f, 0.5f );

Как видите, есть два разных способа определения цвета: один с


тремя параметрами (красный, зеленый и синий) и один — с
четырьмя (красный, зеленый, синий и альфа)

Все каналы цвета доступны через переменные экземпляра:

print( Color.yellow.г ); // 1, Красный компонент желтого цвета

print( Color.yellow.g ); // 0.92f, Зеленый компонент желтого цвета

print( Color.yellow.b ); // 0.016f, Синий компонент желтого цвета

print( Color.yellow.a ); // 1, Альфа-компонент желтого цвета

Некоторые цвета предопределены в Unity в виде статических


переменных класса:

// Основные цвета: красный, зеленый и синий

Color.red = new Color(1, 0, 0, 1); // Чистый красный

Color.green = new Color(0, 1, 0, 1); // Чистый зеленый

Color.blue = new Color(0, 0, 1, 1); // Чистый синий

// Вторичные цвета: циан, фуксин и желтый

Color.cyan = new Color(0, 1, 1, 1); // Циан, яркий сине-зеленый

Color.magenta = new Color(1, 0, 1, 1); // Фуксин, розово-фиолетовый


Color.yellow = new Color(1, 0.92f, 0.016f, 1); // Приятный для глаз
желтый

// Нетрудно догадаться, что стандартный желтый цвет можно


получить как new Color(1, 1, 0, 1), но, по мнению разработчиков
Unity, этот желтый смотрится лучше.

// Черный, белый и прозрачный

Color.black = new Color(0, 0, 0, 1); // Чистый черный

Color.white = new Color(1, 1, 1, 1); // Чистый белый

Color.gray = new Color(0.5f, 0.5f, 0.5f, 1) // Серый

Color.grey = new Color(0.5f, 0.5f, 0.5f, 1) // Британское написание


цвета gray (серый)

Color.clear = new Color(0, 0, 0, 0); // Полностью прозрачный

Экземпляры Quaternion определяют углы поворота так, чтобы


избежать складывания шарнирных соединений — проблемы,
характерной при использовании стандартного способа поворота
относительно осей X, Y, Z

Quaternion lookUp45Deg = Quaternion.Euler( -45f, 0f, 0f );

В случаях, подобных этому, функции Quaternion.Euler() передаются


три числа типа float — углы поворота в градусах относительно осей
X, Y и Z

Операция выше повернет камеру на -45° относительно красной оси


X, которая в результате будет смотреть на игровой мир в
положительном направлении вдоль оси Z под углом 45°.

Обратившись к переменной eulerAngles экземпляра Quaternion,


можно узнать углы эйлерова поворота объекта относительно осей в
виде экземпляра Vector3: print( lookUp45Deg.eulerAngles ); // ( -45,
0, 0 ), Эйлеров поворот

Mathf: библиотека математических функций

В действительности Mathf является не типом переменных, а


фантастически полезной библиотекой математических функций.

Mathf.Sin(x); // Вычисляет синус угла х

Mathf.Cos(x); // Также имеются функции .Tan(), .Asin(), .Acos()


и .Atan()

Mathf.Atan2( у, x ); // Возвращает угол поворота относительно оси Z,


на который нужно повернуть объект, смотрящий вдоль оси X,
лицом к точке х, у.

print(Mathf.PI); // 3.141593; отношение длины окружности к


диаметру

Mathf.Min( 2, 3, 1 ); // 1, наименьшее из трех чисел (float или int)

Mathf.Мах( 2, 3, 1 ); // 3, наибольшее из трех чисел (float или int)

Mathf.Round( 1.75f ); // 2, округление вверх или вниз до


ближайшего целого

Mathf.Ceil( 1.75f ); // 2, округление вверх до следующего большего


целого

Mathf.Floor( 1.75f ); // 1, округление вниз до следующего меньшего


целого

Mathf.Abs( -25 ); // 25, абсолютное значение числа -25

Mathf.Approximately( а, b ); // Сравнение двух значение float с


заданной точностью
Mathf.Approximately() — отличный инструмент, позволяющий
справиться с невысокой точностью типа float, потому что (в отличие
от оператора ==) возвращает true, если два значения float
настолько близки друг к другу, что неточность, свойственная типу
float, может заставить их выглядеть неравными.

Screen — еще одна библиотека, подобная Mathf, позволяющая


получить информацию об экране, на котором отображается игра.

print( Screen.width ); // Выведет ширину экрана в пикселах

print( Screen.height ); // Выведет высоту экрана в пикселах

SystemInfo предоставляет информацию об устройстве, на котором


выполняется игра, в том числе информацию об операционной
системе, количестве процессоров, графическом оборудовании и
многом другом.

print( SystemInfo.operatingSystem ); // Например: Mac OS X 10.8.5

GameObject: тип любого объекта в сцене

GameObject — базовый класс всех сущностей, присутствующих в


сценах Unity. Все объекты, которые вы видите на экране в игре
Unity, являются подклассами класса GameObject. Игровые объекты
GameObject могут содержать разные компоненты

GameObject gObj = new GameObject("MyGO"); // Создание нового


игрового объекта с именем MyGO

print( gObj.name ); // MyGO., имя игрового объекта gObj

Transform trans =
gObj.GetComponent<Transform>( ); // Определение
ссылки trans на компонент Transform объекта gObj

Transform trans2 = gObj.transform; // Сокращенный способ доступа к


тому же компоненту Transform
gObj.SetActive(false); // Деактивирует объект gObj, в результате он
становится невидимым и его код прекращает выполняться.

Метод gObj.GetComponent<Transform>( ), показанный здесь, играет


особую роль, позволяя получить доступ к любому компоненту,
присоединенному к игровому объекту GameObject. Иногда вам
будут встречаться методы с угловыми скобками < >, такие как
GetComponent< > ( ). Такие методы называют обобщенными,
потому что они способны работать с разными типами данных. В
случае с GetComponent<Transform>( ) используется тип данных
Transform, который сообщает методу GetComponent<>( ), что тот
должен отыскать компонент Transform в игровом объекте
GameObject и вернуть его вам. Аналогично можно получать любые
другие компоненты, подключенные к GameObject, указывая тип
компонента в угловых скобках вместо Transform.

Renderer rend = gObj.GetComponent<Renderer>(); // Вернет


компонент Renderer

Collider coll = gObj.GetComponent<Collider>(); // Вернет компонент


Collider

HelloWorld hwlnstance = gObj.GetComponent<HelloWorld>();

Как показано в третьей строке предыдущего листинга, с помощью


GetComponent< > () можно получить экземпляр любого класса С#,
присоединенный к игровому объекту GameObject. Если
предположить, что к объекту gObj присоединен сценарий
HelloWorld на C, тогда gObj.GetComponent<HelloWorld>() вернет
его. Этот прием несколько раз используется в примерах в этой
книге.

Transform: местоположение, поворот и масштаб


Transform — обязательный компонент, присутствующий во всех
игровых объектах. КомпонентTransform управляет важной
информацией об игровом объекте, такой как местоположение
(координаты игрового объекта), поворот (ориентация игрового
объекта) и масштаб (размер игрового объекта). Компонент
Transform отвечает также за отношения родитель— потомок в
панели Hierarchy (Иерархия). Когда один объект является потомком
другого, он перемещается вместе с родителем, если присоединен к
нему

MeshFilter: видимая модель


Компонент MeshFilter присоединяет к игровому объекту
трехмерную сетку, присутствующую в панели Project (Проект).
Чтобы увидеть модель на экране, к игровому объекту должны быть
присоединены оба компонента: MeshFilter, хранящий информацию
о фактической трехмерной сетке, и MeshRenderer, объединяющий
эту сетку с шейдером или материалом и отображающий
изображение на экране. MeshFilter создает поверхность игрового
объекта, a MeshRenderer определяет форму цвет и текстуру этой
поверхности.

Renderer: позволяет увидеть игровой объект


Компонент Renderer — в большинстве случаев MeshRenderer —
позволяет увидеть игровой объект в панелях Scene (Сцена) и Game
(Игра). MeshRenderer требует наличия MeshFilter с трехмерной
сеткой, а также хотя бы одного компонента Material.Компоненты
Material применяют текстуры к объектам. Компоненты Renderer
объединяют вместе MeshFilter, компонент(ы) Material и освещение,
чтобы показать игровой объект GameObject на экране.

Collider: физическое присутствие игрового объекта


Компонент Collider обеспечивает физическое присутствие объекта
GameObject в игровом мире и определяет момент столкновения с
другими объектами. В Unity имеется четыре вида компонентов
Collider, перечисленные ниже в порядке уменьшения скорости
работы.

Sphere Collider: шар, или сфера. Столкновения с этой формой


вычисляются быстрее всего.

Capsule Collider: цилиндр со сферами на обоих концах. Второй тип


по быстродействию.

Box Collider: сплошной прямоугольник. Удобно использовать для


моделирования коробок, ящиков и других предметов
прямоугольной формы.

Mesh Collider: коллайдер, имеющий форму трехмерной сетки. Это


удобный и очень точный коллайдер, но работает намного, намного
медленнее трех предыдущих. Кроме того, Mesh Collider сможет
обнаруживать столкновения с другими коллайдерами Mesh
Collider, только если установить его признак Convex в значение true.

Rigidbody: моделирование поведения физических тел


Компонент Rigidbody моделирует поведение игрового объекта с
учетом законов физики. Он пересчитывает ускорение и скорость
движения в каждом вызове FixedUpdate (обычно 50 раз в секунду),
обновляя местоположение и поворот компонента Transform с
течением времени. Он также использует компонент Collider для
определения столкновений с другими игровыми объектами. Кроме
того, компонент Rigidbody может моделировать действие сил
тяготения, сопротивления и др., таких как сила ветра или взрыва.
Установите переменную isKinematic этого компонента в значение
true, если хотите сами позиционировать игровой объект, без
моделирования физики, поддерживаемой компонентом Rigidbody.
Script: сценарии на С#, которые вы пишете
Все сценарии на C# также являются компонентами игрового
объекта. Одно из преимуществ принадлежности сценариев к
компонентам — возможность присоединить к игровому объекту
несколько сценариев, и она будет использована в некоторых
учебных примерах в части III.

В инспекторе имена классов и переменных отображаются не так,


как они записаны в сценариях на С#

Имя класса ScopeExample превращается в Scope Example (Script).

Имя переменной trueOrFalse превращается в True Or False.

Имя переменной graduationAge превращается в Graduation Age.

Имя переменной goldenRatio превращается в Golden Ratio.

Логические операции и условия


! (оператор НЕ)

Оператор ! (читаеться как “не”) меняет логическое значение на


противоположное. Ложь становиться истиной, а истина – ложью

print( !true ); // Выведет: false

print( !false ); // Выведет: true

print( !(!true) ); // Выведет: true (двойное отрицание значения true


дает true)

Иногда оператор ! называют оператором логического отрицания,


чтобы подчеркнуть отличие от оператора - (поразрядный оператор
НЕ), о котором рассказывается в разделе «Поразрядные логические
операторы и маски уровней» приложения Б «Полезные идеи».
&& (оператор И)

Оператор && возвращает true, только если оба операнда имеют


значение true:

print( false && false ); // false

print( false && true ); // false

print( true && false ); // false

print( true && true ); // true

|| (оператор ИЛИ)

Оператор || возвращает true, если хотя бы один из операндов


имеет значение true:

print( false || false ); // false

print( false || true ); // true

print( true || false ); // true

print( true || true ); // true

Существуют также логические операторы И и ИЛИ, выполняющие


вычисления по полной схеме (& и |) — они вычисляют оба
операнда независимо от значения первого.

Иногда | и & называют поразрядным ИЛИ и поразрядным И,


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

Часто бывает полезно объединить несколько логических операций


в одну строку:

bool tf = true || false && false;

В C# логические операции выполняются в следующем порядке:

! - NOT
& - И с полной схемой вычислений / поразрядное И

|- ИЛИ с полной схемой вычислений / поразрядное ИЛИ

&& - И

|| - ИЛИ

То есть предыдущая строка будет интерпретироваться


компилятором как

bool tf = true || ( false && false );

(true || false) && false даст в результате false), но фактически без


круглых скобок строка дает значение true!

Ассоциативность: ( а & b ) & с эквивалентно а & ( b & с )

Коммутативность: ( а & b ) эквивалентно ( b & а )

Дистрибутивность И перед ИЛИ: а & ( b | с ) эквивалентно ( а & b ) |


(а&с)

Дистрибутивность ИЛИ перед И: а | ( b & с ) эквивалентно ( а | b ) &


(а|с)

( а & b ) эквивалентно ! ( !а | !b )

( а | b ) эквивалентно ! ( !а & !b )

== (равно)

Оператор равенства проверяет равенство значений двух


переменных или эквивалентность литералов. Результатом является
логическое значение true или false

Начинающие программисты часто путают операторы присваивания


(=) и равенства (==).

bool f = false;

bool t = true;
print( f == t ); // выведет: false

print( f = t ); // выведет: true

int i0 = 10;

int i1 = 10;

int i2 = 20;

float f0 = 1.23f;

float f1 = 3.14f;

float f2 = Mathf.PI;

print( i0 == i1 ); // Выведет: True

print( i1 == i2 ); // Выведет: False

print( i2 == 20 ); // Выведет: True

print( f0 == f1 ); // Выведет: False

print( f0 == 1.23f ); // Выведет: True

print( f1 == f2 ); // Выведет: False

!= (не равно)

Оператор неравенства возвращает true, если два значения не


равны, и false, если равны.

print( 10 != 10 ); // Выведет: False

print( 10 != 20 ); // Выведет: True

print( 1.23f != 3.14f ); // Выведет: True

print( 1.23f != 1.23f ); // Выведет: False

print( 3.14f != Mathf.PI ); // Выведет: True


> (больше) и < (меньше)

Оператор > возвращает true, если значение слева больше значения


справа:

print( 10 > 10); // Выведет: False

print( 20 > 10); // Выведет: True

print( 1.23f > 3.14f ); // Выведет: False

print( 1.23f > 1.23f ); // Выведет: False

print( 3.14f > 1.23f ); // Выведет: True

Оператор < возвращает true, если значение слева меньше значения


справа:

print( 10 < 10); // Выведет: False

print( 20 < 10); // Выведет: False

print( 1.23f < 3.14f ); // Выведет: True

print( 1.23f < 1.23f ); // Выведет: False

print( 3.14f < 1.23f ); // Выведет: False

Сравнение объектов по ссылке с помощью >,<,>= и <= невозможно.

>= (больше или равно) и <= (меньше или равно)

Оператор >= возвращает true, если значение слева больше или


равно значению справа:

print( 10 >= 10 ); // Выведет: True

print( 10 >= 20 ); // Выведет: False

print( 1.23f >= 3.14f ); // Выведет: False

print( 1.23f >= 1.23f ); // Выведет: True


print( 3.14f >= 1.23f ); // Выведет: True

Оператор <= возвращает true, если значение слева меньше или


равно значению справа:

print( 10 <= 10 ); // Выведет: True

print( 10 <= 20 ); // Выведет: True

print( 1.23f <= 3.14f ); // Выведет: True

print( 1.23f <= 1.23f ); // Выведет: True

print( 3.14f <= 1.23f ); // Выведет: False

Инструкция if
Инструкция if выполняет код в фигурных скобках {}, только если
значение в круглых скобках () вычисляется как true:

if (true) {

print( "The code in the first if statement executed." );

if (false) {

print( "The code in the second if statement executed." );

// Этот код выведет: The code in the first if statement executed.

Для определения реакции игры на разные ситуации логические


операторы можно объединять с инструкциями if:

И конечно, инструкции if можно объединять с операторами


сравнения:
print( "3.14 is not equal to "+Mathf.PI+"." );

// оператор + можно использовать для конкатенации строк с


данными других типов. В этом случае данные других типов
преобразуются в строки.

Из предложений else можно также составлять цепочки:

Если какое-то из условий в цепочке if.. .else if.. .else вычисляется как
true, все остальные условия не проверяются (остальная часть
цепочки просто пропускается).

Для реализации более сложного поведения допускается


вкладывать инструкции if друг в друга:

инструкция switch проверяет только равенство;

инструкция switch выполняет сравнение только с одной


переменной;

инструкция switch сравнивает переменную только с литералами (но


не с другими переменными).

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

Цикл do...while: похож на цикл while, но выполняет проверку после


каждой итерации.

Цикл for: инструкция цикла включает выражение инициализации,


условие завершения цикла и выражение наращивания переменной
цикла. Это наиболее часто используемый вид цикла.

Цикл foreach: инструкция цикла автоматически выполняет


итерации по всем элементам перечисляемого объекта или
коллекции. Эта глава включает первую часть обсуждения
инструкции foreach, а другая часть обсуждения, более обширная,
приводиться в следующей главе как часть дискуссии о коллекциях в
C#, таких как списки и массивы.

Цикл while

Бесконечный цикл
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Loops : MonoBehaviour {

    // Use this for initialization
    void Start () {
        while (true) {
            print ("Loop");
        }
        
    }
    
    // Update is called once per frame
    void Update () {
        
    }
}

Более полезный цикл while


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Loops : MonoBehaviour {

    // Use this for initialization
    void Start () {
        int i = 0;
        while (i<3) {
            print ("Loop:" + i);
            i++;
        }
        
    }
    
    // Update is called once per frame
    void Update () {
        
    }
}

ОПЕРАТОРЫ ИНКРЕМЕНТА И ДЕКРЕМЕНТА


Оператор инкремента (++), который увеличивает значение
соответствующей переменной на 1.
Оператор декремента (--), уменьшающий значение
соответствующей переменной на 1.
Операторы инкремента и декремента можно помещать перед или
после имени переменной, но в этих случаях инструкции будут
работать по-разному
Разница в том, какое значение возвращается, начальное (i++) или
уже увеличенное (++i).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Loops : MonoBehaviour {
    // Use this for initialization
    void Start () {
        int i = 1;
        print (i); //Выведет: 1
        print(i++); //Выведет: 1
        print(i); //Выведет: 2
        print(++i); //Выведет: 3 
        }
        

    
    // Update is called once per frame
    void Update () {
        
    }
}
Цикл do...while

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Loops : MonoBehaviour {

    // Use this for initialization
    void Start () {
        int i = 10;
        do {
            print ("Loop: " + i);
        } while(i < 3);

        }
        

    
    // Update is called once per frame
    void Update () {
        
    }
}
Цикл for
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Loops : MonoBehaviour {

    // Use this for initialization
    void Start () {
        for (int i = 0; i < 3; i++) {
            print ("Loop: " + i);
        }

        }
        

    
    // Update is called once per frame
    void Update () {
        
    }
}

Структура цикла for требует указать допустимые выражение


инициализации, условное выражение и выражение итерации.

for (int i = 0; i < 3; i++) {

Выражение инициализации: int i = 0; 


Условное выражение: i < 3; 
Выражение итерации: i++

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Loops : MonoBehaviour {

    // Use this for initialization
    void Start () {
        for (int i = 5; i > 2; i--) {
            print ("Loop: " + i); 
        }

        }
        

    
    // Update is called once per frame
    void Update () {
        
    }
}

Этот пример выведет в панель Console (Консоль) следующие


строки:
Loop: 5
Loop: 4
Loop: 3

Цикл foreach
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Loops : MonoBehaviour {

    // Use this for initialization
    void Start () {
        string str = "Hello";
        foreach (char chr in str) {
            print (chr);
        }
        }
        

    
    // Update is called once per frame
    void Update () {
        
    }
}

В каждой итерации этот цикл будет выводить очередной символ из


строки str, как показано ниже:
H
e
l
l
o

Инструкции перехода в циклах


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

Инструкция break
Инструкция break может также использоваться в любых циклах для
преждевременного выхода из них.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Loops : MonoBehaviour {

    // Use this for initialization
    void Start () {
        for (int i = 0; i < 10; i++) {
            print (i);
            if (i == 3) {
                break;
            }
        }
        }
        

    
    // Update is called once per frame
    void Update () {
        
    }
}

Запустив этот код в Unity, вы получите вывод:


0
1
2
3

Примеры кода: Вывод в консоль:


for (int i = 0; i < 10; i++)  0
{ 1
            print (i); 2
            if (i == 3) { 3
                break;
            }
        }

int i = 0; 0
        while (true) { 1
            print (i); 2
            if (i > 2) break; 3
                i++;
 }
int i = 3; 3
        do { 2
            print (i);
            i--;
            if (i == 1)
break;
        } while (i > 0);
foreach (char c in "Hello") { H
            if (c == 'l') { e
                break;
            }
            print (c);
        }

Инструкция continue
Инструкция continue заставляет программу пропустить код,
оставшийся в теле цикла, и начать следующую итерацию.

Код: Вывод:
for (int i = 0; i <= 360; i++)  0
{ 90
            if (i % 90 != 0) { 180
                continue; 270
            } 360
            print (i);
        }

В предыдущем коде, всякий раз, когда выполняется условие i


%90 ! = 0 (то есть когда остаток от деления i/90 не равен нулю)

% - ОПЕРАТОР ДЕЛЕНИЯ ПО МОДУЛЮ


Оператор деления по модулю (%), он возвращает остаток от
деления двух чисел. Например, 12 % 10 вернет значение 2, потому
что остаток от деления 12/10 равен 2.
Коллекции в C#
Коллекция — это группа элементов, на которую можно сослаться
посредством единственной переменной.

Массив*: массив — это индексируемый, упорядоченный список


объектов. Определяя массив, вы должны задать его размер,
который нельзя изменить позднее, что отличает массив от более
гибкого типа List.
stringArray[0] = "Hello";
stringArray[1] = "World";
print (stringArray[0] + " " + stringArray[1]);//Выведет: Hello World

Список List*: тип List (или список) напоминает массив, но, в отличие
от последнего, его размер не фиксирован и лишь немного уступает
ему в производительности.

new List<T>( ) — объявляет новую коллекцию List с элементами


типа Т

Add(X) — добавляет объект X типа Т в конец List

Clear( ) — удаляет все объекты из List

Contains(X) — возвращает true, если объект X (типа Т) имеется в List

Count — свойство, возвращающее количество объектов в List

IndexOf(X) — возвращает числовой индекс объекта X в List. Если


объект X отсутствует в коллекции, возвращается -1

Remove (X) — удаляет объект X из List

RemoveAt(#) — удаляет из List объект с индексом #


Словарь*: словари позволяют хранить пары ключ-значение и
связывать объекты с определенными ключами. Словари
объявляются с двумя типами (с типом ключа и типом значения)

Добавлять и читать значения из словаря можно с помощью


квадратных скобок (например, dict[ "key" ]).

new Dictionary<Tkey, Tvalue>( ) — объявляет новый словарь


Dictionary с указанными типами ключей и значений

Add(TKey, Tvalue) — добавляет в словарь объект Tvalue с ключом


Ткеу

Clear() — удаляет все объекты из словаря

ContainsKey (ТКеу) — возвращает true, если ключ ТКеу имеется в


словаре

ContainsValue(TValue) — возвращает true, если значение TValue


имеется в словаре

Count — свойство, возвращающее количество пар ключ-значение в


словаре

Remove (ТКеу) — удаляет из словаря значение с ключом ТКеу

Очередь: упорядоченная коллекция, действующая по принципу


«первым пришел, первым ушел» (first-in, first-out, FIFO). Очередь
Queue.

Clear( ) — удаляет все объекты из очереди

Contains(X) — возвращает true, если объект X имеется в очереди

Count — свойство, возвращающее количество объектов в очереди

Dequeue( ) — удаляет объект из начала очереди и возвращает его


Enqueue(X) — добавляет объект X в конец очереди

Реек() — возвращает объект из начала очереди, не удаляя его

Стек: упорядоченная коллекция, действующая по принципу


«первым пришел, последним ушел» (first-in, last-out, FILO). Стек
Stack

Clear( ) — удаляет все объекты из стека

Contains(X) — возвращает true, если объект X имеется в стеке

Count — свойство, возвращающее количество объектов в стеке

Реек( ) — возвращает объект с вершины стека, не удаляя его

Рор( ) — удаляет и возвращает объект с вершины стека

Push(X)— добавляет объект X на вершину стека

В начало каждого сценария на C# Unity автоматически добавляет


три строки, начинающиеся со слова using:

using UnityEngine;

using System.Collections;

using System.Collections.Generic;

Каждая из этих строк using загружает библиотеку кода и дает


сценарию возможность использовать эти библиотеки. Первая
строка — самая важная для проектов Unity, так как она открывает
сценарию доступ ко всем стандартным объектам Unity, включая
MonoBehaviour, GameObject, Rigidbody, Transform и т. д.

Вторая строка позволяет сценарию использовать некоторые


нетипизированные коллекции, такие как ArrayList.
Нетипизированные коллекции могут одновременно хранить
данные разных типов

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


открывает доступ к нескольким обобщенным коллекциям, включая
List, Queue, Stack и Dictionary. Обобщенные коллекции являются
строго типизированными в том смысле, что могут храни элементы
только одного типа, указанного в угловых скобках.

public List<string> sList; — объявляет список List строк.

public List<GameObject> goList; — объявляет список List игровых


объектов GameObject.

public Dictionary<char, string> acronymDict; — объявляет словарь


Dictionary строковых значений с символьными ключами (например,
вы сможете использовать символ 'о' для доступа к строке "Okami").
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ListEx : MonoBehaviour {

    public List<string> sList;
    // Use this for initialization
    void Start () {
        sList = new List<string> ();
        sList.Add ("Experience");
        sList.Add ("is");
        sList.Add ("what");
        sList.Add ("you");
        sList.Add ("get");
        sList.Add ("when");
        sList.Add ("you");
        sList.Add ("don't");
        sList.Add ("get");
        sList.Add ("what");
        sList.Add ("you");
        sList.Add ("wanted");

        print ("sList Count = " + sList.Count);//sLis
t Count = 12
        print ( "The 0th element is: " + sList[0]); /
/The 0th element is: Experience
        print ( "The 1st element is: " + sList[1]); /
/The 1st element is: is
        print ( "The 3rd element is: " + sList[3]); /
/The 3rd element is: you
        print ( "The 8th element is: " + sList[8]); /
/The 8th element is: get

        string str = "";
        foreach( string sTemp in sList) {
            str += sTemp + " ";    
        }
        print (str); //Experience is what you get whe
n you don't get what you wanted 
    }
    
    // Update is called once per frame
    void Update () {
        
    }
}

Оператор присваивания сложения (+=)


Выражение, использующее оператор +=, такое как

x += y

эквивалентно

x=x+y
List
Свойства
Свойства возвращают информацию о списке List

Последний допустимый индекс в списке List всегда равен Count-1

Методы
Методы — это функции, позволяющие изменять список

sL.lnsert(2, "В.5"): вставит второй параметр ("B.5") в список sL как


элемент с индексом в первом параметре (2). Все последующие
элементы списка List сдвинутся к концу. В первом параметре
допускается передавать значения из диапазона от 0 до sL.Count.

Значения не из этого диапазона вызовут ошибку времени


выполнения.

Преобразование списка в массив


sL.ToArray( ): сгенерирует массив, содержащий все элементы из
списка sL. Тип нового массива будет соответствовать типу списка. В
данном случае вызов метода вернет новый массив строк [ "А", "В",
"С", "D" ].

Dictionary
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DictionaryEx : MonoBehaviour {
    public Dictionary<string,string> statesDict;
    // Use this for initialization
    void Start () {
       statesDict = new Dictionary<string,string> ();
        statesDict.Add ("MD", "Maryland");
        statesDict.Add ("TX", "Texas");
        statesDict.Add ("PA", "Pennsylvania");
        statesDict.Add ("CA", "California"); 
        statesDict.Add ("MI", "Michigan");

        print ("There are " + statesDict.Count + " el
ements in statesDict.");//There are 5 elements in sta
tesDict. 

        foreach (KeyValuePair<string,string> kvp in 
statesDict) {
            print (kvp.Key + ": " + kvp.Value);//MD:M
aryland TX:Texas PA:Pennsylvania ...
        }

        print ("MI is " + statesDict ["MI"]);//MI is 
Michigan

        statesDict ["BC"] = "British Columbia";

        foreach (string k in statesDict.Keys) {
            print (k + " is " + statesDict [k]);//BC 
is British Columbia MI is Michigan TX is Texas
        }
    }
    
    // Update is called once per frame
    void Update () {
        
    }
}

foreach (KeyValuePair<string,string> kvp in 
statesDict) {
            print (kvp.Key + ": " + kvp.Value);//MD:M
aryland TX:Texas PA:Pennsylvania ...
}
Для обхода элементов словаря можно использовать цикл foreach,
но переменная цикла в этом случае должна иметь тип
KeyValuePair<,>.Два типа в угловых скобках KeyValuePair<,> должны
совпадать с типами, указанными в объявлении переменной
словаря (в данном примере <string,string> ).

foreach (string k in statesDict.Keys) {
            print (k + " is " + statesDict [k]);//BC 
is British Columbia MI is Michigan TX is Texas
}

Для обхода элементов словаря в цикле foreach можно также


использовать метод Keys.

public Dictionary<int,string> dIS;

dIS = new Dictionary<int, string>();
        dIS[0] = "Zero";
        dIS[1] = "One";
        dIS[10] = "Ten";
        dIS[1234567890] = "A lot!";

Другой способ объявить и инициализировать тот же словарь:

public Dictionary<int,string> dIS;

dIS = new Dictionary<int, string> () {
            { 0, "Zero" },
            { 1, "One" },
            { 10, "Ten" },
            { 1234567890, "A lot!" }
        };
Массивы
Массив — простейший и самый быстрый тип коллекций. Для
работы с массивами не требуется импортировать дополнительные
библиотеки (инструкцией using), потому что они встроены в ядро
языка С#. Кроме того, массивы могут быть многомерными и
ступенчатыми, что иногда очень удобно.

Массивы имеют фиксированную длину, которая должна быть


определена при инициализации.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ArrayEx : MonoBehaviour {
    public string[] sArray;
    // Use this for initialization
    void Start () {
        sArray = new string[10];
        sArray[0] = "These";
        sArray[1] = "are";
        sArray[2] = "some";
        sArray[3] = "words";

        print ("The length of sArray is: " + sArray.L
ength);//The length of sArray is: 10

        string str = "";
        foreach (string sTemp in sArray) {
            str += "|" + sTemp; 
        }
        print (str);//|These|are|some|words||||||
    }
    
    // Update is called once per frame
    void         Update () {
        
    }
}

Обратите внимание: несмотря на то что переменная sArray


объявляется как массив, длина массива не указывается в
объявлении.

Для int [ ] или float [ ] значением по умолчанию является 0. Для


string [] и других сложных типов данных, таких как GameObject[],
все элементы массива заполняются значением null (которое
указывает на отсутствие значения).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ArrayEx : MonoBehaviour {
    public string[] sArray;
    // Use this for initialization
    void Start () {
        sArray = new string[10];
        sArray[0] = "These";
        sArray[1] = "are";
        sArray[2] = "some";
        sArray[3] = "words";

        print ("The length of sArray is: " + sArray.L
ength);//The length of sArray is: 10

        string str = "";
        foreach (string sTemp in sArray) {
            str += "|" + sTemp; 
            if (sTemp == null)
                break;
        }
        print (str);//|These|are|some|words|
    }
// Update is called once per frame
    void Update () {
        
    }
}

string[] sA = new string[] { "А", "В", "С", "D" };

// В результате получится массив: [ "А", "В", "С", "D" ]

Свойства
sA.Length: вернет общий размер массива. Учитываются все
элементы, независимо от того, было им присвоено какое-то
значение или они все еще хранят значение по умолчанию.

Статические методы
Статические методы массивов являются частью класса System.Array
(то есть определены в библиотеке System.Collections) и добавляют
в массивы некоторые возможности, свойственные спискам List.

System.Array.indexOf( sA, "С" ): найдет первый элемент в массиве sA


со строкой "С" и вернет его индекс.

Если искомое значение отсутствует в массиве, возвращается -1

System.Array.Resize( ref sA, 6 ): изменит размер массива. В первом


параметре этот метод принимает ссылку на экземпляр массива
(именно поэтому требуется использовать ключевое слово ref), а во
втором — новый размер.

Если во втором параметре передать новый размер меньше


текущего значения Length, лишние элементы в конце массива будут
отброшены(удаленны).

System.Array.Resize() не работает с многомерными массивами.


Преобразование массива в список List
List<string> sL = new List<string>( sA ): эта строка создаст список List
sL, содержащий копии элементов массива sA.

Для объявления, инициализации и заполнения списка List также


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

List<string> sL = new List<string>( new string[] { "А", "В", "C" } );

Эта строка объявляет, определяет и заполняет новый анонимный


массив string[ ], который тут же передается в вызов функции
new List<string>( )

Многомерные массивы
При работе с многомерными массивами в квадратных скобках
можно вместо одного использовать два или более индекса. Таким
способом можно создать двумерную таблицу с элементами-
ячейками.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Array2dEx : MonoBehaviour {

    public string[,] sArray2d;
    // Use this for initialization
    void Start () {
        sArray2d = new string[4,4];

        sArray2d[0,0] = "A";
        sArray2d[0,3] = "B"; 
        sArray2d[1,2] = "C";
        sArray2d[3,1] = "D";

        print ("The Length of sArray2d is: " + sArray
2d.Length);//The Length of sArray2d is: 16
    }

Как видите, свойство Length возвращает единственное целое число


даже для многомерных массивов. Оно просто отражает общее
количество элементов в массиве

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Array2dEx : MonoBehaviour {

    public string[,] sArray2d;
    // Use this for initialization
    void Start () {
        sArray2d = new string[4,4];

        sArray2d[0,0] = "A";
        sArray2d[0,3] = "B"; 
        sArray2d[1,2] = "C";
        sArray2d[3,1] = "D";

        print ("The Length of sArray2d is: " + sArray
2d.Length);//The Length of sArray2d is: 16
        string str = "";
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (sArray2d [i, j] != null) {
                    str += "|" + sArray2d [i, j];
                } else {
                    str += "|_";
                }
            }
            str += "|" + "\n";
        }
        print (str);
    }
    
    // Update is called once per frame
    void Update () {
        
    }
}

Этот сценарий выведет:

The Length of sArray2d is: 16

|A|_|_|B|
|_|_|C|_|
|_|_|_|_|
|_|D|_|_|

Строку "\n" компилятор C# воспринимает как один символ,


отмечающий начало новой строки. Он обеспечивает перенос строк
при выводе на экран.

Ступенчатые массивы
Ступенчатый массив — это массив массивов. Он напоминает
многомерный массив, но может иметь вложенные массивы разной
длины.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class JaggedArrayEx : MonoBehaviour {
    public string[][] jArray;
    // Use this for initialization
    void Start () {
        jArray = new string[4][];

        jArray[0] = new string[4];
        jArray[0][0] = "A";
        jArray[0][1] = "B";
        jArray[0][2] = "C";
        jArray[0][3] = "D";

        //Примеры инициализации массива в одной строк
е
        jArray[1] = new string[] {"E", "F", "G"};
        jArray[2] = new string[] { "H", "I" };

        jArray[3] = new string[4];
        jArray[3][0] = "J";
        jArray[3][3] = "K";

        print ("The Length of jArray is: " + jArray.L
ength);
        //Выведет: The Length of jArray is: 4

        print ("The Length of jArray[1] is: " + jArra
y [1].Length);
        //Выведет: The Length of jArray[1] is: 3

        string str = "";
        foreach (string[] sArray in jArray) {
            foreach (string sTemp in sArray) {
                if (sTemp != null) {
                    str += " | " + sTemp;
                } else {
                    str += " | ";
                }
            }
            str += " | \n";
        }
        print(str);
    }    
    
    // Update is called once per frame
    void Update () {
        
    }
}

Этот сценарий выведет:

The Length of jArray is: 4

The Length of jArray[1] is: 3

|A|B|C|D|

|E|F|G|

|H|I|

|J| | |K|

Если string[] — это коллекция строк, то string[ ][ ] — это коллекция


массивов строк (массивов типа string[ ]).
print ("The Length of jArray is: " + jArray.Length);
//Выведет: The Length of jArray is: 4

Так как jArray — это массив массивов (а не многомерный массив),


jArray.Length подсчитывает количество элементов, доступных
посредством первой пары квадратных скобок (то есть четыре
вложенных массива).
Обход ступенчатых массивов с помощью for вместо
foreach
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class JaggedArrayEx : MonoBehaviour {
    public string[][] jArray;
    // Use this for initialization
    void Start () {
        jArray = new string[4][];

        jArray[0] = new string[4];
        jArray[0][0] = "A";
        jArray[0][1] = "B";
        jArray[0][2] = "C";
        jArray[0][3] = "D";

        //Примеры инициализации массива в одной строк
е
        jArray[1] = new string[] {"E", "F", "G"};
        jArray[2] = new string[] { "H", "I" };

        jArray[3] = new string[4];
        jArray[3][0] = "J";
        jArray[3][3] = "K";

        print ("The Length of jArray is: " + jArray.L
ength);
        //Выведет: The Length of jArray is: 4

        print ("The Length of jArray[1] is: " + jArra
y [1].Length);
        //Выведет: The Length of jArray[1] is: 3

        string str = "";
        for (int i = 0; i < jArray.Length; i++) {
            for (int j = 0; j < jArray [i].Length; j+
+) {
                if (jArray [i] [j] != null) {
                    str += " | " + jArray [i] [j];
                } else {
                    str += " | ";
                }
            }
            str += " | \n";
        }
        print (str);
    }    
    
    // Update is called once per frame
    void Update () {
        
    }
}

Этот сценарий выведет:

The Length of jArray is: 4

The Length of jArray[1] is: 3

|A|B|C|D|

|E|F|G|

|H|I|

|J| | |K|
Ступенчатые списки
Также возможно создать ступенчатый список List. Ступенчатый
двумерный список строк можно объявить так: List<List<string>>
jaggedStringList. По аналогии со ступенчатыми массивами,
вложенные списки получают значение по умолчанию null, поэтому
их нужно инициализировать при добавлении
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class JaggedListTest : MonoBehaviour {
    public List<List<string>> jaggedList;

    // Используйте этот метод для инициализации
    void Start () {
        jaggedList = new List<List<string>>();

        //  Добавить два списка List<string> в jagged
List
        jaggedList.Add( new List<string>() );
        jaggedList.Add (new List<string> ());

        // Добавить две строки в jaggedList[0]
        jaggedList[0].Add ("Hello");
        jaggedList[0].Add ("World");

        // Добавить третий список List<string> в jagg
edList, включая данные
        jaggedList.Add ( new List<string>(new string[
] {"complex", "initialization"}) );

        string str = "";
        foreach (List<string> sL in jaggedList) {
            foreach (string sTemp in sL) {
                if (sTemp != null) {
                    str += " | " + sTemp;
                } else {
                    str += " | ";
                }
            }
            str += " | \n";
        }
        print (str);
    }
    
    // Update is called once per frame
    void Update () {
        
    }
}

Этот сценарий выведет:

| Hello | World |

| complex | initialization |

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class JaggedListTest : MonoBehaviour {
    public List<List<string>> jaggedList;

    // Используйте этот метод для инициализации
    void Start () {
        jaggedList = new List<List<string>>();

        //  Добавить два списка List<string> в jagged
List
        jaggedList.Add(new List<string>());
        jaggedList.Add(new List<string>());

        // Добавить две строки в jaggedList[0]
        jaggedList[0].Add ("Hello");
        jaggedList[0].Add ("World");

        // Добавить третий список List<string> в jagg
edList, включая данные
        jaggedList.Add ( new List<string>(new string[
] {"complex", "initialization"}) );

        string str = "";
        for (int i = 0; i < jaggedList.Count; i++) {
            for (int j = 0; j < jaggedList[i].Count; 
j++) {
                if (jaggedList[i][j] != null) {
                    str += " | " + jaggedList[i][j];
                } else {
                    str += " | ";
                }
            }
            str += " | \n";
        }
        print (str);
    }
    
    // Update is called once per frame
    void Update () {
        
    }
}
Этот сценарий выведет:

| Hello | World |

| complex | initialization |

Когда использовать массивы или списки


 Списки легко изменяют свою длину, тогда как с массивами
проделать это намного сложнее
 Массивы работают быстрее, но ненамного
 Массивы поддерживают многомерные индексы
 Массивы допускают наличие пустых элементов в середине
коллекции

Списки проще в реализации и менее строги (благодаря


гибкому изменению длины). Это особенно актуально при
разработке прототипов игр, когда гибкость особенно важна

Оператор *=
Умножает значение переменной или свойства на значение
выражения и присваивает результат переменной или
свойству.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CubeSpawner3 : MonoBehaviour {
    public GameObject cubePrefabVar;
    public List<GameObject> gameObjectList; //Будет х
ранить все кубики
    public float scalingFactor = 0.95f;
    // ^ Коэффициент изменения масштаба каждого кубик
а в каждом кадре
    public int numCubes = 0; //Общее количество кубик
ов

    // Используйте этот метод для инициализации
    void Start () {
        // Инициализация списка List<GameObject>
        gameObjectList = new List<GameObject>();
    }
    
    // Update вызывается в каждом кадре
    void Update () {
        numCubes++; //Увеличить количество кубиков  /
/ a

        GameObject gObj = Instantiate<GameObject> (cu
bePrefabVar); // b

        // Следующие строки устанавливают некоторые з
начения в новом кубике
        gObj.name = "Cube " +numCubes; // c
        Color c = new Color (Random.value, Random.val
ue, Random.value); // d
        gObj.GetComponent<Renderer>().material.color 
= c;
        // ^ Получить компонент Renderer из gObj и на
значить случайный цвет
        gObj.transform.position = Random.insideUnitSp
here; // e

        gameObjectList.Add (gObj); //Добавить gObj в 
список кубиков

        List<GameObject> removeList = new List<GameOb
ject> (); // f
        // ^ Список removeList будет хранить кубики, 
подлежащие удалению из списка gameObjectList

        // Обход кубиков в gameObjectList
        foreach (GameObject goTemp in gameObjectList)
{ // g 

            // Получить масштаб кубика
            float scale = goTemp.transform.localScale
.x; // h
            scale *= scalingFactor; // Умножить на ко
эффициент scalingFactor
            goTemp.transform.localScale = Vector3.one 
* scale;

            if (scale <= 0.1f) { //Если масштаб меньш
е 0.1f... // i
                removeList.Add (goTemp); //...добавит
ь кубик в removeList
            }
        }
        foreach (GameObject goTemp in removeList) { /
/ g
            gameObjectList.Remove (goTemp); // j
            // ^ Удалить кубик из gameObjectList
            Destroy (goTemp); // Удалить игровой объе
кт кубика
        }
    }
}
Функции и параметры

Функция — это фрагмент кода, выполняющий некоторые действия.

Чтобы подсчитать количество вызовов функции Update(), можно


создать новый сценарий на C# со следующим кодом
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    public int numTimesCalled = 0;

    void Update () {
        numTimesCalled++;
        PrintUpdates();
    }

    void PrintUpdates() {
        string outputMessage = "Updates: " + numTimes
Called;
        print (outputMessage); // Пример вывода: "Upd
ates: 1"
}

Void — это тип значения, возвращаемого функцией, в данном


случае функция ничего не возвращает

Строки 13-16 все вместе определяют функцию. Все строки в коде


между открывающей фигурной скобкой { в строке 13 и
закрывающей } в строке 16 являются частью определения
PrintUpdates( ).
Функции инкапсулируют действия: функцию можно считать
именованной коллекцией строк кода. Эти строки выполняются
каждый раз, когда вызывается функция.

Функции создают свою область видимости: переменные,


объявленные внутри функции, имеют область видимости,
ограниченную телом этой функции. В таких случаях говорят, что
«outputMessage видима только в функции PrintUpdates()» или
«outputMessage является локальной для функции PrintUpdates()».

Чтобы подсчитать количество вызовов функции Update(), можно


создать новый сценарий на C# со следующим кодом
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    public int numTimesCalled = 0;

    void Update () {
        PrintUpdates();
    }

    void PrintUpdates() {
        numTimesCalled++;
        print ("Updates: " + numTimesCalled); //Приме
р: "Updates: 5"
        }
}

Этот сценарий выведет:

Updates: 1

Updates: 2
Updates: 3

Updates: 4

Updates: 5

…………………

Параметры и аргументы функций


Когда функция предполагает получение информации извне, тип
этой информации определяется объявлением одного или
нескольких параметров, которые создают локальные переменные
функции (указанного типа). В строке 10 в следующем листинге, void
Say ( string sayThis ), объявляется параметр с именем sayThis типа
string. sayThis можно использовать внутри функции Say( ) как
обычную локальную переменную.

Когда информация посылается в функцию через ее параметры,


говорят, что информация передается в функцию. Любое значение,
переданное в параметре, называется аргументом. Строка 7 в
следующем листинге вызывает функцию Say( ) с аргументом
"Hello". Также можно сказать, что значение "Hello" передается в
функцию Say( ). Передаваемый аргумент должен соответствовать
параметру функции, иначе возникнет ошибка
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    void Awake() {
        Say ("Hello"); // 7
    }
    
void Say( string sayThis) { // 10
        print (sayThis);
    }
}

Метод Update( ) каждого игрового объекта GameObject вызывается


в каждом кадре, а метод Start( ) — один раз, непосредственно
перед первым вызовом Update( )

Awake( ). Он вызывается один раз, так же как метод Start( ), но


вызов его происходит непосредственно в момент создания
игрового объекта. То есть вызов метода Awake( ) каждого игрового
объекта всегда происходит непосредственно перед Start( ).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
void Awake() {        
        PrintGameObjectName(this.gameObject);
        SetColor(Color.red, this.gameObject);
    }

void PrintGameObjectName( GameObject go ) {
        print (go.name);
    }

void SetColor(Color c, GameObject go) {
        Renderer r = go.GetComponent<Renderer>();
        r.material.color = c;
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    public GameObject cube;
    void Awake() {
        GameObject gObj = Instantiate<GameObject> (cu
be);
        gObj.name = "CUBE";
        PrintGameObjectName(gObj);
        SetColor(Color.red, gObj);
    }

    void PrintGameObjectName( GameObject go ) {
        print (go.name);
    }

    void SetColor(Color c, GameObject go) {
        Renderer r = go.GetComponent<Renderer>();
        r.material.color = c;
    }
}

Создаст красный кубик с именем "CUBE"


Возвращаемые значения
Кроме приема входных значений в параметрах функции могут
также возвращать единственное значение — результат функции,
как показано в строке 13 следующего листинга:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    void Awake() {        
        int num = Add(2, 5);
        print(num);
    }

    int Add(int numA, int numB) {
        int sum = numA + numB;
        return(sum);
    }

Этот сценарий выведет:

В этом примере функция Add( ) имеет два параметра,


целочисленные numA и numB. Она складывает два целых числа,
переданных ей, и возвращает результат. Слово int в начале
объявления функции в строке 11 указывает, что Add( ) возвращает
целое число в результате. Так же как, объявляя переменную, вы
должны указать ее тип, объявляя функцию, вы должны указать тип
возвращаемого ею результата.
Возвращаемое значение void
Большинство функций, написанных нами до сих пор, имели
возвращаемое значение типа void, то есть не возвращали ничего.
Даже при том, что эти функции ничего не возвращают, внутри них
иногда нужно вызвать инструкцию return. Инструкция return
используется внутри функции, чтобы прервать ее выполнение и
вернуть управление обратно в строку, откуда эта функция была
вызвана. (Например, инструкция return в строке 16 в следующем
листинге вернет управление в строку 9.)

Иногда бывает полезно выйти из функции, пропустив оставшийся


код.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    public List<GameObject> reallyLongList; // Опреде
ляется в инспекторе // а

    void Awake() {
        MoveToOrigin("Phil"); //b
    }

    void MoveToOrigin(string theName) {
        foreach (GameObject go in reallyLongList) { /
/c
            if (go.name == theName) { //d
                go.transform.position = Vector3.zero; 
//e
                return; //f
            }
        }
    } 
Этот сценарий найдёт в списке reallyLongList игровой объект
GameObject с именем "Phil" с помощью цикла foreach и изменит
его местоположение на точку [0,0,0] после чего завершит
выполнение функции MoveToOrigin() и вернет управление в строку
9 при помощи return

Зачем нужны функции?


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

Функция AlignX( ) в следующем листинге принимает три параметра


с игровыми объектами, вычисляет среднее значение их
координаты X и назначает им всем это среднее значение
координаты X:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
        void Awake() {
        
        }
    void AlignX(GameObject go0, GameObject go1, GameO
bject go2) {
        float avgX = go0.transform.position.x;
        avgX += go1.transform.position.x;
        avgX += go2.transform.position.x;
        avgX = avgX / 3.0f;

        Vector3 tempPos;
        tempPos = go0.transform.position;
        tempPos.x = avgX;
        go0.transform.position = tempPos;

        tempPos = go1.transform.position;
        tempPos.x = avgX;
        go1.transform.position = tempPos;

        tempPos = go2.transform.position;
        tempPos.x = avgX;
        go2.transform.position = tempPos;
    }
    } 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    public GameObject g1;
    public GameObject g2;
    public GameObject g0;
    void Awake() {
        AlignX(g0,g1,g2);
        }
    void AlignX(GameObject go0, GameObject go1, GameO
bject go2) {
        float avgX = go0.transform.position.x;
        avgX += go1.transform.position.x;
        avgX += go2.transform.position.x;
        avgX = avgX / 3.0f;

        Vector3 tempPos;
        tempPos = go0.transform.position;
        tempPos.x = avgX;
        go0.transform.position = tempPos;
        tempPos = go1.transform.position;
        tempPos.x = avgX;
        go1.transform.position = tempPos;

        tempPos = go2.transform.position;
        tempPos.x = avgX;
        go2.transform.position = tempPos;
    }
    } 

В строках 13-15 можно видеть, как преодолевается ограничение


Unity, не позволяющее напрямую изменять значение position.х
компонента transform. Для этого нужно сначала скопировать
текущие координаты в другую переменную (например, Vector3
tempPos), затем изменить значение х и, наконец, скопировать весь
вектор Vector3 обратно в transform.position. Функция SetX( )
позволяет установить координату х компонента transform за один
шаг (например, SetX( this.gameObject, 25.0f ) ).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {    
void Awake() {
       
        }
    void AlignX(GameObject go0, GameObject go1, GameO
bject go2) {
        float avgX = go0.transform.position.x;
        avgX += go1.transform.position.x;
        avgX += go2.transform.position.x;
        avgX = avgX / 3.0f;
        SetX(go0, avgX);
        SetX(go1, avgX);
        SetX(go2, avgX);
    } 

    void SetX( GameObject go, float eX) {
        Vector3 tempPos = go.transform.position;
        tempPos.x = eX;
        go.transform.position = tempPos;
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    public GameObject g1;
    public GameObject g2;
    public GameObject g0;
    void Awake() {
        AlignX(g0,g1,g2);
        }
    void AlignX(GameObject go0, GameObject go1, GameO
bject go2) {
        float avgX = go0.transform.position.x;
        avgX += go1.transform.position.x;
        avgX += go2.transform.position.x;
        avgX = avgX / 3.0f;

        SetX(go0, avgX);
        SetX(go1, avgX);
        SetX(go2, avgX);
    } 
    void SetX( GameObject go, float eX) {
        Vector3 tempPos = go.transform.position;
        tempPos.x = eX;
        go.transform.position = tempPos;
    }
}

Перегрузка функций
Перегрузка функций — причудливый термин, описывающий
возможность функций в C# действовать по-разному в зависимости
от типов и количества передаваемых им параметров. В следующем
листинге жирным выделены фрагменты, демонстрирующие
перегрузку функций.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    void Awake() {
        print( Add(1.0f, 2.5f));
        // ^ Выведет: "3.5"    
        print( Add( new Vector3(1, 0, 0), new Vector3
(0, 1, 0)));
        // ^ Выведет "(1.0, 1.0, 0.0)"
        Color colorA = new Color(0.5f, 1, 0, 1);
        Color colorB = new Color(0.25f, 0.33f, 0, 1);
        print( Add(colorA, colorB ));
        // ^ Выведет "RGBA(0.750, 1.000, 0.000, 1.000
)"
    }

    float Add( float f0, float f1 ) { // a
        return(f0 + f1);
    }
    Vector3 Add( Vector3 v0, Vector3 v1 ) { // a
        return(v0 + v1);
    }

    Color Add( Color c0, Color c1 ) { // a
        float r, g, b, a;
        r = Mathf.Min(c0.r + c1.r, 1.0f); // b
        g = Mathf.Min(c0.g + c1.g, 1.0f); // b
        b = Mathf.Min(c0.b + c1.b, 1.0f); // b
        a = Mathf.Min(c0.a + c1.a, 1.0f); // b
        return(new Color(r, g, b, a));
    }
}

Этот сценарий выведет:

3.5

(1.0, 1.0, 0.0)

RGBA(0.750, 1.000, 0.000, 1.000)

В этом листинге объявляются и определяются три разные функции


Add( ), вызываемая версия в каждом случае определяется
параметрами, переданными в вызов. Когда функции передаются
два числа с плавающей точкой, вызывается версия Add( ),
складывающая вещественные числа; когда передаются два вектора
Vector3, вызывается версия, складывающая векторы; а когда
передаются два значения типа Color, вызывается версия,
складывающая два цвета.

Необязательные параметры
Иногда желательно, чтобы функция имела необязательные
параметры, которые могут передаваться или не передаваться. В
следующем листинге параметр еХ функции SetX( ) является
необязательным. Если задать значение по умолчанию для
параметра в определении функции, компилятор будет
интерпретировать его как необязательный (как, например, в строке
13 в следующем листинге, где параметр еХ получает значение по
умолчанию 0,0f).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    void Awake() {
        SetX(this.gameObject, 25 ); // b
        print(this.gameObject.transform.position.x ); 
// Выведет: "25"
        SetX( this.gameObject ); // c 
        print(this.gameObject.transform.position.x ); 
//Выведет: "0"
    }

    void SetX( GameObject go, float eX = 0.0f ) { // 
a
        Vector3 tempPos = go.transform.position;
        tempPos.x = eX;
        go.transform.position = tempPos;
    }
}

Параметр еХ определен как необязательный co значением по


умолчанию 0,0f. Определение значения по умолчанию для
параметра еХ в объявлении функции (часть =0.0f) делает параметр
еХ необязательным. Если вызвать функцию без аргумента для
параметра еХ, он получит значение 0,0f.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    public GameObject gObj;
    void Awake() {
        SetX(gObj, 25 ); // b
        print(gObj.transform.position.x ); // Выведет
: "25"
        SetX( gObj ); // c 
        print(gObj.transform.position.x ); //Выведет: 
"0"
    }

    void SetX( GameObject go, float eX = 0.0f ) { // 
a
        Vector3 tempPos = go.transform.position;
        tempPos.x = eX;
        go.transform.position = tempPos;
    }
}

Этот сценарий выведет:

25

Необязательные параметры всегда должны следовать в


объявлении функции после всех обязательных параметров.

Ключевое слово params


Как показано в следующем листинге, в строке 13, с помощью
ключевого слова params можно позволить функции принимать
произвольное количество параметров одного типа. Эти параметры
преобразуются в массив указанного типа. Фрагменты, выделенные
жирным, демонстрируют применение ключевого слова params.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    void Awake() {
        print(Add(1)); // Выведет: "1"
        print(Add(1,2)); // Выведет: "3"
        print(Add(1,2,3)); // Выведет: "6"
        print(Add(1,2,3,4)); // Выведет: "10"
    }

    int Add( params int[] ints ) {
        int sum = 0;
        foreach (int i in ints) {
            sum += i;
        }
        return(sum);
    }
}

Этот сценарий выведет:

10
Теперь функция Add() может принимать любое количество целых
чисел и возвращать их сумму Подобно необязательным
параметрам, список params должен следовать в объявлении
функции после всех обязательных параметров (то есть все
обязательные параметры должны быть объявлены перед списком
params).

Это ключевое слово позволяет также переписать предыдущую


функцию AlignX(), чтобы она принимала любое количество игровых
объектов, как показано в следующем листинге.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    void AlignX( params GameObject[] goArray ) { //a
        float sumX = 0;
        foreach(GameObject go in goArray) {
            sumX += go.transform.position.x;
        }
        float avgX = sumX / goArray.Length;

        foreach (GameObject go in goArray) {
            SetX (go, avgX);
        }
    }

    void SetX( GameObject go, float eX ) {
        Vector3 tempPos = go.transform.position;
        tempPos.x = eX;
        go.transform.position = tempPos;
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    public GameObject gObj;
    public GameObject gObj1;
    public GameObject gObj2;
    void Start() {
        AlignX(gObj, gObj1, gObj2);
    }
    void AlignX( params GameObject[] goArray ) {
        float sumX = 0;
        foreach(GameObject go in goArray) {
            sumX += go.transform.position.x;
        }
        float avgX = sumX / goArray.Length;

        foreach (GameObject go in goArray) {
            SetX (go, avgX);
        }
    }

    void SetX( GameObject go, float eX ) {
        Vector3 tempPos = go.transform.position;
        tempPos.x = eX;
        go.transform.position = tempPos;
    
}
}

Ключевое слово params создает массив и включает в него все


игровые объекты, переданные в вызов функции.
Рекурсивные функции
Иногда функции должны вновь и вновь вызывать самих себя, —
такие функции называют рекурсивными. Простым примером
может служить вычисление факториала числа

Для вычисления факториала любого целого числа можно написать


рекурсивную функцию Fac():
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CodeExample : MonoBehaviour {
    void Awake() {
        print(Fac(5)); // Выведет: "120" // a
        print(Fac(0)); // Выведет: "1"
        print(Fac(-5)); // Выведет: "0"    
}

    int Fac( int n ) { // b, d 
        if (n < 0) { //Обрабатывает случай if n<0
            return(0);
        }
        if (n == 0) { // Это "завершающий случай" // 
e
            return(1);
    }
        int result = n * Fac(n-1); // c, f
        return(result); // g
}
}
Этот сценарий выведет:

120

1
0

В строке 19 параметр n (со значением 5) умножается на результат


вызова Fac() с параметром 4. Этот способ работы функции
называется рекурсией.

Отладка
Ошибки времени компиляции
Ошибка времени компиляции — это проблема, которую Unity
обнаруживает во время компиляции кода на C# (то есть при
попытке интерпретировать код на C# и превратить его в код на
обобщенном промежуточном языке (Common Intermediate
Language), который позднее будет преобразован средой Unity в
машинный код, понятный компьютеру).

Ошибки времени выполнения


Это ошибка времени выполнения, то есть ошибка, возникающая,
только когда Unity фактически пытается запустить проект. Ошибки
времени выполнения возникают, когда вы набрали код правильно
(с точки зрения компилятора), но что-то идет не так, когда этот код
выполняется.

Вам также может понравиться