Pure JavaScript animation.
The basic concept for these particle animations started with some basic physics after being curious what the terminal velocity of rain is.
Originally code was written in 2013 in AS3 (Flash ActionScript 3).
//look up any objects density (water has a density of 1) and drag coefficient (http://en.wikipedia.org/wiki/Drag_coefficient)
//changing the stage dimensions will not affect the code
// time is derived from 60 frames per second in the calculations
stage.frameRate = 60;
// holds the falling objects
var dropsVector: Vector. < Sprite > =new Vector. < Sprite > ();
// holds the time for each object - the calculations on enter frame below are all functions of time
var framesVector: Vector. < Number > =new Vector. < Number > ();
// holds what the velocity is for each object
var velocityVector: Vector. < Number > =new Vector. < Number > ();
var numOfDrops: Number = 300;
//gravity here is 9.8 pixels
var gravity: Number = 9.8;
// how close together the stuff this object is made of is
var density: Number = 1;
// how thick is the air
var airDensity: Number = 1.29;
//how much air does the object "catch" increase to slow down an decrease to speed up
var dragCoefficient: Number = .47;
//minimum and maximum scale of the water droplets
var maxScale: Number = 1.3;
var minScale: Number = .3;
// create all the droplets doesn't have to be a Sprite could be sprite or you could create a clip give it a class name and add it in place of the circle
for (var i: Number = 0; i < numOfDrops; i++) {
var rainDrop: Sprite = new Sprite();
rainDrop.graphics.beginFill(0x82CDFF, 1);
rainDrop.graphics.drawCircle(0, 0, 1);
rainDrop.graphics.endFill();
//set a random location on the stage so it isn't blank with a sudden shower of water - neat experiment though just get rid of the Math.Random()* before rainDrop.y
rainDrop.x = Math.random() * stage.stageWidth;
rainDrop.y = Math.random() * stage.stageHeight * -2;
rainDrop.scaleX = Math.random() * (maxScale - minScale) + minScale;
rainDrop.scaleY = rainDrop.scaleX;
//put a value for each droplet into the holders (object, time, velocity)
dropsVector.push(rainDrop);
framesVector.push(0);
velocityVector.push(0);
}
// super cool guy Dan Geis wrote this stuff (http://www.flashandmath.com/intermediate/ghost/)
// its pretty simple and very cool - basically create a bitmap (image) redraw all those droplets every frame and blur the previous one makes pretty trails
var bitmapData: BitmapData;
var bitmap: Bitmap;
var displayWidth: Number;
var displayHeight: Number;
var display: Sprite;
var origin: Point;
var colorTransform1: ColorTransform;
display = new Sprite();
displayWidth = stage.stageWidth;
displayHeight = stage.stageHeight;
bitmapData = new BitmapData(displayWidth, displayHeight, true, 0x00000000);
bitmap = new Bitmap(bitmapData);
var blur: BlurFilter = new BlurFilter();
blur.blurX = 2;
blur.blurY = 2;
colorTransform1 = new ColorTransform(0.999, 0.999, 0.999, .8);
origin = new Point(0, 0);
bitmap.x = 0;
bitmap.y = 0;
addChild(bitmap);
//end Dan's code
addEventListener(Event.ENTER_FRAME, rainDown);
function rainDown(event: Event) {
for (var n: Number = 0; n < dropsVector.length; n++) {
// keeps track of time falling for each droplet
framesVector[n] = framesVector[n] + 1;
var time: Number = framesVector[n] / 60;
// all this stuff is what really calculates the terminal velocity... these are not perfect measurements
var velocity: Number = .5 * (gravity * Math.pow(time, 2));
var volume_: Number = ((4 / 3) * (Math.PI * Math.pow((dropsVector[n].width / 2), 3)));
// spherical object volume if you want a none a spherical object look up the volume formula for said object and apply it here
var mass: Number = density * volume_;
// mass "how much stuff there is"
var weight: Number = gravity * mass;
// not really weight of the object this is a reference to something more like force of the object due to gravity
var area: Number = Math.PI * Math.pow(dropsVector[n].width / 2, 2);
// cross sectional area, if you chop and object exactly down the middle at its widest point and take the area of that, that is the cross sectional area again I'm taking a circular area
var drag: Number = dragCoefficient * (.5 * (airDensity * Math.pow(velocity, 2))) * area;
//calculates the drag based on the air density the cross sectional area and drag coefficient
var terminalVelocity: Number = (weight - drag) / mass;
//when the weight force and drag equal each-other that is terminal velocity, test this out for yourself change the drag coefficient to 0 move all the object to the same location on the y axis and run the program, they all fall at exactly the same speed
if (terminalVelocity >= 0) {
//test that terminal velocity is equal to 0 (weight-drag)/mass = 0... terminal velocity
velocityVector[n] = velocity;
}
// move the droplets down
dropsVector[n].y += velocityVector[n];
// if the droplets go off the stage move them back to the top... no real need for the x test here unless you decide to make wind :)
if (dropsVector[n].x > stage.stageWidth || dropsVector[n].x < 0 || dropsVector[n].y > stage.stageHeight) {
//reset the time, scale, location to some random settings
framesVector[n] = 0;
dropsVector[n].x = Math.random() * stage.stageWidth;
dropsVector[n].y = dropsVector[n].height * -1;
//if you want to stop the dripping look change -1 to a larger negative number
dropsVector[n].scaleX = Math.random() * (maxScale - minScale) + minScale;
dropsVector[n].scaleY = dropsVector[n].scaleX;
}
// adds the droplets to the display where the bitmap is draw that adds the trails
display.addChild(dropsVector[n]);
}
// draws the bitmap
bitmapData.applyFilter(bitmapData, bitmapData.rect, origin, blur);
bitmapData.colorTransform(bitmapData.rect, colorTransform1);
bitmapData.draw(display);
}