カラーパーティクル
カラーパーティクル
色はパーティクルにかかる力の方向で決定
@author tkinjo
/**
* Copyright tkinjo ( http://wonderfl.net/user/tkinjo )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/x3uc
*/
// forked from tkinjo's パーティクルテスト
// forked from tkinjo's パーリンノイズの生成とフレームスキップ
package
{
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.utils.*;
import net.hires.debug.Stats;
[SWF(width="465", height="465", backgroundColor="0x0", frameRate="30")]
/**
* カラーパーティクル
*
* 色はパーティクルにかかる力の方向で決定
*
* @author tkinjo
*/
public class Main extends Sprite
{
// farame skip setting
private const FRAME_SKIP_MARGIN:uint = 0;
// force map setting
private const FORCE_MAP_CREATE_BY_ENTER_FRAME:Boolean = true;
private const FORCE_MAP_SCALE:uint = 3;
private const OFFSET_SPEED:Number = 1;
private const NUM_OCTAVES:uint = 4;
// particle setting
private const PARTICLE_NUM:uint = 1000;
private const FRAME_SKIP_DRAW_PARTICLE:Boolean = false;
// view setting
private const FADE_OUT_COLOR_TRANSFORM:ColorTransform = new ColorTransform( 1, 1, 1, 1, -8, -8, -8);
private var stageWidth:Number = stage.stageWidth;
private var stageHeight:Number = stage.stageHeight;
private var frameSkipper:FrameSkipper;
private var forceMapBitmap:Bitmap;
private var forceMapBitmapData:BitmapData;
private var offsets:Array;
private var seed:uint;
private var particles:Particle;
private var viewBitmapData:BitmapData;
private var viewBitmap:Bitmap;
public function Main()
{
frameSkipper = new FrameSkipper( stage.frameRate, FRAME_SKIP_MARGIN );
forceMapBitmapData = new BitmapData( stageWidth >> FORCE_MAP_SCALE, stageHeight >> FORCE_MAP_SCALE );
offsets = new Array();
for ( var i:uint = 0; i < NUM_OCTAVES; i++ )
offsets.push( new Point() );
seed = Math.random() * 0xffff;
// create particle
var previousParticle:Particle = particles = new Particle( Math.random() * 465, Math.random() * 465 );
var particle:Particle;
for ( i = 0; i < PARTICLE_NUM; i++) {
previousParticle.next = particle = new Particle( Math.random() * 465, Math.random() * 465 );
previousParticle = particle;
}
// create view bitmap
viewBitmapData = new BitmapData( stageWidth, stageHeight, false, 0x0 );
viewBitmap = new Bitmap( viewBitmapData );
addChild( viewBitmap );
addEventListener( Event.ENTER_FRAME, enterFrameHandler );
forceMapBitmap = new Bitmap( forceMapBitmapData );
forceMapBitmap.scaleX = 100 / forceMapBitmap.width
forceMapBitmap.scaleY = 100 / forceMapBitmap.height;
forceMapBitmap.x = stageWidth - forceMapBitmap.width;
addChild( forceMapBitmap );
var hueCircle:HueCircle = new HueCircle( 50, 30 );
hueCircle.x = hueCircle.radius + stageWidth - hueCircle.width;
hueCircle.y = hueCircle.radius + forceMapBitmap.height;
hueCircle.graphics.beginFill( 0x0 );
hueCircle.graphics.drawRect( -hueCircle.radius, -hueCircle.radius, hueCircle.width, hueCircle.height );
hueCircle.graphics.endFill();
addChild( hueCircle );
if( !FORCE_MAP_CREATE_BY_ENTER_FRAME )
forceMapBitmapData.perlinNoise( stageHeight >> ( FORCE_MAP_SCALE + 1 ), stageHeight >> ( FORCE_MAP_SCALE + 1 ), NUM_OCTAVES, seed, true, true, 3, false, offsets );
addChild(new Stats);
}
private function enterFrameHandler( event:Event ):void {
frameSkipper.update();
if ( FORCE_MAP_CREATE_BY_ENTER_FRAME && !frameSkipper.skip ) {
var offset:Number = ( frameSkipper.skipped + 1 ) * ( OFFSET_SPEED / FORCE_MAP_SCALE );
for ( var i:uint = 0; i < NUM_OCTAVES; i++ ) {
switch( i % 4 ) {
case 0:
offsets[i].x += offset;
break;
case 1:
offsets[i].x -= offset;
break;
case 2:
offsets[i].y += offset;
break;
case 3:
offsets[i].y -= offset;
break;
}
}
forceMapBitmapData.lock();
forceMapBitmapData.perlinNoise( stageHeight >> ( FORCE_MAP_SCALE + 1 ), stageHeight >> ( FORCE_MAP_SCALE + 1 ), NUM_OCTAVES, seed, true, true, 3, false, offsets );
forceMapBitmapData.unlock();
}
var particle:Particle = particles;
var color:uint;
var centerPoint:Point = new Point();
var force:Point = new Point();
viewBitmapData.lock();
if ( !FRAME_SKIP_DRAW_PARTICLE || ( FRAME_SKIP_DRAW_PARTICLE && !frameSkipper.skip ) )
viewBitmapData.colorTransform( viewBitmapData.rect, FADE_OUT_COLOR_TRANSFORM );
while ( ( particle = particle.next ) != null )
{
color = forceMapBitmapData.getPixel( particle.x >> FORCE_MAP_SCALE, particle.y >> FORCE_MAP_SCALE );
particle.x += ( particle.vx = particle.vx * 0.98 + ( ( color >> 16 & 0xff ) - 128 ) * 0.005 );
particle.y += ( particle.vy = particle.vy * 0.98 + ( ( color >> 8 & 0xff ) - 128 ) * 0.005 ) ;
if (particle.x < 0)
particle.x += stageWidth;
else if ( particle.x >= stageWidth )
particle.x -= stageWidth;
if ( particle.y < 0 )
particle.y += stageHeight;
else if ( particle.y >= stageHeight )
particle.y -= stageHeight;
force.x = ( color >> 16 & 0xff ) - 128;
force.y = ( color >> 8 & 0xff ) - 128;
if ( !FRAME_SKIP_DRAW_PARTICLE || ( FRAME_SKIP_DRAW_PARTICLE && !frameSkipper.skip ) )
viewBitmapData.setPixel( particle.x, particle.y, getHueCircleColor( centerPoint, force ) );
}
viewBitmapData.unlock();
}
}
}
import flash.display.*;
import flash.events.*;
import flash.utils.*;
import flash.geom.*;
class Particle {
public var vx:Number = 0;
public var vy:Number = 0;
public var x:int;
public var y:int;
public var next: Particle;
function Particle( x:int, y:int ) {
this.x = x;
this.y = y;
}
}
class FrameSkipper {
/* ==================================================
* property
* ==================================================
*/
/**
* スキップされたフレーム数
*/
public function get skipped():uint { return _skipped; }
private var _skipped:uint = 0;
/**
* スキップするべきときなら true、そうでないなら false
*
* --- 例 ---
* if( !frameSkipper.skip )
* // フレームスキップしない時の処理(描画などの重い処理)
* else
* // フレームスキップするときの処理(描画をせずにデータ地だけ変更するなどの軽い処理)
*/
public function get skip():Boolean { return skipCounter >= 0; }
/**
* 保ちたい fps 値
*/
public var expectedFPS:uint;
/**
*
*/
public var margin:uint;
/* ==================================================
* field
* ==================================================
*/
private var previousTime:int = 0;
private var currentTime:int = 0;
private var skipCounter:int = 0;
private var fps:uint;
/* ==================================================
* method
* ==================================================
*/
public function FrameSkipper( expectedFPS:uint = 60, margin:uint = 0 ):void {
this.expectedFPS = expectedFPS;
this.margin = margin;
}
public function update():void {
currentTime = getTimer();
fps = 1000 / ( currentTime - previousTime );
if ( !skip && fps < expectedFPS ) {
_skipped = expectedFPS / fps + margin;
skipCounter = skipped;
} else
skipCounter--;
previousTime = currentTime;
}
}
class HueCircle extends Sprite {
public function get radius():Number { return _radius; }
public function set radius(value:Number):void
{
_radius = value;
draw();
}
private var _radius:Number;
public function get innerRadius():Number { return _innerRadius; }
public function set innerRadius(value:Number):void
{
_innerRadius = value;
draw();
}
private var _innerRadius:Number;
private var bitmap:Bitmap;
private var circleMask:Sprite;
public function HueCircle( radius:Number, innerRadius:Number = 0 ) {
_radius = radius;
_innerRadius = innerRadius;
var diameter:Number = radius * 2;
if ( hueCircleBitmapData == null )
resizeHueCircleBitmapData( diameter );
bitmap = new Bitmap( hueCircleBitmapData );
bitmap.cacheAsBitmap = true;
addChild( bitmap );
circleMask = new Sprite();
circleMask.cacheAsBitmap = true;
addChild( circleMask );
bitmap.mask = circleMask;
draw();
}
private function draw():void {
circleMask.graphics.clear();
circleMask.graphics.beginFill( 0xffffff );
circleMask.graphics.drawCircle( radius, radius, radius);
if( innerRadius != 0 ) circleMask.graphics.drawCircle( radius, radius, innerRadius );
circleMask.graphics.endFill();
var largeRadius:Number = ( ( radius > innerRadius ) ? radius : innerRadius );
bitmap.x = -largeRadius;
bitmap.y = -largeRadius;
bitmap.scaleX = largeRadius / ( hueCircleBitmapData.width / 2 );
bitmap.scaleY = largeRadius / ( hueCircleBitmapData.width / 2 );
circleMask.x = -radius;
circleMask.y = -radius;
}
private static var hueCircleBitmapData:BitmapData;
public static function resizeHueCircleBitmapData( width:Number ):void {
var centerPoint:Point = new Point( width / 2, width / 2 );
var tempPoint:Point = new Point();
hueCircleBitmapData = new BitmapData( width, width, false );
hueCircleBitmapData.lock();
for ( var i:int = 0; i < width; i++ ) {
for ( var j:int = 0; j < width; j++ ) {
tempPoint.x = i;
tempPoint.y = j;
hueCircleBitmapData.setPixel( i, j, getHueCircleColor( centerPoint, tempPoint ) );
}
}
hueCircleBitmapData.unlock();
}
}
function getHueCircleColor( centerPoint:Point, point:Point ):uint {
var pointFromCenterPoint:Point = point.subtract( centerPoint );
var pointBearingFromCenterPoint:Number = Math.atan2( pointFromCenterPoint.y, pointFromCenterPoint.x ) * 180 / Math.PI;
if ( pointBearingFromCenterPoint < 0 )
pointBearingFromCenterPoint = pointBearingFromCenterPoint + 360;
return HSVtoRGB( pointBearingFromCenterPoint, 1, 1 );
}
function HSVtoRGB( h:Number, s:Number, v:Number ):uint {
var Hi:uint = ( h / 60 ) % 6;
var f:Number = h / 60 - Hi;
var p:Number = v * ( 1 - s );
var q:Number = v * ( 1 - f * s );
var t:Number = v * ( 1 - ( 1 - f ) * s );
switch( Hi ) {
case 0:
return toRGB255( v, t, p );
case 1:
return toRGB255( q, v, p );
case 2:
return toRGB255( p, v, t );
case 3:
return toRGB255( p, q, v );
case 4:
return toRGB255( t, p, v );
case 5:
return toRGB255( v, p, q );
}
return 0;
}
function toRGB255( r:Number, g:Number, b:Number ):uint {
return ( r * 255 << 16 ) + ( g * 255 << 8 ) + b * 255;
}