Math and (Quasi) Physics in Action Script 3

Fluid simulation with 10000 particles

Fluid simulation with 10000 particles.

Main.as

package {
  import flash.display.*;
  import flash.events.*;
  import flash.filters.*;
  import flash.geom.*;

  public class Main extends Sprite {
    private var mapHN:uint = 30,mapVN:uint = 30, sh:uint, sw:uint;
    private var tr:Number = 0.95, tg:Number = 0.95, tb:Number = 0.95;
    private var mapW:Number,mapH:Number;
    private var mX:Number,mY:Number;
    private var map:Array;
    private var particles:Array;
    private var numParticles:uint = 10000;
    private var canvas:BitmapData;

    public function Main() {
      sw = stage.stageWidth;
      sh = stage.stageHeight;
      graphics.beginFill(0xffffff);
      graphics.drawRect(0,0,sw,sh);
      graphics.endFill();
      canvas = new BitmapData(sw,sh,true,0x00ffffff);
      addChild(new Bitmap(canvas));
      var i:uint,j:uint;
      mapW = sw / mapHN;
      mapH = sw / mapVN;
      map = [];
      
      var m:Object;
      for (j = 0; j < mapVN; j ++) {
        map.push([]);
        for (i = 0; i < mapHN; i ++) {
          map[j].push(m = new Object);
          
          m.vx = Math.random() * 10- 5;
          m.vy = Math.random() * 10 - 5;
        }
      }
      
      var p:Particle;
      particles = [];
      for (i = 0; i < numParticles; i ++) {
        particles.push(p = new Particle(sw, sh));
      }
      
      addEventListener(Event.ENTER_FRAME, h_enterFrame);
    }

    private function h_enterFrame(evt:Event):void {
      var i:uint,j:uint,k:int,l:int,cnt:uint,tvx:Number,tvy:Number;
      var p:Particle,m:Object;
      var temp:BitmapData = new BitmapData(sw,sh,true,0x00000000);
      for (i = 0; i < numParticles; i ++) {
        p = particles[i];
        m = map[Math.floor(p.x / mapW)][Math.floor(p.y / mapH)];
        p.vx = (p.vx +(m.vx  - p.vx) / 10) * 0.99;
        p.vy = (p.vy + (m.vy  - p.vy) / 10) * 0.99;
        p.x += p.vx;
        p.y+= p.vy;
        if (p.x < 0 || p.y < 0 || p.x >= sw || p.y >= sw || Math.random() < 0.01) {
          p.init();
        }
        temp.setPixel32(p.x, p.y, 0xffffffff);
      }
      
      for (j = 0; j < mapVN; j ++) {
        for (i = 0; i < mapHN; i ++) {
          cnt  = 30;
          tvx = map[i][j].vx * cnt;
          tvy = map[i][j].vy * cnt;
          for (k = -2; k <=2; k ++) {
            if (i + k < 0 || i + k >= map.length) { continue }
            for (l = -2; l <= 2; l ++) {
              if (j + l < 0 || j + l >= map[i + k].length) { continue }
                tvx += map[i + k][j + l].vx;
                tvy += map[i + k][j + l].vy;
                cnt ++;
            }
          }
          map[i][j].vx = tvx / cnt;
          map[i][j].vy = tvy / cnt;
        }
      }
      
      if (mX || mY) {
        m = map[Math.floor(mX / mapW)][Math.floor(mY / mapH)];
        m.vx = (m.vx +(mouseX - mX) * 5) * 0.99;
        m.vy = (m.vy + (mouseY - mY) * 5) * 0.99;
      }
      mX = Math.max(0,Math.min(mouseX, sw - 1));
      mY = Math.max(0,Math.min(mouseY, sh - 1));
      
      var filter:BitmapFilter;
      if (Math.random() < 0.05) {
        tr = Math.random() / 5 + 0.85;
        tg = Math.random() / 5 + 0.85;
        tb = Math.random() / 5 + 0.85;
      }
      filter = new ColorMatrixFilter([tr,0,0,0,0,  0,tg,0,0,0,  0,0,tb,0,0,  0,0,0,0.96,0]);
      canvas.applyFilter(canvas,new Rectangle(0,0,sw,sh),new Point(),filter);
      
      filter= new BlurFilter(4,4);
      canvas.applyFilter(canvas,new Rectangle(0,0,sw,sh),new Point(),filter);
      
        
      canvas.draw(temp, new Matrix(), new ColorTransform(1,1,1,0.5,0,0,0,0),BlendMode.ADD);
    }
  }
}

class Particle {
  public var x:Number,y:Number, vx:Number, vy:Number, sw:uint, sh:uint;
  function Particle(w:uint, h:uint) {
    sw = w;
    sh = h;
    vx = vy = 0;
    init();
  }
  public function init():void {
    x = Math.random() * sw;
    y = Math.random() * sh;
    
  }
}