C# Game Programming Cookbook for Unity 3D / Программирование игр на Unity 3D C#. Книга готовых решений.: 1.1.4 Наследование

Оглавление
Английский оригинал Перевод на русский

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

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

Arien0028 28.09.14 в 02:07

0

Суть в том, что наследование используется в программировании для описания метода предоставления шаблонов скриптов, которые могут быть перегружены, или добавлены другими скриптами. В качестве метафоры представьте себе автомобиль. Все автомобили имеют четыре колеса и двигатель. Типы колес могут варьироваться от машины к машине, так же как и двигатель, поэтому, когда мы говорим "это автомобиль" и пытаемся описать, что наша машина из себя представляет, мы также можем описывать двигатель и колеса.
Эти отношения могут быть представлены в иерархическом порядке:

Arien0028 28.09.14 в 02:33

0

Машина
-Колёса
-Двигатель

Arien0028 28.09.14 в 02:43

0

Теперь попробуйте представить себе это как C# скрипт:
Автомобиль класс
Колеса функция
Двигателя функция

Arien0028 28.09.14 в 02:44

0

Если мы создаём игру с большим количеством автомобилей, переписывать класс автомобиля для каждого типа автомобиля было бы глупо. Гораздо более эффективным методом может быть создание базового класса и заполнение его виртуальными функциями. Когда нам нужно создать автомобиль, вместо того чтобы использовать этот базовый класс, мы создаём новый класс, который наследует базовый класс. Так как наш новый класс является наследуемым, мы можем выбирать перегрузить ли функции Колеса или Двигатель, чтобы заставить их вести себя образом, определённым для нашего нового класса. То есть, мы можем создать функции "по умолчанию" в базовом классе, и если нам нужно только использовать поведение по умолчанию для двигателя, то в нашем новом классе не нужно перегружать функцию двигателя.
Базовый класс может выглядеть примерно так:

Arien0028 28.09.14 в 03:08

0

public class BaseCar : MonoBehavior {
public virtual void Engine () {
Debug.Log("Vroom");
}
public virtual void Wheels () {
Debug.Log("Four wheels");
}
}

Zeke0028 25.09.14 в 02:58

0

Есть два ключевых момента, на которые нужно обратить внимание в приведенном выше скрипте. Одним из них является само объявление класса и тот факт, что этот класс наследуется от MonoBehavior. MonoBehavior сам по себе является классом - который в документации Unity описывается как "базовый класс, от которого наследуется каждый скрипт" - так вот класс MonoBehavior содержит множество специальных функций движка и методов, таких как Start(), Update(), FixedUpdate() и многие другие.

Arien0028 28.09.14 в 03:48

0

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

Arien0028 28.09.14 в 06:46

0

Давайте взглянем на то, что конкретно этот скрипт делает: если бы мы вызывали функцию Engine() нашего класса BaseCar, она бы написала в консоле: "Vroom". Если бы мы вызвали Wheels, консоль прочитала бы "Четыре колеса".
Теперь, когда у нас есть класс BaseCar, мы можем использовать это в качестве шаблона и сделать новые версии этого следующим образом:

Arien0028 28.09.14 в 06:52

0

public class OctoCar : BaseCar {
public override void Wheels () {
Debug.Log("Eight wheels");
}
}

Zeke0028 25.09.14 в 02:58

0

Первое, что вы могли заметить, класс OctoCar наследуется от BaseCar, а не от MonoBehavior. Это означает, что OctoCar наследует функции и методы, принадлежащие нашему скрипту BaseCar. Так как функции заданные в BaseCar были виртуальными, они могут быть перегружены. Для OctoCar, мы перегрузим Wheels с строкой:

Arien0028 28.09.14 в 06:59

0

public override void Wheels () {

Zeke0028 25.09.14 в 02:58

0

Давайте взглянем на то, что именно этот скрипт делает: в этом случае, если бы мы вызывали функцию Engine() в OctoCar, она будет делать то же самое, что и в классе BaseCar; то есть, она будет писать "Vroom" в консоле. Она будет делать это, потому что мы унаследовали функцию, но не перегрузили её, что означает, что мы оставили её способ действия по умолчанию. В OctoCar, однако, мы перегрузили функцию Wheels(). Способ действия из BaseCar функции Wheels будет печатать "Четыре колеса" в консоль, но если мы вызываем Wheels() в OctoCar, из-за переопределённого способа действия функция будет вместо этого писать "Восемь колес".

Arien0028 28.09.14 в 07:08

0

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

Arien0028 28.09.14 в 07:20

0

Тема на этом не исчерпывается, но дальше мы не будем заходить. Каждый метод будет полезен в различных областях разработки игр. Например, в тех случаях, когда компонент требует ссылку на другой объект, например, материала или текстуры, имеет смысл установить это через редактор Unity. В тех случаях, когда мы разрабатываем классы, которые не относятся к GameObjects, мы можем использовать статическую переменную, чтобы сделать его доступным для всех других скриптов. Ради здравомыслия, мы вероятней всего никогда не будем использовать статическую ссылку на объект, не используя ее как одиночку.

(Примечание: Одиночка (англ. Singleton) — порождающий шаблон проектирования, гарантирующий, что в однопоточном приложении будет единственный экземпляр класса с глобальной точкой доступа.)

Arien0028 28.09.14 в 07:28

0
Минутку...