Статьи

AS3 101: ООП Введение — Basix

Два раза в месяц мы возвращаемся к любимым постам наших читателей на протяжении всей истории Activetuts +. Учебное пособие по ретроактивности этой недели, впервые опубликованное в октябре 2010 года, представляет собой введение в объектно-ориентированное программирование в AS3. Не забудьте ознакомиться с другими учебниками по AS3 101 !

Объектно-ориентированное программирование — горячая тема. Появляется все больше и больше языков программирования, которые поддерживают его (например, Ruby), и все больше и больше языков, которые ранее не поддерживали объектно-ориентированное программирование (для краткости ООП), выпускались с версиями, которые поддерживают такие, как PHP и ActionScript. , Некоторые языки работают, только если вы используете весь ООП, например, Java и Objective-C.

На самом деле это было давно, но стало известно в 1990-х годах, прежде всего, из-за его преимуществ в программировании GUI и появлении C ++ и Objective-C. В Википедии есть интересный раздел по истории ООП , который является отличным местом для начала обучения.


Если вы новичок в объектно-ориентированном программировании, у вас впереди немного обучения. Тем не менее, использование этой техники — это не просто то, что нужно делать; это может сократить время разработки, а также уменьшить количество ошибок в вашем коде. Это держит вас организованным и предотвращает ненужное дублирование. Но, пожалуй, более убедительным, чем эти высокие обещания, является тот факт, что Adobe, безусловно, приложила все усилия к концепции ООП, когда речь заходит о ActionScript. ActionScript 1 вообще не был объектно-ориентированным, а AS 2 был только объектно-ориентированным для удобства разработчика. В отличие от этого, AS 3 поддерживает полнопроходные объектно-ориентированные функции и, в любом случае, сделает это еще больше в ближайшие годы. Так что, если вы любите программировать на Flash и не хотите отстать, вам будет полезно принять ООП как образ жизни.

В этом уроке мы будем постепенно вводить некоторые из основных понятий, связанных с объектно-ориентированным программированием. Конечный продукт, выходящий из Flash, будет немного тусклым, но это всего лишь часть 1. Вы увидите некоторые практические исследования методов ООП, даже если этот учебник на самом деле не посвящен созданию конкретного проекта.

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


Так что же это за объектно-ориентированное программирование?

Во-первых, позвольте мне объяснить, что это не так. Объектно-ориентированное программирование (или сокращенно ООП) — не единственный или даже не обязательно лучший способ программирования в ActionScript 3. С тех пор, как в ActionScript 3 появился дебют, кажется, что для использования AS3 вам необходимо используйте ООП.

Хотя верно то, что AS3 гораздо лучше подходит для ООП, чем AS2, и что вам предлагается двигаться в этом направлении, неверно, что вам приходится учиться писать классы и создавать объекты для создания реальных приложений во Flash. Если вы следили за серией AS3 101 до сих пор, вы, возможно, заметили, что каждая строка ActionScript 3, которую мы написали в процессе, была на панели сценариев, а не в файле классов. Это должно помочь проиллюстрировать, что вполне допустимо не использовать ООП во время работы во Flash.

При этом ActionScript 3 действительно сияет, когда вы начинаете использовать ООП. И не только AS3, но и любой язык, который поддерживает ООП, может использоваться более эффективно при использовании методов ООП. Это потому, что ООП — это на самом деле просто техника — большая, сложная техника с множеством вариантов для рассмотрения, но все же просто техника — а не мандат. И это отличная техника, которую вы должны освоить. И вот почему ты здесь, верно?


Объектно-ориентированное программирование действительно сводится к двум фундаментальным единицам: классам и объектам . Эти два неразрывно связаны: класс порождает объект.

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

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

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

Термин « экземпляр» — это слово, которое описывает объект. Когда объект создается из класса, он называется созданным, и, таким образом, создается экземпляр класса . Слово объект обычно является синонимом экземпляра .

Если вас беспокоит терминология, помните, что отношение Символ библиотеки / Экземпляр, существующее со времен Flash 1. Символ — это отдельный элемент в библиотеке. Экземпляр — это конкретное проявление этого символа. Может быть более одного экземпляра данного символа, и изменения в оформлении одного символа изменит весь экземпляр этого символа. Тем не менее, каждый отдельный экземпляр может поддерживать некоторые уникальные свойства, такие как положение, вращение, преобразование цвета, фильтры и масштаб (и это лишь некоторые из них). Это прямо аналогично классу и объектам (экземплярам). На самом деле, это больше, чем просто аналог, как мы увидим в следующем выпуске этой серии.


Хорошо, давай прыгнем, ладно? Я думаю, что лучший способ намочить ноги в ООП AS3 — это ознакомиться с классом документов. Класс документа является классом, подобным любому другому в AS3, за исключением того, что он имеет особые отношения с файлом Flash. Это класс, представляющий SWF, который вы публикуете. Класс документа создается при запуске SWF. Это аналогично идее «основной» функции, если у вас есть фон в C, или «main» метода основного класса в Java.


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

Теперь создайте файл Flash (ActionScript 3.0) и сохраните его в этой папке. Имя не очень важно, но я буду называть мой MeetTheDocumentClass.fla


Теперь вам нужно сделать текстовый файл. Вы можете использовать Flash CS3 + для этого, или вы можете использовать Flex / Flash Builder , или вы можете использовать любой другой текстовый редактор, действительно. FlashDevelop — отличный (и бесплатный) выбор, если вы используете Windows. Есть много вариантов в текстовых редакторах, и нет правильных ответов (хотя, как я говорю моим студентам, есть один неправильный ответ. Текстовый редактор, встроенный в Flash CS3 / 4, на самом деле довольно ужасен, и чем скорее вы примете этот факт тем скорее вы получите удовольствие от написания кода в реальном редакторе). Лично мне нравится TextMate , но имейте в виду, что важен текст в файле.

После всего этого создайте новый файл в редакторе по вашему выбору (если вы используете Flash CS3 +, перейдите в меню «Файл», выберите «Новый», а затем выберите «Файл ActionScript» из списка. Если нет, то я Предположим, вы достаточно знакомы с вашим редактором, чтобы иметь возможность делать это без моего ведома).

Сохраните этот файл как DocumentClass.as в той же папке, что и ваш Flash-файл . Это важно: местоположение и название очень важны. Название не обязательно должно быть «DocumentClass.as», но это то, что я буду использовать, и чтобы избежать путаницы, я рекомендую вам просто делать то, что я делаю. Имя может быть любым, каким угодно (более или менее), но я хочу сказать, что имя играет важную роль в ООП AS3, поэтому будьте внимательны. То же самое касается местоположения файла; технически это может быть где угодно, но для удобства просто следуйте моим указаниям. Больше вариантов будет раскрыто к концу этой серии.

Подводя итог, вот моя папка проекта в ее нынешнем виде:


Теперь вы столкнулись с пустым файлом. Если вы когда-либо сталкивались с блоком писателя (как и я, о чем обычные читатели могли догадаться …), вы можете быть утешены тем фактом, что первое, что вам нужно написать, это на самом деле шаблон . Вам нужно будет написать следующее:

1
2
3
4
5
6
7
8
package {
    import flash.display.MovieClip;
    public class DocumentClass extends MovieClip {
        public function DocumentClass() {
  
        }
    }
}

Вау, что это все? Ну, это немного больше, чем мы должны сейчас объяснить. Я просто укажу несколько достопримечательностей.

Во-первых, обратите внимание, что package оборачивает всю вещь. Не беспокойтесь о том, что это сейчас, просто помните, что оно должно быть там, и класс должен содержаться в нем.

Во-вторых, у нас есть заявление на import . Возможно, вы раньше не видели такой строки кода; если вы до сих пор занимались программированием на панели «Сценарий» и не использовали сторонние библиотеки ActionScript, вам никогда не приходилось писать оператор импорта. В мире ООП каждый класс должен импортировать различные классы, которые ему необходимы для выполнения своих задач. Подробнее об импорте позже.

В-третьих, следующая «обертка» — это сам class . Вы можете увидеть ключевое слово «класс» в третьей строке. Анатомия этой строки больше, чем нам нужно сейчас, просто отметьте, что слово, следующее за словом «класс», является именем класса. Возможно, вы заметили, что имя, которое я использовал, совпадает с именем файла без расширения. Это не совпадение. Чтобы классы работали в AS3, имя класса должно совпадать с именем файла. Не забывай это.

Мы вернемся к биту «extends MovieClip» в следующем уроке. А пока, просто знайте, что этот бит необходим для класса документа (вы также можете расширить Sprite, а именно « extends Sprite », если вам не нужна временная шкала, и если вы измените строку импорта на « import flash.display.Sprite; «)

Наконец, у нас есть конструктор.


В предыдущем примере в классе определена (почти) нормальная функция. Почти нормально, за исключением той «публики» впереди и отсутствующего типа данных. Опять же, пока не беспокойтесь о «публике», это придет вовремя. Однако обратите внимание на название функции. Это верно, это то же самое, что и файл и имя класса . Надеюсь, вы не слишком параноик, потому что это не заговор. Просто так все работает. Называя функцию с тем же именем, что и класс, мы создаем специальную функцию, которая называется конструктор . Конструктор выполняется во время создания экземпляра. Надеюсь, вы не отставали от новой терминологии, потому что мы просто использовали два новых термина в одном предложении. nerdCred++;

В объекте могут быть другие функции, которые вы можете определить, но конструктор — единственная функция, которая вызывается автоматически во время создания экземпляра. Следовательно, конструктор — это то место, куда вы захотите поместить код, который должен выполняться, чтобы подготовить объект к первоначальному использованию. Например, если вы пишете класс для объекта, задачей которого будет загрузка некоторого XML, его анализ, затем загрузка миниатюрных изображений на основе этих данных, вы можете создать URLLoader , настроить его прослушиватель событий и возможно, даже начать загрузку, все, когда вы создаете объект. Эта логика может затем войти в конструктор.


В качестве практического примера мы сделаем небольшую программу «Hello World». Мы не будем просто прослеживать слова на панели «Вывод», нет, это немного странно и определенно чересчур. Мы создадим TextField , добавим его на сцену и поместим в него текст. Разверните файл DocumentClass.as чтобы он выглядел следующим образом (изменения выделены жирным шрифтом):

01
02
03
04
05
06
07
08
09
10
11
package {
    import flash.display.
    import flash.text.TextField;
    public class DocumentClass extends MovieClip {
        public function DocumentClass() {
            var tf:TextField = new TextField();
            addChild(tf);
            tf.text = «Hello World»;
        }
    }
}

Обратите внимание, что в дополнение к трем строкам, добавленным в конструктор, теперь есть дополнительная строка import в ожидании TextField.

Очевидно, мы могли бы пойти дальше, расположив и стилизовав текст, и вы можете сделать это самостоятельно, но пока это служит цели. Этот код создает текстовое поле со словами «Hello Word» и отображает его на сцене. За исключением одного: файл Flash не знает, что он должен иметь класс документа. Если вы попытаетесь запустить ваш файл Flash сейчас, вы получите пустое окно. Давайте исправим это дальше.


Как упоминалось в конце последнего шага, файл Flash (в моем случае MeetTheDocumentClass.fla ) еще не знает, что с ним связан определенный класс документов. Технически, у него есть класс документа, только класс документа — это просто старый MovieClip , так что он не собирается делать много.

Хорошо это знать, но сейчас мы действительно хотим, чтобы этот файл Flash знал, где находится файл DocumentClass.as который мы только что написали. Для этого сначала убедитесь, что ничего не выбрано (вы можете щелкнуть в любом месте на сцене, где отсутствует визуальный актив, или вы можете выбрать « Правка»> «Отменить выбор всех» или нажмите «Command» — «Shift-A» или «Control-Shift-A») ,

Затем откройте панель свойств. Если вы все успешно отменили, панель «Свойства» должна отображаться вверху

Теперь, где написано «Class:» в разделе «Публикация» на панели «Свойства», введите « DocumentClass » (или любое другое имя, которое вы использовали для своей версии класса, если вы настаиваете на создании своего собственного пути). Обратите внимание, что это без «.as» — это просто имя класса, а не имя файла.

Если вы уже следовали указаниям, вы должны нажать Return / Enter, и все будет хорошо. Если каким-то образом вы неправильно указали имя класса или не сохранили файлы в той же папке, вы не получите ошибку при публикации. Вы должны были получить эту ошибку при вводе имени класса:

Если вы проигнорировали его или не увидели, потому что ранее вы отметили опцию «Больше не показывать», SWF-файл будет опубликован без ошибок, но вы получите простой белый экран. В этом случае дважды проверьте имя класса, которое вы ввели на панели «Свойства».

Как только класс документа будет правильно подключен, вы можете убедиться в этом, щелкнув маленький значок карандаша рядом с текстовым полем класса документа на панели свойств. Это откроет файл в Flash CS3 + для редактирования. Не то, чтобы я рекомендовал хранить его там, но проверка того, что вы получили правильный файл, может быть полезным советом по устранению неполадок.

Как только все проверится, протестируйте свой фильм. Вы должны увидеть простое окно со словами Hello World:


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

Свойства, по своей сути, просто переменные . Однако есть небольшая разница между свойством и переменной. Это тонко, и нам нужно будет проиллюстрировать это на примере, но у нас есть кое-что, что нужно покрыть, прежде чем мы доберемся.

Во-первых, свойство записывается идентично переменной с двумя оговорками. Вот пример:

1
private var tf:TextField;

Первое предостережение должно быть очевидным: перед ключевым словом var стоит большой старый «private». « private » похож на « public », который я просил вас игнорировать несколько шагов назад. Я попрошу вас продолжать игнорировать это. Мы не доберемся до них до следующего урока.

Второе предостережение не будет очевидным, потому что фрагмент кода находится вне контекста. Это более уместно:

1
2
3
4
5
6
public class DocumentClass extends MovieClip {
    private var tf:TextField;
    public function DocumentClass() {
        // …
    }
}

Обратите внимание на положение свойства по отношению к структуре класса. Функция конструктора и свойство находятся на одном и том же «уровне» и «принадлежат» непосредственно классу (они оба вложены в класс напрямую). Эта характеристика делает переменную свойством (несмотря на то, что она объявлена ​​с использованием ключевого слова var ).

Напротив, переменная с именем » foo » в фрагменте ниже является просто переменной:

1
2
3
4
5
6
public class DocumentClass extends MovieClip {
    private var tf:TextField;
    public function DocumentClass() {
        var foo:String = «bar»;
    }
}

Почему? Потому что он «принадлежит» функции, а не классу. Когда переменная или функция объявляются в пределах фигурных скобок (что технически каждый раз), они существуют только до тех пор, пока существует вещь, представленная фигурными скобками. Итак, и здесь есть тонкое различие: свойство « tf » существует до тех пор, пока объект « DocumentClass » находится вокруг, и «принадлежит» объекту DocumentClass , но переменная « foo » существует только до тех пор, пока функция, содержащая его запускается и перестает существовать после завершения функции.

Естественно, есть исключения из этого правила «фигурных скобок». Циклы, например, не влияют на область действия переменной, объявленной внутри, поэтому возьмите это правило с частичкой соли. Вы не найдете его в книгах по программированию.

Вы можете спросить,

но подождите, разве функция не существует в объекте на том же уровне, что и свойство? Разве оно не существует так же постоянно, как свойство, и, следовательно, не существует ли переменная внутри функции?

У вас есть точка зрения, однако, различие заключается в том, что потенциал для запуска функции существует внутри объекта, в то время как фактически запущенная функция существует только в тот момент, когда ее вызывают. Переменная создается во время выполнения и, следовательно, перестает существовать после завершения выполнения. Я сказал, что различие было тонким. Но это важно, как мы скоро увидим.


Прежде чем мы перейдем к этому, мне нужно экстраполировать то, что мы только что узнали, на функции и методы. По сути, методы — это просто функции, которые принадлежат объекту, например, функция конструктора, только они не повышены до какого-либо особого статуса. Здесь мы добавили еще один метод:

1
2
3
4
5
6
7
8
public class DocumentClass extends MovieClip {
    public function DocumentClass() {
        // …
    }
    public function onButtonClick(e:MouseEvent):void {
        trace(«click»);
    }
}

Теперь onButtonClick() — довольно знакомая функция, за исключением этой надоедливой public в начале. Еще раз, отложи это. В противном случае вы должны признать это как обычную функцию. Единственное отличие состоит в том, что к методам применяется то же понятие «владения», что и к свойствам, а не к обычным переменным и функциям. Наконец, давайте рассмотрим это на рабочем примере.

В вашем DocumentClass мы добавим фрагменты, которые мы видели. Сделайте так, чтобы ваш класс выглядел так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package {
    import flash.display.
    import flash.text.TextField;
    import flash.events.MouseEvent;
 
    public class DocumentClass extends MovieClip {
  
        private var tf:TextField;
  
        public function DocumentClass() {
            tf = new TextField();
            addChild(tf);
            tf.text = «Hello World»;
  
            stage.addEventListener(MouseEvent.CLICK, onButtonClick);
        }
  
        private function onButtonClick(e:MouseEvent):void {
            tf.text = «Hey, you clicked!»;
        }
  
    }
}

Обратите внимание на изменения и дополнения: мы добавили свойство под названием « tf ». В конструкторе мы все еще создаем TextField , но вместо создания переменной в конструкторе, как мы делали раньше, мы просто используем « tf » — свойство. Наш TextField теперь хранится в свойстве вместо переменной.

Мы также добавили прослушиватель щелчков на сцену (нет, сцена на самом деле не кнопка, но в этом случае она избавляет нас от необходимости создавать MovieClip будет действовать как кнопка). И этот слушатель является методом с именем onButtonClick() , и кроме того, что он является методом вместо функции, он идентичен любому другому слушателю событий.

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


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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package {
    import flash.display.MovieClip;
    import flash.text.TextField;
    import flash.events.MouseEvent;
  
    public class DocumentClass extends MovieClip {
         
        //private var tf:TextField;
  
        public function DocumentClass() {
            var tf:TextField = new TextField();
            addChild(tf);
            tf.text = «Hello World»;
  
            stage.addEventListener(MouseEvent.CLICK, onButtonClick);
        }
  
        private function onButtonClick(e:MouseEvent):void {
            tf.text = «Hey, you clicked!»;
        }
  
    }
}

Выдает эту ошибку:

Что произошло? Что ж, в ActionScript переменная, созданная в одной функции, существует на время действия функции (что более чем на несколько строк позже) и исчезает после запуска второй функции. Поэтому, если мы создадим переменную tf в функции конструктора и попытаемся использовать ее в функции onButtonClick() , у нас onButtonClick() проблема. tf больше не существует при onButtonClick() .

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

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

И это тонкий момент, который начал этот этап марафона. Надеюсь, что он утонул, потому что я считаю, что этот момент стал причиной многих «ошибок» для начинающих студентов ООП.

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


Хорошо, на последнем шаге я пропустил создание кнопки и просто использовал сцену в качестве интерактивной области. Мы изменим это, но не потому, что щелкнуть по сцене неправильно (в некоторых случаях это не так), а потому, что мы можем создать класс Button для дальнейшего изучения ООП.

Наша цель — создать класс Button , из которого мы можем создать несколько объектов Button . Каждый объект Button будет иметь некоторую базовую функциональность, универсальную для кнопок:

  • Hover и нормальные состояния
  • Курсор превращается в значок руки
  • Графический фон с текстовой меткой

В то же время, для каждой кнопки должны быть уникальные вещи:

  • Текст метки
  • Действие щелчка
  • Положение кнопки

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


Мы создадим класс, который при создании экземпляра рисует прямоугольник, помещает текст в метку, обрабатывает переворачивания и переворачивания и может реагировать на щелчки. Начните с создания нового текстового файла в вашем текстовом редакторе. Сохраните его как «Button101.as» в той же папке, что и ваш Flash-файл . Это важно. Не испорти это! Я серьезно.


В вашем новом файле начните заглушки в шаблоне класса:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
package {
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    import flash.text.TextFormat;
  
    public class Button101 extends Sprite {
  
        public function Button101() {
  
        }
  
    }
}

Далее мы добавим некоторые свойства для хранения формы фона и метки:

1
2
3
4
5
6
7
8
// …
   public class Button101 extends Sprite {
 
       private var bgd:Shape;
       private var labelField:TextField;
 
       public function Button101() {
       // …

Свойство bgd будет содержать ссылку на Shape которую мы будем программно рисовать, чтобы она была заполненным прямоугольником, и добавим как дочерний элемент Sprite.

Свойство labelField будет содержать ссылку на TextField который мы также создадим с кодом, и использовать для отображения текстовой метки поверх фона.


А теперь мы расскажем о реальной логике. Для конструктора:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public function Button101() {
    bgd = new Shape();
    bgd.graphics.beginFill(0x999999, 1);
    bgd.graphics.drawRect(0, 0, 200, 50);
    addChild(bgd);
  
    labelField = new TextField();
    labelField.width = 200;
    labelField.height = 30;
    labelField.y = 15;
    var format:TextFormat = new TextFormat();
    format.align = «center»;
    format.size = 14;
    format.font = «Verdana»;
    labelField.defaultTextFormat = format;
    addChild(labelField);
  
    addEventListener(MouseEvent.ROLL_OVER, onOver);
    addEventListener(MouseEvent.ROLL_OUT, onOut);
  
    mouseChildren = false;
    buttonMode = true;
}

Это много кода, но по большей части в этом нет ничего удивительного. Мы создаем новую Shape и рисуем в ней прямоугольник. Затем мы создаем TextField , настраиваем его с некоторым базовым форматированием. Далее мы добавим некоторые события опрокидывания и развертывания (слушатели, для которых мы добавим на следующем шаге). Наконец, мы устанавливаем некоторые свойства, чтобы объект вел себя как кнопка.

Единственная часть, которая может вызвать путаницу, — это вызов addChild() , и откуда buttonMode свойства mouseChildren и buttonMode . Я попрошу вас еще раз подождать более полного ответа, так как он придет в следующей части, но это во многом связано с « extends Sprite », который мы написали ранее.


Теперь мы можем продолжить работу над нашим классом. После конструктора создайте функцию с именем setLabel :

1
2
3
public function setLabel(label:String):void {
    labelField.text = label;
}

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

1
2
3
4
5
6
private function onOver(e:MouseEvent):void {
    bgd.alpha = 0.8;
}
private function onOut(e:MouseEvent):void {
    bgd.alpha = 1;
}

Окончательный код должен выглядеть так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package {
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    import flash.text.TextFormat;
  
    public class Button101 extends Sprite {
  
        private var bgd:Shape;
        private var labelField:TextField;
  
        public function Button101() {
            bgd = new Shape();
            bgd.graphics.beginFill(0x999999, 1);
            bgd.graphics.drawRect(0, 0, 200, 50);
            addChild(bgd);
  
            labelField = new TextField();
            labelField.width = 200;
            labelField.height = 30;
            labelField.y = 15;
            var format:TextFormat = new TextFormat();
            format.align = «center»;
            format.size = 14;
            format.font = «Verdana»;
            labelField.defaultTextFormat = format;
            addChild(labelField);
  
            addEventListener(MouseEvent.ROLL_OVER, onOver);
            addEventListener(MouseEvent.ROLL_OUT, onOut);
  
            mouseChildren = false;
            buttonMode = true;
        }
        public function setLabel(label:String):void {
            labelField.text = label;
        }
        private function onOver(e:MouseEvent):void {
            bgd.alpha = 0.8;
        }
        private function onOut(e:MouseEvent):void {
            bgd.alpha = 1;
        }
    }
}

Очень важно убедиться, что ваши методы объявлены на уровне класса . Это еще одна ошибка новичка: иногда люди не обращают внимания на то, где их фигурные скобки начинаются и заканчиваются, и заканчивают тем, что вкладывают то, что должно быть методом (то есть объявленным на «корневом уровне» класса), внутри другого метода. Это эффективно превращает метод (который должен сохраняться в течение всего срока службы объекта ) в локальную функцию (которая сохраняется только в течение срока службы запущенного метода, в котором он был объявлен).

Надеемся, что ошибки компилятора сообщат вам о такой ошибке, но сама ошибка может быть загадочной. Было бы сказано: «1114: атрибут public / private / protected / internal можно использовать только внутри пакета». Если вы получили это, проверьте уровень вложенности ваших методов. Чтобы предотвратить эти ошибки, нужно обратить особое внимание на пробелы и отступы. «Настоящий» текстовый редактор может помочь вам в этом, но просто убедитесь, что все ваши объявления методов находятся на одном уровне отступа (обычно две позиции табуляции).

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


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

Сначала мы добавим новое свойство для удержания кнопки. Прикрепите это ниже линии с вашей существующей собственностью.

1
2
private var tf:TextField;
private var button:Button101;

Не обязательно собирать все свойства вместе, но для организации вашего файла полезно хранить вещи в согласованных местах. Лично я всегда перечисляю свойства в самом верху класса, перед конструктором. Таким образом, я всегда знаю, куда идти, чтобы найти объявление о недвижимости. Где они находятся в файле, не так важно, как придумать свой собственный стандарт и придерживаться его.

Двигаясь дальше, теперь мы можем создать экземпляр Button101 в конструкторе класса документа:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
public function DocumentClass() {
    tf = new TextField();
    addChild(tf);
    tf.text = «Hello World»;
  
    button = new Button101();
    button.x = 10;
    button.y = 200;
    button.setLabel(«Button 1»);
    addChild(button);
    button.addEventListener(MouseEvent.CLICK, onButtonClick);
     
    //stage.addEventListener(MouseEvent.CLICK, onButtonClick);
}

Обратите внимание, что мы изменили строку, которая настраивала слушателя для кликов на сцене. Мы переносим эту интерактивность на кнопку.

Теперь вам может быть интересно, как получается, что мы обрабатываем этот объект Button101 как если бы он был Sprite или MovieClip (см. Учебник по AS3 101 в списке отображения, если вам это не интересно). Это все, что связано с тем, что extends бизнес, который я просил пока затушевывать. Обещаю, мы скоро к этому вернемся (в следующей части этой серии).

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

Для справки, вот полный класс документа на данный момент, с дополнениями и изменениями, выделенными жирным шрифтом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package {
    import flash.display.MovieClip;
    import flash.text.TextField;
    import flash.events.MouseEvent;
  
    public class DocumentClass extends MovieClip {
  
        private var tf:TextField;
        private var button:Button101;
  
        public function DocumentClass() {
            tf = new TextField();
            addChild(tf);
            tf.text = «Hello World»;
  
            button = new Button101();
            button.x = 10;
            button.y = 200;
            button.setLabel(«Button 1»);
            addChild(button);
            button.addEventListener(MouseEvent.CLICK, onButtonClick);
 
        }
  
        private function onButtonClick(e:MouseEvent):void {
            tf.text = «Hey, you clicked!»;
        }
    }
}

Итак, что это сделало нас? Самое главное, что мы получили довольно изящную кнопку, которую мы могли бы использовать с минимальными усилиями (не считая усилий, вложенных в написание класса Button101 в первую очередь).

Чтобы реализовать ту же функциональность без классов и ООП, нам нужно было бы написать значительно больше кода в нашем основном скрипте. Чтобы проиллюстрировать это далее, давайте создадим вторую кнопку.


ОК, теперь давайте ООП действительно сиять. Мы создадим второй экземпляр кнопки, просто добавив еще несколько строк кода в класс документа.

Изменения будут очень похожи на предыдущий шаг. Сначала добавьте свойство:

1
2
3
private var tf:TextField;
private var button:Button101;
private var button2:Button101;

Затем установите его в конструкторе:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public function DocumentClass() {
    tf = new TextField();
    addChild(tf);
    tf.text = «Hello World»;
  
    button = new Button101();
    button.x = 10;
    button.y = 200;
    button.setLabel(«Button 1»);
    addChild(button);
    button.addEventListener(MouseEvent.CLICK, onButtonClick);
  
    button2 = new Button101();
    button2.x = 220;
    button2.y = 200;
    button2.setLabel(«Button 2»);
    addChild(button2);
    button2.addEventListener(MouseEvent.CLICK, onButtonClick);
}

Фактически вы можете просто скопировать и вставить строки кода первой кнопки и просто изменить button на button2 , а также положение x второй кнопки (в противном случае button2 будет располагаться прямо над button1 ).

Благодаря возможности повторного использования класса Button101 мы удвоили сложность нашего приложения всего за несколько коротких строк кода. У нас есть класс, который, если вы помните, является планом, из которого создаются фактические экземпляры. Теперь у нас есть две разные кнопки, но они разделяют это общее «наследие». Несмотря на то, что есть много характеристик, которые одинаковы между этими двумя кнопками, например, эффект прокрутки и размер, все же есть аспекты индивидуальности, а именно положение.

Надеемся, что это начинает иллюстрировать полезность и мощь объектно-ориентированного программирования, в котором мы очень легко облегчаем повторное использование кода.

Идите и проверьте это; у вас должно быть две кнопки, которые делают одно и то же.

Естественно, вы, вероятно, захотите настроить класс Button101 так, чтобы он выглядел более изящно, или имел эффект пролонгации или что-то еще. Button101 бы то ни стало, возьмите класс Button101 и сделайте его более полезным для собственных нужд. Наша цель состояла в том, чтобы продемонстрировать, как можно создать класс кнопок, а не создать окончательный класс кнопок.


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

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

Сфера является важной концепцией всего программирования, и не менее важно в объектно-ориентированном программировании. Область действия определяет «продолжительность жизни» переменной или функции, а также «место для жизни». Переменная в области объекта имеет другой срок службы, чем переменная в области метода.


Это, однако, просто царапать поверхность верхушки айсберга. Это все, на что у нас есть время прямо сейчас, но во второй части серии ООС AS3101, которая скоро будет опубликована, мы немного углубимся и, наконец, получим объяснение всех вещей, которые я просил отложить в сторону, вроде extends и на public . Вещи станут более понятными. Но когда дело доходит до такой сложной темы, как объектно-ориентированное программирование, лучше всего идти медленно.