Конструктор персонажа с помощью as3

В этом уроке мы научимся создавать конструктор персонажа с помощью as3, чтобы по клику менялись части тела. А затем сохраним понравившийся образ в виде картинки. Часто конструкторы используются в играх, когда пользователь сам собирает главного героя, которым будет играть в дальнейшем. Например, всевозможные тамагоччи, по типу Pet Society.

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

 

Графику с разными вариациями той или иной части располагаем последовательно в кадрах на временной шкале внутри символа. Например, 3 типа глаз размещаем в мувиклипе в 3-х кадрах. Для глаз временная шкала выглядит так:

 

Каждый элемент располагается на отдельном слое.

Те элементы которые будут меняться оборачиваем в клипы и назначаем им instancename на панели Properties (в нашем случае это eyes, hair, ears, tail и neck).

Добавляем новый слой as3. И пишем следующий код:

  1. // сюда пишем все клипы которые будут меняться по клику
  2. addItems(eyes, hair, ears, tail, neck);
  3.  
  4. // добавляет события всем клипам и останавливает аним. на 1-м кадре
  5. function addItems(...rest){
  6.      foreach (varitem:MovieClipinrest){
  7.           item.stop();
  8.           item.addEventListener(MouseEvent.CLICK, nextItem);
  9.      }
  10. }
  11.  
  12. // выполняет смену кадра в клипе
  13. function nextItem(e:MouseEvent){
  14.      var item:MovieClip = e.currentTargetasMovieClip;
  15.      if (item.currentFrame != item.totalFrames)
  16.           item.nextFrame();
  17.      else
  18.           item.gotoAndStop(1);
  19. }

получим вот такой результат:

Кликая на любую часть тела, для которой это предусмотрено, графика меняется. Данный код является очень удобным для аниматоров, так как для того, чтобы создать свой конструктор, нужно назвать (присвоить instancename) все клипы которые будут меняться и, всего-лишь, прописать их имена в вызов функции addItems(). Это возможно благодаря специфической особенности данной функции. Она может принимать любое количество параметров. А конструкция foreach{} обрабатывает все эти параметры, в нашем случае, добавляя слушатели событий каждому параметру.

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

  1. addItems(eyes, hair, ears, tail, neck);
  2. // подсветка
  3. var glow:GlowFilter = new GlowFilter();
  4. glow.color = 0xFAAA25;
  5. glow.strength = 10;
  6. var filtersArray:Array = new Array(glow);
  7. function addItems(...rest){
  8.      for each (varitem:MovieClip in rest){
  9.           item.stop();
  10.           item.addEventListener(MouseEvent.CLICK, nextItem);
  11.           // событиядляподсветки
  12.           item.addEventListener(MouseEvent.MOUSE_OVER, onMOver);
  13.           item.addEventListener(MouseEvent.MOUSE_OUT, onMOut);
  14.      }
  15. }
  16. function nextItem(e:MouseEvent){
  17.      var item:MovieClip = e.currentTarget as MovieClip;
  18.      if (item.currentFrame != item.totalFrames)
  19.           item.nextFrame();
  20.      else
  21.           item.gotoAndStop(1);
  22.      // если не написать этих строкто иногда подсветка глаз не будет выключаться
  23.      if (e.target != item)
  24.           item.filters = null;
  25. }
  26. // подсветка
  27. function onMOver(e:MouseEvent){
  28.      e.currentTarget.filters = filtersArray;
  29. }
  30.  
  31. function onMOut(e:MouseEvent){
  32.      e.currentTarget.filters = null;
  33. }

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

У нас получился отличный конструктор персонажей. Было бы здорово как-нибудь сохранить полученного персонажа, например, в виде изображения. Стандартными средствами флеш это не осуществимо, но с помощью одного из классов этой библиотеки это сделать очень просто. Он находится в папке src/com/adobe/images и называется PNGEncoder.as (там, также, есть класс и для jpg изображений). Этот класс нужно поместить в папку с проектом, затем открыть его и убрать com.adobe.images из строки с package, или скачать уже поправленный файл (про классы будет отдельный пост-обзор в ближайшее время):

PNGEncoder

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

Вот так выглядит финальный результат:

Для того, чтобы сделать такую красоту нужно 3 дня медитировать и танцевать с бубном обернём всю графику нашего героя в клип и присвоим ему instancename, в нашем случае -dog. При этом, слой с кодом мы не оборачиваем в клип, а в функции addItems() учитываем появление нового клипа:

addItems(dog.eyes, dog.hair, dog.ears, dog.tail, dog.neck);

В принципе, оборачивать в клип не обязательно, здесь просто акцентируется внимание, что так можно делать, да и слоёв становится меньше. Так на много проще работать. В идеале, вообще всё содержимое размещать внутри клипа - так проще будет его повторно использовать.

Добавляем две кнопки, которые размещаем на разных слоях, одну над другой. Кнопки возьмём с плавной анимацией сделанной по принципу, который описан здесь. Эти кнопки мы будем поочерёдно показывать с помощью параметра visible. Таймлайн выглядит так:

 

Как видим по картинке нежно добавить ещё один кадр, а код изменится следующим образом:

  1. stop();
  2. addItems(dog.eyes, dog.hair, dog.ears, dog.tail, dog.neck);
  3. var glow:GlowFilter = newGlowFilter();
  4. glow.color = 0xFAAA25;
  5. glow.strength = 10;
  6. var filtersArray:Array = newArray(glow);
  7. // события кнопок
  8. btnSave.addEventListener(MouseEvent.CLICK, onSave);
  9. btnBack.addEventListener(MouseEvent.CLICK, onBack);
  10.  
  11. function addItems(...rest){
  12.      foreach (varitem:MovieClipinrest){
  13.           item.stop();
  14.           item.addEventListener(MouseEvent.CLICK, nextItem);
  15.           item.addEventListener(MouseEvent.MOUSE_OVER, onMOver);
  16.           item.addEventListener(MouseEvent.MOUSE_OUT, onMOut);
  17.      }
  18. }
  19. // убирает события всех клипов
  20. function removeItems(...rest){
  21.      foreach (varitem:MovieClipinrest){
  22.           item.removeEventListener(MouseEvent.CLICK, nextItem);
  23.           item.removeEventListener(MouseEvent.MOUSE_OVER, onMOver);
  24.           item.removeEventListener(MouseEvent.MOUSE_OUT, onMOut);
  25.      }
  26. }
  27. function nextItem(e:MouseEvent){
  28.      var item:MovieClip = e.currentTargetasMovieClip;
  29.      if (item.currentFrame != item.totalFrames)
  30.           item.nextFrame();
  31.      else
  32.           item.gotoAndStop(1);
  33.      if (e.target != item)
  34.           item.filters = null;
  35. }
  36. function onMOver(e:MouseEvent){
  37.      e.currentTarget.filters = filtersArray;
  38. }
  39. function onMOut(e:MouseEvent){
  40.      e.currentTarget.filters = null;
  41. }
  42. // функция сохранения рабочей области в картинку png
  43. function savePng(){
  44.      var bd:BitmapData = newBitmapData(stage.stageWidth, stage.stageHeight);
  45.      bd.draw(stage);
  46.      var barr:ByteArray = PNGEncoder.encode(bd);
  47.      var fr:FileReference = newFileReference();
  48.      fr.save(barr, "image.png");
  49. }
  50. // для кнопок
  51. function onSave(e:MouseEvent){
  52.      gotoAndStop(2);
  53.      // скрываем кнопки, чтобы их не было видно на картинке
  54.      btnSave.visible = false;
  55.      btnBack.visible = false;
  56.      // сохраняем картинку
  57.      savePng();
  58.      // отображаем кномку "назад"
  59.      btnBack.visible = true;
  60.      // удаляем события по редактированию персонажа
  61.      removeItems(dog.eyes, dog.hair, dog.ears, dog.tail, dog.neck);
  62. }
  63. functiononBack(e:MouseEvent){
  64.      gotoAndStop(1);
  65.      // покаываем кнопку "сохранить"
  66.      btnSave.visible = true;
  67.      // добавляем события для редактирования персонажа
  68.      addItems(dog.eyes, dog.hair, dog.ears, dog.tail, dog.neck);
  69. }

Предыдущий код дополнился новыми элементами. Мы добавили слушателей событий кнопкам и соответствующие им методы. Метод onSave() скрывает кнопки, вызывает метод savePng(), который в свою очередь подготавливает png изображение к сохранению и открывает окно, в котором можно выбрать, куда сохранить изображение. Метод onSave() опять показывает кнопку "back" на экране и удаляет слушатели событий из всех изменяемых элементов методом removeItems(). Этот метод устроен так же, как и addItems(), только он удаляет слушатели событий, а не добавляет.

И это ещё не всё. На втором кадре, как вы наверное заметили, присутствует анимированный фон. Он делается очень просто:

Рисуем один лучик, и располагаем его острым концом к центру. Оборачиваем его в клип. Копируем его и вставляем в тоже место. Затем с помощью панели трансформации меняем угол поворота на 20 градусов:

предварительно установив точку поворота в острый угол.

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

Итого получаем третий, четвёртый и т.д. лучик, пока не получим полный круг. Выделяем все лучики и оборачиваем их в клип, скажем, rotator и присвоим ему instancename "rot", и этот клип ещё в один клип, container. Внутринегонановомслоепишемкод:

  1. addEventListener(Event.ENTER_FRAME, update);
  2. function update(e:Event){
  3.      rot.rotation++;
  4. }

Ещё можно добавить маску слоя, чтобы наши лучики не вылезали за края рабочей области. Смотрим результат:

Копируем наш контейнер и вставляем в то же место. Отражаем его слева на право. Смотрим:

­­

Если что-то не понятно – задавайте вопросы и поскорее разбирайтесь! Все, кто дочитал да конца и всё понял – вы супер:)

Исходник (Cs5)

Автор урока: Андрей Барвинко

Графика: flash-animated.com (использование графики разрешено лишь в учебных целях)

Комментарии
Аватар пользователя Mariya

скажите пожалуйста, я новичок,и мало что понимаю в action script,у меня ошибка выходит вот в этой строке function addItems(...rest){
for each (varitem:MovieClip in rest), что здесь не так?

Аватар пользователя Mariya

а так же выходит вот такая ошибка 1084: Syntax error: expecting in before colon.

Аватар пользователя Scar

Ну неплохо Валентин... подпишусь чуть позже, дабы было (: А так если собрался учить, то ютуб тут не обезателен. Вот у него неплохо получается учить людей http://ruseller.com/ посмотри пару видеоуроков. Парень не только фактами сыпит но и методой.

Аватар пользователя Scar

О бл... давно не заходил. Но вы молодцы! Много нового... здорово!

Аватар пользователя Алексей

Дайте ссылку на программу пожалуйста, если не сложно скиньте на мыло плииииззз

Аватар пользователя Игорь

Приветствую всех, спасибо за урок. Сам задумал себе подобную помогалку, а у вас уже всё написано. Я с вопросом, что значит - ...rest , при иередаче в метод. Это какое то специальное, зарезервированное слово или нет, опять же тип не указан. Помогите пожалуйста понять.

Аватар пользователя flahhi

Здравствуйте! Нет это не зарезервированное слово. Туда можно написать любое имя после точек. Если простыми словами - то это тот же массив. Такая запись используется тогда, когда мы точно не знаем сколько аргументов будет передаваться в функцию. Например мы можем передать ей 2, а можем 20 мувиклипов, через запятую, без разницы. То есть мы можем написать
addItems(eyes, hair, ears, tail, neck);
а можем
addItems(eyes, hair);
или любой другой вариант.
Это очень удобно.
Удачи)

Аватар пользователя Игорь

Спасибо большое, за оперативность, я недавно только более менее начал разбираться в AS3, а такой записи ещё не встречал. Ещё раз спасибо. И Вам удачи и процветания.

Аватар пользователя Нина

Андрей спасибо за урок)
У меня немного вопросов: 1. где лучше создавать графику? в иллюстраторе на отдельных слоях?
2. Как использовать маску соя , что бы убрать то, что выходит за края поля? (например если задний фон - карта города- перемещается , но я не хочу что бы то, что за пределами в последующем было видно на ролике.

спасибо))

Аватар пользователя flahhi

На здоровье)
1. Рисуйте там, где вам удобно. Я рисую сразу во флеше, иллюстратор использую редко.
2. Очень просто. Почитайте здесь. Если не разберётесь, - пишите, покажу пример.

Аватар пользователя AntonyBeck

Спасибо за урок =)
А как сделать что бы части тела менялись не по клику по ним самим, а по ним, только из каталога "частей" (скажем слева)???

Аватар пользователя flahhi

Можно по разному это организовать. Например создать символ с графикой (sym) и несколько кнопок (s1, s2, s3). И по клику менять номер кадра в sym. Вот так:

  1. sym.stop();
  2. addEventListener(MouseEvent.CLICK, onClk);
  3. function onClk(e:MouseEvent){
  4. 	if(e.target==s1)sym.gotoAndStop(1);
  5. 	else if(e.target==s2)sym.gotoAndStop(2);
  6. 	else if(e.target==s3)sym.gotoAndStop(3);
  7. }

Аватар пользователя AntonyBeck

Спасибо, все получилось!

Аватар пользователя flahhi

Здорово, я очень рад!)

Аватар пользователя AntonyBeck

Спасибо, буду пробовать =)

Аватар пользователя Anyoneelselikeyou

Да... Вся эта серия уроков по as3 всегда была ну_просто _вау!!!, невероятно_Круто... Но сейчас... нет слов, шикарнейший пост, тема полезная, очень толково разжёвано. И сохранение в pngшку... А обещанный пост про классы, - эй, я теперь спать не смогу, так ждать буду.
Спасибо Огромное!

Что бы вы сделали, если бы точно знали что всё получится?...

Аватар пользователя Oksana

да, Андрей постарался, умничка он)

Аватар пользователя flahhi

Приятна похвала из уст людей, достойных похвалы! Спасибо Smile

Аватар пользователя Renderdoll

Ой, Оксана, Андрей, какие же вы молодцы! Спасибо за полезный и понятный урок, пошла грызть ганит АS-науки... )))

Аватар пользователя Oksana

стараемся, спс)

Аватар пользователя SlyBrowney

Спасибо-спасибо-спасибо! Все ваши посты - один полезнее другого, а этот - одна из исполненных мечт просто!

Аватар пользователя Oksana

:)