The Boids + DoF (Depth of Field)
/**
* Copyright bradsedito ( http://wonderfl.net/user/bradsedito )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/rEmw
*/
package {
import flash.filters.BlurFilter;
import com.flashdynamix.utils.SWFProfiler;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import flash.geom.Vector3D;
import com.greensock.*;
import com.greensock.easing.*;
[SWF(backgroundColor="0xffffff", frameRate="100", width="465", height="465")]
public class Trick extends Sprite {
private var SCREEN_WIDTH:Number, SCREEN_HEIGHT:Number, SCREEN_WIDTH_HALF:Number, SCREEN_HEIGHT_HALF:Number;
private var camera:Camera3D, bird:Object3D, birds:Vector.<Object3D>, boid:Boid, boids:Vector.<Boid>;
private var perspective:PerspectiveProjection
public var stats:SWFProfiler = new SWFProfiler();
// public var blurr:BlurFilter = new BlurFilter;
public function Trick() {
// SWFProfiler.init(stage, this);
init();
}
private function init():void
{
SWFProfiler.init(this);
SCREEN_WIDTH = stage.stageWidth;
SCREEN_HEIGHT = stage.stageHeight;
SCREEN_WIDTH_HALF = SCREEN_WIDTH / 2;
SCREEN_HEIGHT_HALF = SCREEN_HEIGHT / 2;
camera = new Camera3D();
birds = new Vector.<Object3D>();
boids = new Vector.<Boid>();
for (var i:uint = 0; i < 100; i++ ) {
boid = boids[i] = new Boid();
boid.position.x = Math.random() * 400 - 200;
boid.position.y = Math.random() * 400 - 200;
boid.position.z = Math.random() * 400 - 200;
boid.velocity.x = Math.random() * 2 - 1;
boid.velocity.y = Math.random() * 2 - 1;
boid.velocity.z = Math.random() * 2 - 1;
boid.setAvoidWalls( true );
boid.setWorldSize( 180, 180, 380 );
bird = birds[i] = new Object3D(camera);
bird.worldMatrix3D.position = boids[i].position;
addChild(bird);
}
stage.addEventListener(Event.ENTER_FRAME, update);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
}
private function update(e:Event=null):void {
for ( var i:uint = 0; i< birds.length; i++ ) {
boid = boids[ i ];
boid.run( boids );
bird = birds[ i ];
bird.worldMatrix3D.appendRotation(Math.atan2( - boid.velocity.z, boid.velocity.x ), Vector3D.Y_AXIS);
bird.worldMatrix3D.appendRotation(Math.asin( boid.velocity.y / boid.velocity.length ), Vector3D.Z_AXIS);
bird.worldMatrix3D.position = boid.position;
bird.world.z = boid.position.z;
var vb:Number = new Number ( bird.world.z );
bird.world.alpha = ( 300 - bird.worldMatrix3D.position.z ) / 200;
TweenMax.to(bird, 1, {blurFilter:{blurX:vb*.1 , blurY:vb*.1 , quality:3}});
bird.update();
}
}
private function mouseMove(e:MouseEvent):void {
var vector:Vector3D = new Vector3D(stage.mouseX - SCREEN_WIDTH_HALF, -stage.mouseY + SCREEN_HEIGHT_HALF, 0)
for ( var i:uint = 0; i < boids.length; i++ ) {
boid = boids[ i ];
vector.z = boid.position.z;
boid.repulse( vector );
}
}
}
}
import flash.geom.Vector3D;
class Boid {
public var position:Vector3D, velocity:Vector3D;
private var vector:Vector3D, acceleration:Vector3D;
private var width:Number = 480, height:Number = 480, depth:Number = 200, goal:Vector3D, neighborhoodRadius:Number = 100;
private var maxSpeed:Number = 4, maxSteerForce:Number = 0.1, avoidWalls:Boolean = false;
public function Boid():void {
init();
}
private function init():void {
position = new Vector3D();
velocity = new Vector3D();
vector = new Vector3D();
acceleration = new Vector3D();
}
public function setGoal(target:Vector3D):void {
goal = target;
}
public function setAvoidWalls(val:Boolean):void {
avoidWalls = val;
}
public function setWorldSize(width:Number, height:Number, depth:Number):void {
this.width = width;
this.height = height;
this.depth = depth;
}
public function run(boids:Vector.<Boid>):void {
if ( avoidWalls ) {
vector = new Vector3D( -width, position.y, position.z );
vector = avoid( vector );
vector.scaleBy( 5 );
acceleration.incrementBy( vector );
vector = new Vector3D( width, position.y, position.z );
vector = avoid( vector );
vector.scaleBy( 5 );
acceleration.incrementBy( vector );
vector = new Vector3D( position.x, -height, position.z );
vector = avoid( vector );
vector.scaleBy( 5 );
acceleration.incrementBy( vector );
vector = new Vector3D( position.x, height, position.z );
vector = avoid( vector );
vector.scaleBy( 5 );
acceleration.incrementBy( vector );
vector = new Vector3D( position.x, position.y, -depth );
vector = avoid( vector );
vector.scaleBy( 5 );
acceleration.incrementBy( vector );
vector = new Vector3D( position.x, position.y, depth );
vector = avoid( vector );
vector.scaleBy( 5 );
acceleration.incrementBy( vector );
}
checkBounds();
if ( Math.random() > 0.5 ) {
flock( boids );
}
move();
}
private function flock(boids:Vector.<Boid>):void {
if ( goal ) {
acceleration.incrementBy( reach( goal, 0.005 ) );
}
acceleration.incrementBy( alignment( boids ) );
acceleration.incrementBy( cohesion( boids ) );
acceleration.incrementBy( separation( boids ) );
}
private function move():void {
velocity.incrementBy( acceleration );
var l:Number = velocity.length;
if ( l > maxSpeed ) {
velocity.scaleBy( 1 / (l / maxSpeed) );
}
position.incrementBy( velocity );
acceleration = new Vector3D();
}
private function checkBounds():void {
if ( position.x > width ) position.x = -width;
if ( position.x < -width ) position.x = width;
if ( position.y > height ) position.y = -height;
if ( position.y < -height ) position.y = height;
if ( position.z > depth ) position.z = -depth;
if ( position.z < -depth ) position.z = depth;
}
private function avoid(target:Vector3D):Vector3D {
var steer:Vector3D = position.clone();
steer.decrementBy( target );
steer.scaleBy( 1 / distanceToSquared( position, target ));
return steer;
}
private function sub(v1:Vector3D, v2:Vector3D):Vector3D {
var dis:Vector3D = new Vector3D();
dis.x = v1.x - v2.x;
dis.y = v1.y - v2.y;
dis.z = v1.z - v2.z;
return dis;
}
private function distanceToSquared(v1:Vector3D, v2:Vector3D):Number {
var dis:Vector3D = sub(v1, v2);
var sq:Number = dis.lengthSquared;
return sq;
}
public function repulse(target:Vector3D):void {
var distance:Number = Vector3D.distance(position, target);
if ( distance < 150 ) {
var steer:Vector3D = sub( position, target );
steer.scaleBy( 1 / distance );
acceleration.incrementBy( steer );
}
}
private function reach(target:Vector3D, amount:Number):Vector3D {
var steer:Vector3D = sub( target, position );
steer.scaleBy( amount );
return steer;
}
//整列
private function alignment(boids:Vector.<Boid>):Vector3D {
var boid:Boid, count:Number = 0;
var velSum:Vector3D = new Vector3D();
for ( var i:uint = 0; i < boids.length; i++ ) {
if ( Math.random() > 0.6 ) continue;
boid = boids[i];
var distance:Number = Vector3D.distance(boid.position, position);
if ( distance > 0 && distance <= neighborhoodRadius ) {
velSum.incrementBy( boid.velocity );
count++;
}
}
if ( count > 0 ) {
velSum.scaleBy( 1 / count );
var l:Number = velSum.length;
if ( l > maxSteerForce ) {
velSum.scaleBy( 1 / (l / maxSteerForce) );
}
}
return velSum;
}
//結合
private function cohesion(boids:Vector.<Boid>):Vector3D {
var boid:Boid, distance:Number, count:Number = 0;
var steer:Vector3D = new Vector3D();
var posSum:Vector3D = new Vector3D();
for ( var i:uint = 0; i < boids.length; i++ ) {
if ( Math.random() > 0.6 ) continue;
boid = boids[i];
distance = Vector3D.distance(boid.position, position);
if ( distance > 0 && distance <= neighborhoodRadius ) {
posSum.incrementBy( boid.position );
count++;
}
}
if ( count > 0 ) {
posSum.scaleBy( 1 / count );
}
steer = sub( posSum, position );
var l:Number = steer.length;
if ( l > maxSteerForce ) {
steer.scaleBy( 1 / (l / maxSteerForce) );
}
return steer;
}
//引き離し
private function separation(boids:Vector.<Boid>):Vector3D {
var boid:Boid, distance:Number, repulse:Vector3D;
var posSum:Vector3D = new Vector3D();
for ( var i:uint=0; i < boids.length; i++ ) {
if ( Math.random() > 0.6 ) continue;
boid = boids[ i ];
distance = Vector3D.distance(boid.position, position);
if ( distance > 0 && distance <= neighborhoodRadius ) {
repulse = sub(position, boid.position);
repulse.normalize();
repulse.scaleBy( 1 / distance );
posSum.incrementBy(repulse);
}
}
return posSum;
}
}
import flash.geom.Matrix3D;
import flash.geom.Vector3D;
import flash.geom.PerspectiveProjection;
class Camera3D extends Matrix3D {
//3D
private var perspective:PerspectiveProjection = new PerspectiveProjection();
private var viewFocus:Number = 10000;
public function Camera3D():void {
init();
}
private function init():void {
perspective.focalLength = viewFocus; //焦点距離
appendTranslation(0, 0, -10000);
append(perspective.toMatrix3D());
}
}
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.Utils3D;
class Object3D extends Sprite {
private var size:uint = 10;
//2D
public var world:Sprite = new Sprite();
protected var vertices2D:Vector.<Number> = new Vector.<Number>();
//3D
public var worldMatrix3D:Matrix3D = new Matrix3D();
protected var camera3d:Camera3D;
protected var vertices3D:Vector.<Number>;
protected var indices:Vector.<int>;
protected var uvtData:Vector.<Number>;
//Draw
protected var bmpData:BitmapData;
public function Object3D(camera3d:Camera3D):void {
this.camera3d = camera3d;
addChild(this.world);
init();
}
private function init():void {
var sprite:Sprite = new Sprite();
sprite.graphics.beginFill(0x111);
sprite.graphics.drawRect( 0,0,10,10 );
sprite.graphics.endFill();
bmpData = new BitmapData(size, size, true);
bmpData.draw(sprite);
vertices3D = new Vector.<Number>();
indices = new Vector.<int>();
uvtData = new Vector.<Number>();
world.x = 250;
world.y = 250;
addChild(world);
var nUnit:Number = size / 2;
vertices3D.push(-nUnit, -nUnit, 0);
vertices3D.push(nUnit, -nUnit, 0);
vertices3D.push(-nUnit, nUnit, 0);
vertices3D.push(nUnit, nUnit, 0);
indices.push(0, 1, 2);
indices.push(1, 3, 2);
uvtData.push(0, 0, 0);
uvtData.push(1, 0, 0);
uvtData.push(0, 1, 0);
uvtData.push(1, 1, 0);
}
public function update():void {
//3D処理
var matrix3D:Matrix3D = worldMatrix3D.clone();
matrix3D.append(camera3d);
Utils3D.projectVectors(matrix3D, vertices3D, vertices2D, uvtData);
//描画
world.graphics.clear();
world.graphics.beginBitmapFill(bmpData);
world.graphics.drawTriangles(vertices2D, indices, uvtData);
world.graphics.endFill();
}
}