Главная | Форум | Реклама | Shop Flash-JePo | Картинки | Регистрация | Вход
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Анимация дождя с брызгами капель
JeepersДата: Понедельник, 29.08.2011, 11:29 | Сообщение # 1




Администратор портала







Главный Админ
Сталин
Группа: Администраторы
Сообщений: 937
Награды: 0
Репутация: 13

Rain Animation with Splashing Raindrops - AS3 Effect

Примеры разбрызгивания дождевых капель

Мы предоставляем вам гибкий пользовательский AS3 класс RainDisplay, который позволяет создавать множество 2D анимаций дождевых капель. Капли образуют брызги при ударе о землю. Ниже мы показываем два примера, чтобы проиллюстрировать основное использование класса RainDisplay.



Загрузка

•Загрузите файлы исходников: rain.rar
Все исходные файлы в пакете хорошо откомментированы. Существует несколько интересных аспектов в коде в этом уроке: использование связанных списков и "корзины" для увеличения оперативности, и техника анимации, которая вызывает отрисовку в битмап и использование фильтров для того, чтобы создать появление плавного движения. Путем легкого изменения параметров может быть получен другой эффект в следующем примере.



Класс RainDisplay и другие пользовательские AS3 классы

Класс RainDisplay

Класс RainDisplay - это расширение класса Sprite; экземпляр класса RainDisplay - это дисплей объект, который можно добавить на сцену.

После того, как экземпляр класса RainDisplay был построен и добавлен на сцену, и заданы желаемые параметры, в основном коде просто необходимо вызвать функцию addDrop для добавления отдельных капель на сцену и функцию update для обновления анимации. В функции addDrop могут быть установлены различные параметры для вновь созданной капли дождя, такие как начальная скорость и цвет.

После того, как капли были добавлены к дисплей листу, их движение регулируется под гравитацией и скоростью ветра. В основном коде просто необходимо сделать повторяющиеся вызовы функции update (на основе или EnterFrame или TimerEvent), чтобы воспроизводить анимацию.

Функция addDrop имеет следующий формат:

Code
ddDrop(
         x0:Number,
         y0:Number,
         [velocityX:Number],
         [velocityY:Number],
         [color:uint],
         [thickness:Number],
         [alpha:Number],
         [splashing:Boolean]
         ):LineRaindrop


В функции addDrop капля добавляется в дисплей лист (капли используются как члены класса LineRaindrop). Первые два требуемых параметра дают положение новой капли. Функция возвращает добавленную дождевую каплю, которая может быть удобна для ссылки на новые капли в коде.

Есть несколько необязательных параметров в функции addDrop, которые определяют атрибуты для новой капли. Они сами себя объясняют, за исключением атрибута splashing. Если капля имеет булевский атрибут splashing и он установлен в true, будет создаваться всплеск, когда она пересечет землю. Если нет, она исчезнет без всплеска.

Одно замечание относительно скорости капли дождя: капля дождя может иметь постоянную "предельную скорость", это будет достигнуто при установке ее булевой переменной atTerminalVelocity равной true. Такие капли не будет иметь скорости, и пострадают от тяжести.

Если необязательные параметры не определяются в функции addDrop, используются значения по умолчанию. Значения по умолчанию содержатся в паблик переменных, которые сами себя объясняют в коде RainDisplay.

Капли можно раскрашивать несколькими методами. Они могут иметь (1) постоянный цвет, (2) случайный серый цвет, (3) случайный цвет в градиенте между двумя определенными цветами, или (4) полностью случайный цвет. Переменные и булевы флаги используются для этих различных методов раскрашивания, это должно быть ясно при изучении кода
RainDisplay класса.

Капли - это члены класса LineRaindrop, они отрисовываются просто как отрезки линий. Эти капли могут быть установлены как "long" или "short" типы. Короткая капля рисуется как линия от последней позиции капли к новой позиции. Длинная капля отрисовывается от своего положения два фрейма преимущественно к ее настоящему положению. Этот метод отрисовки создает эффект длинной непрерывной полосы движения, а не дискретных точек.

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

Несколько комментов по коду

Хотя для разработчика нет нужды понимать всю внутреннюю работу класса RainDisplay, некоторые аспекты в коде могут представлять интерес. Чтобы запомнить списки капель, код в этом классе использует связанные списки вместо массивов, поскольку массивы, как правило, в коде работают более медленнее. Другой эффективный метод - сделать использование “корзины” для капель, которые покидают видимый диапазон анимации. Вместо удаления капель, когда они выходят за видимый диапазон анимации, они делаются невидимыми, удаляются из основного листа капель и помещаются в корзину (которая является еще одним связанным списком) где они запоминаются для дальнейшего использования. Когда нужны новые капли, они берутся из корзины (если она не пустая); цвет и другие параметры для дождевой капли восстанавливаются в соответствии с пожеланиями. Этот метод предоставляет постоянное создание новых капель дождя, а также частые добавления и удаления капель со сцены, все это является трудоемкой задачей.

Брызги, которые возникают от капель дождя, достигающих земли, могут привнести в код сложный аспект, но на самом деле всплески было довольно легко закодировать. Каждый всплеск просто создается путем добавления дополнительных капель дождя на сцену, с возрастающимися скоростями (с некоторой рандомизацией).
Однако это представляет потенциальную проблему: как предотвратить новые капли от водяных брызг снова после столкновения с землей, создавая все больше и больше капель дождя в дисплей листе? Секрет содержится в булевом атрибуте splashing в классе LineRaindrop. Только капли, которые имеют атрибут splashing, установленный в true, создают брызги при ударе. Капли, которые создаются как часть всплеска, имеют свой атрибут splashing установленным в false, поэтому когда они ударяются о землю, они исчезают без создания новых брызг.

Как RainDisplay класс используется в примерах

В обоих представленных примерах rain display в действительности не добавляется на сцену. Вместо этого он отрисовывается в битмап на сцене в каждом фрейме анимации. Это позволяет использовать некоторую технику фильтров. Вместо того, чтобы стирать битмап и перерисовывать каждый фрейм, старая картинка должна затухать с помощью ColorTransform. Это приводит к тому, что красивый след остается позади опускающейся капли, что создает
хороший эстетический эффект. Вы можете поэкспериментировать с другими типами фильтров (например,использовать BlurFilter вместо ColorTransform) для создания различных видов эффектов.

Пример RainDisplay_Basic иллюстрирует наиболее частое использование класса RainDisplay для создания падающих и разбрызгивающихся капель. Скорость ветра изменяет анимацию на всем протяжении.

Пример RainDisplay_Dripping создает эффект падающих капель с рандомной раскраской. Здесь мы даем каждой капле начальную нулевую скорость, таким образом, чтобы капли начали свое падение от положения покоя. Мы также явно используем некоторые переменные, которые оставались в дефолтных значениях в первом примере, но которые были разработаны для красочного эффекта капания. Есть переменные globalBreakawayTime и breakawayTimeVariance. globalBreakawayTime устанавливает время в течение которого должна находиться на сцене пред тем, как начнет двигаться (она названа “global” чтобы отразить, что эффекты всех капель добавляются, чтобы отобразить дождь). Переменная breakawayTimeVariance придает некоторую случайную вариацию для этого breakaway time.

Привожу вашему вниманию этот класс

Code
/*
Класс RainDisplay -это расширение класса Sprite; экземпляр класса  RainDisplay
это display object, который можно добавить на сцену.

Взаимодействие с объектом RainDisplay в основном коде  главным образом полностью
происходит с помощью 2 методов: addDrop и update.  Функция addDrop добавляет капли для отображения,
а функция update изменяет и перерисовывает капли в дисплей листе, перемещая
капли в соответствии с их скоростями  и ускорением  благодаря гравитации.

Функция addDrop имеет следующий формат:

addDrop(
x0:Number,
y0:Number,
[velocityX:Number],
[velocityY:Number],
[color:uint],
[thickness:Number],
[alpha:Number],
[splashing:Boolean]
   ):LineRaindrop

Первые два параметра дают положение для новой капли. Необязательные параметры
определяют другие атрибуты для новой капли, и говорят сами за себя, за исключением
атрибута "splashing".  Если капля имеет булев атрибут splashing, установленный в
true, будет создаваться всплеск, когда она коснется земли.  Если же нет, она исчезнет
без всплеска.

*/

package com.flashandmath.dg.display {
import com.flashandmath.dg.objects.*;
import com.flashandmath.dg.dataStructures.*;
import flash.geom.*;
import flash.display.*;

public class RainDisplay extends Sprite {
       
   public var gravity:Number;
     
   //linked list - onStageList - это список всех капель,
   //которые в настоящее время анимированы.    
   private var onStageList:LinkedList;
   //recycleBin хранит капли, которые больше не являются частью анимации, но
   //которые могут использоваться снова, когда нужны новые капли.
   private var recycleBin:LinkedList;
     
   public var numOnStage:Number;
   public var numInRecycleBin:Number;
   public var displayWidth:Number;
   public var displayHeight:Number;
     
   //вектор, определяющий скорость ветра:
   public var wind:Point;
       
   public var defaultInitialVelocity:Point;
   public var defaultDropThickness:Number;
   public var windOnSplash:Number;
   public var noSplashes:Boolean;
     
   //defaultDropColor используется только, когда капли не окрашиваются рандомно
   //а окрашены в серые тона, градиент, или полностью случайного цвета.
   public var defaultDropColor:uint;
     
   public var randomizeColor:Boolean;
   public var colorMethod:String;
   public var minGray:Number;
   public var maxGray:Number;
   public var _gradientColor1:uint;
   public var _gradientColor2:uint;
   public var dropLength:String;
   public var minSplashDrops:Number;
   public var maxSplashDrops:Number;
   public var defaultDropAlpha:Number;
   public var splashAlpha:Number;
   public var splashThickness:Number;
   public var splashMinVelX:Number;
   public var splashMaxVelX:Number;
   public var splashMinVelY:Number;
   public var splashMaxVelY:Number;
     
   //если капли выходят за пределы видимости окна xRange, они могут быть
   //удалены из анимации или сохранены для проигрыания.  Если ветер изменяется быстро,
   //существует возможность, чтобы капли появились вновь со стороны, итак
   //вы можете пожелать сохранять их, и установить следующую переменную в false.
   public var removeDropsOutsideXRange:Boolean;
     
   //Эти параметры для изменений разрешают контролировать
   //случайные вариации в скоростях капелек
   public var initialVelocityVarianceX:Number;
   public var initialVelocityVarianceY:Number;
   public var initialVelocityVariancePercent:Number;
     
   public var globalBreakawayTime:Number;
   public var breakawayTimeVariance:Number;
     
   private var displayMask:Sprite;
   private var left:Number;
   private var right:Number;
   private var r1:Number;
   private var g1:Number;
   private var b1:Number;
   private var r2:Number;
   private var g2:Number;
   private var b2:Number;
   private var param:Number;
   private var r:Number;
   private var g:Number;
   private var b:Number;
   private var numSplashDrops:int;
   private var outsideTest:Boolean;    
   private var variance:Number;
   private var dropX:Number;
     
   public function RainDisplay(w = 400, h=300, useMask = true) {    
    displayWidth = w;
    displayHeight = h;
    onStageList = new LinkedList();
    recycleBin = new LinkedList();
    wind = new Point(0,0);
    defaultInitialVelocity = new Point(0,0);
    initialVelocityVarianceX = 0;
    initialVelocityVarianceY = 0;
    initialVelocityVariancePercent = 0;
    windOnSplash = 0.20;
     
    noSplashes = false;
     
    numOnStage = 0;
    numInRecycleBin = 0;
     
    if (useMask) {
     displayMask = new Sprite();
     displayMask.graphics.beginFill(0xFFFF00);
     displayMask.graphics.drawRect(0,0,w,h);
     displayMask.graphics.endFill();
     this.addChild(displayMask);
     this.mask = displayMask;
    }
     
     
    defaultDropColor = 0xFFFFFF;
    defaultDropThickness = 1;
    defaultDropAlpha = 1;
    gravity = 1;
    randomizeColor = true;
    colorMethod = "gray";
    minGray = 0;
    maxGray = 1;
    _gradientColor1 = 0x0000FF;
    _gradientColor2 = 0x00FFFF;
    dropLength = "short";
     
    splashAlpha = 0.6;
    splashThickness = 1;
    minSplashDrops = 4;
    maxSplashDrops = 8;
    splashMinVelX = -2.5;
    splashMaxVelX = 2.5;
    splashMinVelY = 1.5;
    splashMaxVelY = 4;
     
    removeDropsOutsideXRange = true;
     
    globalBreakawayTime = 0;
    breakawayTimeVariance = 0;
     
   }
     
   public function get gradientColor1():uint {
    return _gradientColor1;
   }
     
   public function get gradientColor2():uint {
    return _gradientColor2;
   }
     
   public function set gradientColor1(input) {
    _gradientColor1 = uint(input);
    r1 = (_gradientColor1 >>16) & 0xFF;
    g1 = (_gradientColor1 >>8) & 0xFF;
    b1 = _gradientColor1 & 0xFF;
   }
     
   public function set gradientColor2(input) {
    _gradientColor2 = uint(input);
    r2 = (_gradientColor2 >>16) & 0xFF;
    g2 = (_gradientColor2 >>8) & 0xFF;
    b2 = _gradientColor2 & 0xFF;
   }
     
   //аргументы - x, y, velx, vely, color, thickness, splashing
   public function addDrop(x0:Number, y0:Number, ...args):LineRaindrop {
    numOnStage++;
    var drop:LineRaindrop;
    var dropColor:uint;
    var dropThickness:Number;
         
    //установим цвет
    if (args.length > 2) {
     dropColor = args[2];
    }
    else if (randomizeColor) {
     if (colorMethod == "gray") {
      param = 255*(minGray + (maxGray-minGray)*Math.random());
      dropColor = param << 16 | param << 8 | param;
     }
     if (colorMethod == "gradient") {
      param = Math.random();
      r = int(r1 + param*(r2 - r1));
      g = int(g1 + param*(g2 - g1));
      b = int(b1 + param*(b2 - b1));
      dropColor = (r << 16) | (g << 8) | b;
     }
     if (colorMethod == "random") {
      dropColor = Math.random()*0xFFFFFF;
     }
    }
    else {
     dropColor = defaultDropColor;
    }    
     
    //установим толщину
    if (args.length > 3) {
     dropThickness = args[3];
    }
    else {
     dropThickness = defaultDropThickness;
    }

    //проверим recycle bin для доступной капли:
    if (recycleBin.first != null) {
     numInRecycleBin--;
     drop = recycleBin.first;
     //удаляем из bin
     if (drop.next != null) {
      recycleBin.first = drop.next;
      drop.next.prev = null;
     }
     else {
      recycleBin.first = null;
     }
     drop.resetPosition(x0,y0);
     drop.visible = true;
    }
    //если recycle bin пустой, создаем новую каплю:
    else {
     drop = new LineRaindrop(x0,y0);
     //добавляем в дисплей лист
     this.addChild(drop);
    }
     
    drop.thickness = dropThickness;
    drop.color = dropColor;
     
    //добавляем в начало onStageList
    if (onStageList.first == null) {
     onStageList.first = drop;
     drop.prev = null; //может быть лишнее
     drop.next = null;
    }
    else {
     drop.next = onStageList.first;
     onStageList.first.prev = drop;  //может быть лишнее
     onStageList.first = drop;
     drop.prev = null; //может быть лишнее
    }
         
    //устанавливаем начальную скорость
    if (args.length < 2) {
     variance = (1+Math.random()*initialVelocityVariancePercent);
     drop.vel.x = defaultInitialVelocity.x*variance+Math.random()*initialVelocityVarianceX;
     drop.vel.y = defaultInitialVelocity.y*variance+Math.random()*initialVelocityVarianceY;
    }
    else {
     drop.vel.x = args[0];
     drop.vel.y = args[1];
    }
     
    //установим альфа
    if (args.length > 4) {
     drop.alpha = args[4];
    }
    else {
     drop.alpha = defaultDropAlpha;
    }
     
    //установим тип есть брызги/нет брызг type
    if (args.length > 5) {
     drop.splashing = args[5];
    }
    else {
     //выключим  всплеск (splashing) если глобально noSplashes установлено в  true.
     //иначе сдеаем каплю типа splashing.
     drop.splashing = !noSplashes;
    }
     
    drop.atTerminalVelocity = false;
     
    drop.lifespan = 0;
    drop.breakawayTime = globalBreakawayTime*(1+breakawayTimeVariance*Math.random());
     
    return drop;
   }
     
   public function update():void {
    var drop:LineRaindrop = onStageList.first;
    var nextDrop:LineRaindrop;
    while (drop != null) {
     //перед тем как списки изменятся, запишем следующую каплю
     nextDrop = drop.next;
     //двигаем все капли. Для каждой капли в onStageList:
       
     drop.lifespan++;
       
     //изменяем только, если время жизни капли  превысило время breakaway.
     if (drop.lifespan > drop.breakawayTime) {
       
      //запишем lastLastPos
      drop.lastLastPos.x = drop.lastPos.x;
      drop.lastLastPos.y = drop.lastPos.y;
       
      //запишем lastPos
      drop.lastPos.x = drop.p1.x;
      drop.lastPos.y = drop.p1.y;
       
      //изменим vel
      if (!drop.atTerminalVelocity) {
       drop.vel.y += gravity;
      }
       
      //изменим позицию p1
      //Из эстетических соображений мы применим меньший ветер к брызгам, чем к
      //падающим каплям.
      if (drop.splashing) {
       drop.p1.x += drop.vel.x + wind.x;
       drop.p1.y += drop.vel.y + wind.y;
      }
      else {
       drop.p1.x += drop.vel.x + windOnSplash*wind.x;
       drop.p1.y += drop.vel.y + windOnSplash*wind.y;
      }
       
      //изменим p0      
      if (dropLength == "long") {
       //use for longer drops:
       drop.p0.x = drop.lastLastPos.x;
       drop.p0.y = drop.lastLastPos.y;
      }
      else if (dropLength == "short") {
       drop.p0.x = drop.lastPos.x;
       drop.p0.y = drop.lastPos.y;
      }
      else {
       //можем добавить другие виды типа dropLength, например, постоянной длины.
      }
           
      //если капля вышла за сцену, добавляем ее в recycle bin, делаем невидимой
      if (removeDropsOutsideXRange) {
       left = Math.min(drop.p0.x,drop.p1.x);
       right = Math.max(drop.p0.x,drop.p1.x);
       outsideTest = ((drop.p0.y > displayHeight)||(right < 0)||(left > displayWidth));
       //у нас нет необходимости создавать всплеск для капель, которые исчезают по сторонам
       drop.splashing = false;
      }
      else {
       outsideTest = (drop.p0.y > displayHeight);
      }
      if (outsideTest) {
       recycleDrop(drop);
      }
     }
       
     //вызываем функцию перерисовкми
     drop.redraw();

     drop = nextDrop;
    }
   }
     
   public function recycleDrop(drop:LineRaindrop):void {
    numOnStage--;
    numInRecycleBin++;
     
    if (drop.splashing) {
     //находим правильное положение для всплеска (интерполируем в обратном направлении по времени
     //чтобы найти, где капля пересечет уровень земли, при условии, что скорость постоянна)
     dropX = drop.p0.x + (displayHeight-drop.p0.y)*(drop.p1.x-drop.p0.x)/(drop.p1.y-drop.p0.y);
     createSplash(dropX, drop.color);
    }
     
    drop.visible = false;
     
    //удаляем из onStageList
    if (onStageList.first == drop) {
     if (drop.next != null) {
      drop.next.prev = null;
      onStageList.first = drop.next;
     }
     else {
      onStageList.first = null;
     }
    }
    else {
     if (drop.next == null) {
      drop.prev.next = null;
     }
     else {
      drop.prev.next = drop.next;
      drop.next.prev = drop.prev;
     }
    }

    //добавляем в  recycle bin
    if (recycleBin.first == null) {
     recycleBin.first = drop;
     drop.prev = null; //может быть лишним
     drop.next = null;
    }
    else {
     drop.next = recycleBin.first;
     recycleBin.first.prev = drop;  //может быть лишним
     recycleBin.first = drop;
     drop.prev = null; //может быть лишним
    }
   }
     
   private function createSplash(x0:Number, c:uint):void {
    numSplashDrops = Math.ceil(minSplashDrops + Math.random()*(maxSplashDrops - minSplashDrops));
    for (var i:int = 0; i<=numSplashDrops-1; i++) {
     //аргументы - x, y, velx, vely, color, thickness
     var randomSplashSize:Number = 0.75+0.75*Math.random();
     var velX:Number = randomSplashSize*(splashMinVelX+Math.random()*(splashMaxVelX-splashMinVelX));
     var velY:Number = -randomSplashSize*(splashMinVelY+Math.random()*(splashMaxVelY-splashMinVelY));
     var thisDrop = addDrop(x0, displayHeight, velX, velY, c, splashThickness, splashAlpha, false);
     thisDrop.breakawayTime = 0;
    }
   }
     
     
}
}


Скачать


Требуются: Модераторы, Журналист новостей, Дизайнер!
Shop Flash-JePo
 
Реклама
  • Страница 1 из 1
  • 1
Поиск: