- 积分
- 136119
- 注册时间
- 2014-12-27
- 最后登录
- 2024-3-28
- 在线时间
- 602 小时
- 威望
- 562
- 贡献
- 29
- 金币
- 52623
- 钢镚
- 1422
- 交易凭证
- 1
- 分享
- 0
- 精华
- 33
- 帖子
- 2094
- 主题
- 1742
TA的每日心情 | 擦汗 2018-4-10 15:18 |
---|
签到天数: 447 天 [LV.9]以坛为家II
超级版主
- 威望
- 562
- 贡献
- 29
- 金币
- 52623
- 钢镚
- 1422
|
- /*
- * 混相流 / Multiphase flow
- *
- * いくつかの種類の液体のシミュレーションです。
- * クリックで注ぎます。
- * Click:Pouring
- */
- package {
- import flash.utils.*;
- import flash.text.*;
- import flash.filters.*;
- import flash.geom.*;
- import flash.events.*;
- import flash.display.*;
- import net.hires.debug.Stats;
- [SWF(frameRate = "60")]
- public class Fluid extends Sprite {
- public static const GRAVITY:Number = 0.05;//重力
- public static const RANGE:Number = 16;//影響半径
- public static const RANGE2:Number = RANGE * RANGE;//影響半径の二乗
- public static const DENSITY:Number = 2.5;//流体の基準(安定する)密度
- public static const PRESSURE:Number = 1;//圧力係数
- public static const PRESSURE_NEAR:Number = 1;//近距離圧力係数
- public static const VISCOSITY:Number = 0.1;//粘性係数
- public static const NUM_GRIDS:int = 29;//グリッド数(≒ 465 / RANGE)
- public static const INV_GRID_SIZE:Number = 1 / (465 / NUM_GRIDS);//グリッドサイズの逆数(≒ 1 / RANGE)
- private var particles:Vector.<Particle>;
- private var numParticles:uint;
- private var neighbors:Vector.<Neighbor>;
- private var numNeighbors:uint;
- private var count:int;
- private var press:Boolean;
- private var bitmap:BitmapData;
- private var grids:Vector.<Vector.<Grid>>;
- private const COLOR_TRANSFORM:ColorTransform = new ColorTransform(0.5, 0.5, 0.5);
- public function Fluid() {
- initialize();
- }
- private function initialize():void {
- particles = new Vector.<Particle>();
- numParticles = 0;
- neighbors = new Vector.<Neighbor>();
- numNeighbors = 0;
- grids = new Vector.<Vector.<Grid>>(NUM_GRIDS, true);
- for(var i:int = 0; i < NUM_GRIDS; i++) {
- grids[i] = new Vector.<Grid>(NUM_GRIDS, true);
- for(var j:int = 0; j < NUM_GRIDS; j++)
- grids[i][j] = new Grid();
- }
- count = 0;
- bitmap = new BitmapData(465, 465, false, 0);
- addChild(new Bitmap(bitmap));
- // var s:Stats = new Stats();
- // s.alpha = 0.8;
- // addChild(s);
- addEventListener(Event.ENTER_FRAME, frame);
- stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void {press = true;});
- stage.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void {press = false;});
- }
- private function frame(e:Event):void {
- if(press)
- pour();
- move();
- }
- private function pour():void {
- for(var i:int = -4; i <= 4; i++) {
- particles[numParticles++] = new Particle(mouseX + i * 10, mouseY,
- count / 10 % 5);
- particles[numParticles - 1].vy = 5;
- }
- }
- private function move():void {
- count++;
- updateGrids();
- findNeighbors();
- calcForce();
- bitmap.lock();
- bitmap.colorTransform(bitmap.rect, COLOR_TRANSFORM);
- for(var i:uint = 0; i < numParticles; i++) {
- const p:Particle = particles[i];
- p.move();
- bitmap.fillRect(new Rectangle(p.x - 1, p.y - 1, 3, 3), p.color);
- }
- bitmap.unlock();
- }
- private function updateGrids():void {
- var i:uint;
- var j:uint;
- for(i = 0; i < NUM_GRIDS; i++)
- for(j = 0; j < NUM_GRIDS; j++)
- grids[i][j].numParticles = 0;
- for(i = 0; i < numParticles; i++) {
- const p:Particle = particles[i];
- p.fx = p.fy = p.density = p.densityNear = 0;
- p.gx = p.x * INV_GRID_SIZE; // グリッドのどこにいるか計算
- p.gy = p.y * INV_GRID_SIZE;
- if(p.gx < 0) // グリッドから外れてたら一番近いとこに入ってることにする
- p.gx = 0;
- if(p.gy < 0)
- p.gy = 0;
- if(p.gx > NUM_GRIDS - 1)
- p.gx = NUM_GRIDS - 1;
- if(p.gy > NUM_GRIDS - 1)
- p.gy = NUM_GRIDS - 1;
- }
- }
- private function findNeighbors():void { // 空間分割で近接粒子を計算
- numNeighbors = 0;
- for(var i:uint = 0; i < numParticles; i++) {
- const p:Particle = particles[i];
- const xMin:Boolean = p.gx != 0;
- const xMax:Boolean = p.gx != NUM_GRIDS - 1;
- const yMin:Boolean = p.gy != 0;
- const yMax:Boolean = p.gy != NUM_GRIDS - 1;
- findNeighborsInGrid(p, grids[p.gx][p.gy]);
- if(xMin) findNeighborsInGrid(p, grids[p.gx - 1][p.gy]);
- if(xMax) findNeighborsInGrid(p, grids[p.gx + 1][p.gy]);
- if(yMin) findNeighborsInGrid(p, grids[p.gx][p.gy - 1]);
- if(yMax) findNeighborsInGrid(p, grids[p.gx][p.gy + 1]);
- if(xMin && yMin) findNeighborsInGrid(p, grids[p.gx - 1][p.gy - 1]);
- if(xMin && yMax) findNeighborsInGrid(p, grids[p.gx - 1][p.gy + 1]);
- if(xMax && yMin) findNeighborsInGrid(p, grids[p.gx + 1][p.gy - 1]);
- if(xMax && yMax) findNeighborsInGrid(p, grids[p.gx + 1][p.gy + 1]);
- grids[p.gx][p.gy].add(p);
- }
- }
- private function findNeighborsInGrid(pi:Particle, g:Grid):void {
- for(var j:uint = 0; j < g.numParticles; j++) {
- var pj:Particle = g.particles[j];
- const distance:Number = (pi.x - pj.x) * (pi.x - pj.x) + (pi.y - pj.y) * (pi.y - pj.y);
- if(distance < RANGE2) {
- if(neighbors.length == numNeighbors)
- neighbors[numNeighbors] = new Neighbor();
- neighbors[numNeighbors++].setParticle(pi, pj);
- }
- }
- }
- private function calcForce():void {
- for(var i:uint = 0; i < numNeighbors; i++)
- neighbors[i].calcForce();
- }
- }
- }
- class Particle {
- public var x:Number;
- public var y:Number;
- public var gx:int;
- public var gy:int;
- public var vx:Number;
- public var vy:Number;
- public var fx:Number;
- public var fy:Number;
- public var density:Number;
- public var densityNear:Number;
- public var color:int;
- public var type:int;
- public const GRAVITY:Number = Fluid.GRAVITY;
- public function Particle(x:Number, y:Number, type:int) {
- this.x = x;
- this.y = y
- this.type = type;
- vx = vy = fx = fy = 0;
- switch(type) {
- case 0:
- color = 0x6060ff;
- break;
- case 1:
- color = 0xff6000;
- break;
- case 2:
- color = 0xff0060;
- break;
- case 3:
- color = 0x00d060;
- break;
- case 4:
- color = 0xd0d000;
- break;
- }
- }
- public function move():void {
- vy += GRAVITY;
- if(density > 0) {
- vx += fx / (density * 0.9 + 0.1); // 本当は密度で割る計算だけど0に近かった時に
- vy += fy / (density * 0.9 + 0.1); // 粒子が飛び出すから微調整
- }
- x += vx;
- y += vy;
- if(x < 5) // 壁境界
- vx += (5 - x) * 0.5 - vx * 0.5;
- if(x > 460)
- vx += (460 - x) * 0.5 - vx * 0.5;
- if(y < 5)
- vy += (5 - y) * 0.5 - vy * 0.5;
- if(y > 460)
- vy += (460 - y) * 0.5 - vy * 0.5;
- }
- }
- class Neighbor {
- public var p1:Particle;
- public var p2:Particle;
- public var distance:Number;
- public var nx:Number;
- public var ny:Number;
- public var weight:Number;
- public const RANGE:Number = Fluid.RANGE;
- public const PRESSURE:Number = Fluid.PRESSURE;
- public const PRESSURE_NEAR:Number = Fluid.PRESSURE_NEAR;
- public const DENSITY:Number = Fluid.DENSITY;
- public const VISCOSITY:Number = Fluid.VISCOSITY;
- public function Neighbor() {
- }
- public function setParticle(p1:Particle, p2:Particle):void { // 使いまわし
- this.distance = distance;
- this.p1 = p1;
- this.p2 = p2;
- nx = p1.x - p2.x;
- ny = p1.y - p2.y;
- distance = Math.sqrt(nx * nx + ny * ny);
- weight = 1 - distance / RANGE;
- var density:Number = weight * weight; // 普通の圧力カーネルは距離の二乗
- p1.density += density;
- p2.density += density;
- density *= weight * PRESSURE_NEAR; // 粒子が近づきすぎないよう近距離用のカーネルを計算
- p1.densityNear += density;
- p2.densityNear += density;
- const invDistance:Number = 1 / distance;
- nx *= invDistance;
- ny *= invDistance;
- }
- public function calcForce():void {
- var p:Number;
- if(p1.type != p2.type) // 違うタイプの粒子なら安定する密度をちょっと減らす
- p = (p1.density + p2.density - DENSITY * 1.5) * PRESSURE;
- else // 同じタイプなら普通に計算
- p = (p1.density + p2.density - DENSITY * 2) * PRESSURE;
- const pn:Number = (p1.densityNear + p2.densityNear) * PRESSURE_NEAR; // 基準密度に関係なく近づきすぎたら跳ね返す!
- var pressureWeight:Number = weight * (p + weight * pn); // 結果としてかかる圧力
- var viscosityWeight:Number = weight * VISCOSITY;
- var fx:Number = nx * pressureWeight;
- var fy:Number = ny * pressureWeight;
- fx += (p2.vx - p1.vx) * viscosityWeight; // 単純に粘性項を解く
- fy += (p2.vy - p1.vy) * viscosityWeight;
- p1.fx += fx;
- p1.fy += fy;
- p2.fx -= fx;
- p2.fy -= fy;
- }
- }
- class Grid {
- public var particles:Vector.<Particle>;
- public var numParticles:uint;
- public function Grid() {
- particles = new Vector.<Particle>;
- }
- public function add(p:Particle):void {
- particles[numParticles++] = p;
- }
- }
复制代码
本文来自:http://wonderfl.net/c/qszD
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|