Циклическая анимация фона - Часть вторая
21.04.2008, автор Stormit, рубрики: ActionScript, Игровые баннерыЕще один несложный способ программной анимации фона.
В отличие от первого урока, где в качестве фона выступает всего один символ, здесь все построено на дубликатах. Есть всего один символ - эталон (в моем случае это будет куст), но внутри него может быть сколько угодно кадров с разными состояниями. Это могут быть 10 по разному отрисованных кустов, разные стадии роста дерева или вообще совершенно непохожие друг на друга объекты (куст, пенек, камень, лужа, холмик…).
Каждый дубликат создается справа от экрана, проходит через всю флэшку и удаляется слева за ненадобностью (хотя можно попробовать возвращать в начальное положение).
Этот способ выигрывает у предыдущего постоянно меняющимся рисунком. Клипы располагаются случайным образом, поэтому пейзаж всегда разный. Плюс, можно поиграть с глубиной (задавать, какой из дубликатов будет выше остальных).
Для удобства, я использую условные границы “Лево” и “Право”. Эту роль играют 2 символа left и right, от которых мне нужны только координаты. Сами же они находятся за пределами флэшки. Таким образом легко можно сузить/расширить ширину фона (это полезно, когда создается группа баннеров с разными размерами).
Порядок действий:
- Рисуем куст и помещаем его в символ (называем его tree). Внутри я создал 2-й кадр и нарисовал куст еще раз.
- Создаем боковые маркеры - символы left и right - это начало и конец будущего фона (обычно делаю их яркими, чтобы не терялись).
- Оба маркера и символ tree помещаем в новый мувик и внутри него на кадре пишем Actionscript:
lev = 0; speed = 5; var dist = right._x - left._x;//ширина анимированного фона //функция создает и модифицирует дубликат placeTree = function () { lev++; var d = tree.duplicateMovieClip("t" + lev, lev); d._x = right._x + Math.random() * 50; //небольшой разброс для правдоподобности d._xscale = d._yscale = 50 + Math.random() * 50;//с той же целью if(Math.random() < .5) {//случайно выбирается вид куста d.gotoAndStop(1); } else { d.gotoAndStop(2); } d.onEnterFrame = function() { this._x -= speed; if(this._x < left._x){//удаляется, если вышел за пределы слева this.removeMovieClip(); } } return d; }; //чтобы сразу что-то было, заполняем экран объектами var i = 20;//подбираем на глаз while (i--){ var d = placeTree(); d._x = left._x + Math.random() * dist;//случайное начальное положение } onEnterFrame = function() { if(lev++ % 10 == 0){//выполнять каждый 10-й кадр placeTree(); } }
- Вот так это теперь выглядит со стороны.
- Раздвигаем маркеры за пределы экрана и получаем рабочую версию (Можно отмасштабировать этот главный клип, но вместе с ним изменится и его система координат и и скорость движения будет уже не та - зато так быстрее и удобнее если знаете что делаете). Вариант вполне годится (для создания объектов в одной плоскости, например аллеи).
- Можно пойти дальше и добавить в пейзаж глубину. Для этого немного перепишем код:
lev = 0; speed = 5; var dist = right._x - left._x;//расстояние между маркерами //функция создает обработанный дубликат символа tree placeTree = function () { lev++; var d = tree.duplicateMovieClip("t" + lev, lev); d._x = right._x; d.ky = Math.random();//коэфициент глубины d._y = right._y + d.ky * right._height;//высоту тоже регулирую маркерами d._xscale = d._yscale = d.ky * 100;//чем дальше, тем меньше //с танцами и бубнами - усложняю чтобы получить уникальное число //простой Math.random() подозрительно часто повторяется d.swapDepths(Math.floor(d._y * 100 + Math.random() * 90)); //случайно выбираем вид куста if(Math.random() < .5) { d.gotoAndStop(1); } else { d.gotoAndStop(2); } //добавляю воздушную перспективу var c = new Color(d); var n = 60 - d.ky * 60; //подбираем на глаз var ct = {rb:n,gb:n,bb:n}; c.setTransform(ct); d.onEnterFrame = function() { this._x -= speed / 2 * (1 + this.ky);//от 50% до 100% от скорости if(this._x < left._x){ this.removeMovieClip(); } } return d; }; //создаем изначально заросшее поле var i = 70; //подбираем на глаз while (i--){ var d = placeTree(); d._x = left._x + Math.random() * dist; } onEnterFrame = function() { if(lev++ % 4 == 0){ //каждый четвертый кадр placeTree(); } }
Получаем объекты, которые как будто в перспективе.
- Но в чистом виде это не очень полезно, поэтому сведу оба способа вместе. Здесь передний план и дорога сделаны отдельными клипами и движутся как в первой части.
Практика показывает что большое количество дубликатов может серьезно притормозить систему, поэтому лучше трезво смотреть на вещи и сочетать оба способа наилучшим образом. Хорошо получается если анимировать фон как один символ, а дубликатами сверху добавлять разнообразия. Например: стена комнаты, обои, плинтус, пол - делаются символом, а картина на стене, тумбочка, ваза, трещина - путем дублирования. Получится что мы действительно идем по коридору, постоянно попадая в новые места.
Еще несколько примеров сочетания. Здесь все вперемешку:
Интересно на 20%




Автор - маладец!
Вдохновляет, спасибо
Красиво рисуете.
Спасибо
Мне тут вчера вечером заказали игрушку написать… к понедельнику
вот сейчас скачиваю Флэш и изучаю туториалы
Ваши - просто прелесть - всё (hope so) понятно и возникает желание продолжить 
Вау!
Мне в свое время понадобился месяц и книга Колина Мука чтобы себя комфортно чувствовать.
Если жанр игры с этим уроком совпадает, советую взять его за основу, но придумать свой сюжет, мир и персонажей. Удачи.
Ошибка в коде, в “//случайно выбираем вид куста”
Unexpected ‘lt’ encoutered
Unexpected ‘}’ encoutered
Я уже устал их править
Наверное после восстановления базы опять спецсимволы заменились безопасными.
“<” - это “< ", а ">" - это ">“
А почему я рисую кустик, а он у меня на пол экрана увеличивается? Где менять масштаб?
Да, и как уменьшить число дубликации и высоту “перспективы”?
И у мне кажется, что два кода одинаковы, так как со вторым у меня получается анимация, как на 5-ом фрейме первой флешки.
to Destroyer
>>как уменьшить число дубликации и высоту “перспективы”
а ты постарайся сам себе объяснить что делает каждая строчка кода - там в комментариях многое расписано.
За высоту отвечает высота маркера
О. Про маркер - спасибо =)
d.swapDepths(Math.floor(d._y * 100 + Math.random() * 90)); - Мне кажеться, что это “плохая” строка, так как трейсом показывает, что очень часто глубина у дубликата клипа становится отрицательной, следовательно дупликат клипа в дальнейщем будет невозможно удалить. Или я не прав?
А вы сдвиньте всё немного ниже, в положительную область, чтобы отрицательные значения не возникали
Stormit, спасибо! разобрался с этим моментом!
А я тупой, у меня вообще ничего не происходит…=)))
Stormit, а можно тупым исходник глянуть? =)
Я принципиально удаляю исходники сразу после публикации поста
В статье есть всё необходимое. Если у кого-то получилось, получится и у вас.
Спасибо, за урок. Как и думал, путаюсь я в определении переменных.
Спасибо,очень полезный урок!
Ноуменя возник вопрос, как я заметил, независимо от положения слоя потом изображений будет всегда на первом плане, т.е. например если надо чтобы тучи по небу двугались из-за горы не получается, они все равно проходят перед горой, даже если слой с горой находится перед слоем с контрольными метками и тучей. Как быть в данном случае?
Можно сделать 2 клипа с тучами и клип с горой, затем расположить клип с горой между клипами с облаками.
А как сделать что бы кусты еще и уменьшались. У меня такая картинка: Автомобиль едет в перед и мы видим его спереди, а кусты уходят назад и уменьшаются.
На EnterFrame менять (уменьшать) размер кустов и постепенно смещать их к горизонту. Учтите что чем дальше объекты, тем меньше амплитуда смещения. То есть сначала кусты резко появляются и потом постепенно замедляясь уносятся за горизонт и там пропадают.
Я создал в ширине между left и right еще центральную точку и после нее куст двигался медленнее и уменьшал свои размер. Плавное уменьшение я не смог сделать. Пришел к тому что создал клип, где кусты с замедлением уменьшаются (как бы уходят за горизонт). И не знаю как сделать так что бы клип дублировался с некоторым временным промежутком, находясь на одном кадре сцены.
Пишет 1151: A conflict exists with definition d in namespace internal.
1151: A conflict exists with definition d in namespace internal.
где у меня лыжи застряли?
ругается на эту строчку var d = placeTree();
Спасибо за уроки… много ценного и для начинающего флешера. очень полезно.
у меня извечная проблема с весом флешек. Все должно в килобайты влезать..а выходят “паровозы”.
С помощью не хитрого кода можно все оживить и весить это будет копейки)
еще раз спасибо)