Море воды - программная анимация и не только

05.05.2008, автор Stormit, рубрики: ActionScript, Flash игры, Анимация, Игровые баннеры

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

Анимировать воду не так-то просто - это скажет каждый, кто хоть раз пытался это сделать. На первый взгляд эта переменчивая структура ведет себя непредсказуемо и пытаться воссоздать ее - пустая трата времени (действительно, некоторые считают что если он не Айвазовский, то даже браться за это не стоит). Но это только на первый взгляд. Главное, чтобы в готовом виде клип мгновенно определялся пользователем как вода и вел себя соответствующим образом. Конечно, можно вставить в игру видео, а можно сделать все гораздо экономичнее.

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

Теперь распишу каждый пример подробно.

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

Здесь Actionscript используется наравне с обычной анимацией. Создается клип с анимацией движения одной волны и потом он раскидывается каждый кадр по площади моря. Когда волна угасает, в последнем кадре анимации вызывается скрипт, который удаляет этот дубликат.

  1. Создаем прямоугольный символ box - это рабочая площадь моря. Дальше рисуем “барашка” - пену которая возникает на пике волны. Помещаем ее в клип wave и анимируем полный цикл - волна появляется и уходит с замедлением в наивысшей точке (можно просто сжимать клип по вертикали, а можно при этом стараться сохранять массу). В последнем кадре клипа wave пишем строку для удаления:
    this.removeMovieClip();
  2. Слоем выше на кадре пишем такой код:
    lev = 0;
    var w = box._width;
    var h = box._height;
    onEnterFrame = function() {
    	lev++;
    	var d = wave.duplicateMovieClip("d" + lev, lev);
    	d._x = box._x + Math.random() * w;//ложим в случайную точку
    	d._y = box._y + Math.random() * h;//на поверхности воды
    	d._xscale = d._yscale = 50 + Math.random() * 100;//больше реализма
    }
  3. Море в готовом виде. Похоже на легкий бриз в ясную погоду.
  4. Но это всего лишь принцип, делать так можно не только море. Например, в этом примере что-то похожее на кислоту, а вместо волн - пузыри с ядовитым газом. Думаю всплески от дождя и мигание звезд тоже неплохо получатся.

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

  1. Символ длинной волны можно создать из маленьких кусков. Зазоры между ними изображены для наглядности, в жизни все должно быть вплотную.
  2. Так как код для всех волн одинаковый, лучше его писать внутри клипа волны.
    x0 = _x;
    x9 = x0 - _width / 2;
    onEnterFrame = function() {
    	_x -= speed;//скорость задается снаружи
    	var dx = x9 - _x;
    	if (dx > 0) {
    		_x = x0 - dx;
    	}
    }
  3. А переменная speed снаружи задается для каждой волны индивидуально. По простому, на клип, через onClipEvent:
    onClipEvent (load) {
    	speed = 3.5;//для верхнего клипа
    }
  4. Должно получиться примерно так. Можно сильнее детализировать море дополнительными волнами. Кораблик раскачивается синусом.

Пример №3 тоже создает волны, но совсем иного типа. Похоже на эффект из фильма “Хищник”. Есть две одинаковые текстуры воды, смещенные по координатам. Причем нижняя просто лежит на сцене, а верхняя проявляется случайным образом.

  1. Берем любую однородную “бесшовную” текстуру воды.
  2. Вызываем для нее Break Apart (Ctrl + B). Теперь белой стрелкой (Subselection Tool) раздвигаем точки до размеров флэшки.
  3. Рисуем и анимируем примерно такой полумесяц, как в примере (у меня эта анимация длится 25 кадров). Это будет рядовой Волна. Внутри нее в первом кадре пишем код, который выполнится один раз и начнет проигрывание с произвольного кадра:
    if(!_first) {
    	_first = true;
    	gotoAndPlay(Math.floor(Math.random()*_totalframes));
     
    }
  4. Формируем из волн “отделение” - заполняем прямоугольную область. Из отделений - взвод, роту, батальон, полк и так далее, пока не заполнится весь экран. Можно, конечно, весь экран закидать одиночными символами, но так гораздо дольше и изменять потом тяжелее.
    Поместим весь набор, который занимает экран в символ wave1. Дублируем его и располагаем выше (символ wave2), зазора между ними быть не должно. Анимировать волны будем таким способом: обе волны смещаются вниз с одинаковой скоростью и как только нижняя скрывается за экраном, тут же перескакивает наверх. На первой волне пишем код:

    onClipEvent (load) {
    	y0 = _y;//запомним координату и привяжемся к ней
    	onEnterFrame = function() {
    		_y += .5;
    		if(_y > 175) _y = y0;
    	}
    }

    На второй:

    onClipEvent (load) {
    	y0 = _parent.water1.y0;//вот и привязались
    	onEnterFrame = function() {
    		_y += .5;
    		if(_y > 175) _y = y0;
    	}
    }

    Должно получиться что-то похожее. как на примере.
    Лимит по _y я подобрал вручную - габариты клипа постоянно меняются и к ним сложно привязаться.

  5. Вот так в рабочем режиме покрывают весь экран
  6. Воду, созданную на шаге 2 дублируем и ложим слоем выше. Смещаем на 5 пикселей вниз. Клип со всеми волнами становится для нее маской (во избежание проблем, в масочном слое должен быть всего 1 клип).
  7. Должно получиться примерно так. Поиграться можно с размером микроволн, плотностью заполнения, длительностью анимации.

Пример №4 - не совсем волны, но эффект каустики во флэше. Здесь почти без скриптов. Способ больше подходит для “вида сверху”.

  1. Берем любую однородную “бесшовную” текстуру воды.
  2. Создаем море размером с экран (а по высоте в 2 раза больше). Break Apart (Ctrl + B), и белой стрелкой (Subselection Tool) раздвигаем точки до размеров сцены. Слоем выше лежит копия моря, повернутая на 180 градусов и простым твиннингом уходит в альфу и обратно (здесь анимация длится 72 кадра - меняя скорость, меняется волнение воды).
  3. Все, что сделано выше, засовываем в символ и смещаем его по принципу “на половинку с возвратом”. То есть на клипе такой код:
    onClipEvent (load) {
    	y0 = _y;
    	y9 = y0 - _height / 2
    	speed = .5;
    }
    onClipEvent (enterFrame) {
    	_y -= speed;
    	if(_y < y9) {
    		var del = Math.abs(_y) - Math.abs(y9);
    		_y = y0 + del - speed;
    	}
    }

Способ №5. На мой взгляд, обладает большим потенциалом и лучше передает реализм. Как и раньше, единицей воды становится анимированная твиннингом волна. От того, как вы ее закрутите, напрямую зависит результат.

  1. Рисуем фон и создаем клип воды water - прямоугольник, закрашенный градиентом (к горизонту светлее).
  2. Создаем клип wave и внутри анимируем волну. Анимация происходит в несколько этапов: вначале гребешок волны поднимается над поверхностью, опускается назад и дальше уже другая форма, деформируясь (анимация отражения по вертикали), смещается вниз с прозрачностью 30% (на глаз). Слева - формы, которые участвуют в анимации. Для них выбран такой же цвет, как у воды над горизонтом. При наложении на градиент появляются блики.
  3. Ложим клип wave за пределами экрана, а _y выравниваем по горизонту.
    Кадром выше пишем код:

    lev = 0;
    onEnterFrame = function () {
    	lev++;
    	var d = wave.duplicateMovieClip("w" + lev, lev);
    	d._x = water._x + Math.random() * water._width;//располагаем по горизонту
    };

Думаю, этих способов хватит на все случаи жизни (мне пока хватало), для игр и баннеров очень даже хорошо подходит. Да и во flash-открытках может пригодиться.

Но не увлекайтесь: анимированное во флэше море - хорошо, а реальное море - лучше!

Интересно на 41%

(28) Хитрых на тему «Море воды - программная анимация и не только»

  1. GB

    Последнее море понравилось.
    “Но не увлекайтесь: анимированное во флэше море - хорошо, а реальное море - лучше!” // это стопудово

  2. Lerika

    отличные примеры!

  3. dimat

    Очень классные примеры!

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

  4. TyomaS_tt

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

  5. deadmorozz

    Зашел в поисках анимации волны, остался дико доволен результатами :)
    Спасибо громаднейшее :)

    Но у данного способа есть один суровый недостаток — клипы дублируются бесконечно без особых ограничений, что со временем ведет к неизбежным тормозам.
    Я сделал немного по-другому: волна генерится с интервалом в 50мс, а при достижении некоего порога (допустим, 300) depth возвращается в исходное состояние. Выходит неплохо - и покрытие в норме, и ресурсы берегутся.

  6. Stormit

    Нету такого недостатка :)
    Когда клип волны доигрывает до конца, он сам себя удаляет, а создавать волны можно, например каждый второй кадр if(lev++%2 == 0){…}

  7. deadmorozz

    Ну, я, в принципе, догадывался, что так оно и есть на самом деле :)
    Правда в статье об этом практически ничего не говорится.
    Может, я что-то просмотрел, или не там читал :)

  8. Stormit

    Самый верхний пример - 1-й комментарий. Для других примеров я уже не повторял

  9. deadmorozz

    Значит реально не туда я сморел :)

  10. Виктор

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

  11. Иришка

    Спасибо за урок! это еще одна капля в океане изучения флэша

  12. Юляшка

    спасибочки,вы мне очнь помогли,разобраться в некоторых хитростях флеша.

  13. Робо

    Простите. Руки кривые. Все заработало. Спасибо за чудесные уроки

  14. 4V_Kirill

    Спасибо большое! :) Прям очень в тему мне сейчас!
    Привет!

  15. VinHome

    Многоуважаемый Stormit, только начал изучать Flash. вот вроде делаю все как у вас написанно но не получается добится конечного результата. Будте так любезны. Скиньте пожалуйста исходник на мой e-mail ( 3s_wapsmile@mail.ru)
    Зарание спасибо!

  16. Виталик

    Пасиба большое за блог!
    Возник вопрос, пробую создать волну как в примере №5
    но не получается дублирование
    1. Создал два клипа фон и фолны.
    2. оба клипа перенес в лейер1, клип с волной вынес за пределы картинки но выровнял по горизонту с морем.
    3. в леейре 1 в первом кейфреме добаил код.

    где может быть ошибка? спс

  17. ВИталик

    Ответ на предыдущее сообщение нашел сам, забыл прописать в свойствах имя

  18. Александр

    У меня не получился первый пример,. Сделал все как надо. Разместил на сцене, у меня wave бесконечно повторяется и все.

  19. Александр

    Где можно скачать исходник? Или пришлите пожалуйста на discodancer88@bk.ru у кого получилось.

  20. Stormit

    Значит не всё так как надо. Волна не дублируется - почему? Если дублируется и не раскидывается по всей площади - почему?
    На эти вопросы можно ответить если проверить переменные функцией trace(). Может переменная lev у вас не изменяется, может клип box отсутствует или не назван. Может ещё что-то.

  21. Anya

    Очень классный сайт! Столько полезного и интересного можно узнать. И все подробно описано. Спасибо огромное! )

  22. Storm

    В первом примере волны, гребешки всегда оказываются на переднем плане и перекрывают другие нарисованные объекты, к примеру, корабль. Если ли возможность отправить их на задний план? Подобный вопрос часто возникает при программном размножении объектов.

  23. Не могу обратиться к функции ...

    […] ЗЫ: в примере тут: http://xitri.com/2008/05/05/more-vod…-ne-tolko.html […]

  24. Stormit

    to Storm
    Самый простой способ - положить корабль выше волн (весь клип box) и маской симитировать его погружение в воду.

  25. F9K

    Видимо, та же проблема, что и у Александра.. волна просто повторяется на одном месте и всё.. создал фон на одном слое, волну на другом.. в символе wave в последнем кадре анимации прописал удаление.. в единственном кадре слоя с волной прописал остальной код..

  26. Вика

    что-то тоже первый вариант не идет… пришлите пожалуйста исходник vika1533@mail.ru

  27. Orlandina

    Сайт классный, очень вдохновляет, но не всегда все получается :) Можно я тоже исходник попрошу? Пришлите, пожалуйста, на rondaWh@gmail.com первый и последний примеры.

  28. богдан

    Дуже тодковий сайт.Я починаю працювати з Flash.
    Скиньте будь-ласка файли fla по анімації 1 і 5 прикладу.
    на email bo_lu@ukr.net.
    Не можу зрозуміти box - це графічний символ чи Movie Clip.
    Де ставити на шкалу анімації символ wave, а де box і в яких
    кадрах анімації.
    Дякую за приклади по анімації води

Оставить комментарий