processing.jsで楽しんだ
公式
ref : http://processingjs.org/
機能的にはこれの模倣/コピペ
ref : http://www.few.vu.nl/~eliens/media/@js-sample-canvas-particles.txt
こうなった
make : http://modeverv.dyndns.org/sample/processing/
made : http://modeverv.dyndns.org/sample/processing/processing.html
パーティクルをflashで作った時よりも速いプログラムな気がしている。
jsでこういう遊びができるのは非常に便利。macユーザーなのでwindowsをわざわざ持ち出し、flashdevelopを立ち上げ、プロジェクトをつくってetcというのはしんどい。
ソース
var debug = function(s){ // console.log(s) ; }; // できるだけ重複処理を省かないとCPU/メモリ食いまくり // if文を並べるよりif-else if-elseでいくとテストの回数が減る // for文の初期化を太らせてイテレーションで計算させないとか // 見通しのよさとかオブジェクトに閉じ込めてメッセージを送りましょうとか // かっこいいけど遅いので臨機応変に function do_processing(){ var sketchProc = function(processing) { // config // バックグラウンドの色 var BG = { r:0,g:0,b:0}; var DrawBG = false; // パーティクルの数 var PARTICLE_NUM = 100; // FPS var FPS = 30; var _canvas = document.getElementById("sketch"); var W = _canvas.width; var H = _canvas.height; // パーティクルのプール var PARTICLE_POOL = []; // トランジションの定義 TRANSITIONELEMENTをくみあわせる // 毎度 無名functionの生成が走るので遅いのかも。ブラウザが賢くやってくれるのかも。 var TRANSITIONS = [ function gravity(){ TRANSITION_HANDLER(this, function(pixel){ pixel = _TRANSITON_ELEMENTS.bounce(pixel); pixel = _TRANSITON_ELEMENTS.gravity(pixel); } ); }, function beyond_gravity(){ TRANSITION_HANDLER(this, function(pixel){ pixel = _TRANSITON_ELEMENTS.bounce(pixel); pixel = _TRANSITON_ELEMENTS.beyond_gravity(pixel); } ); }, function gravityB(){ TRANSITION_HANDLER(this, function(pixel){ pixel = _TRANSITON_ELEMENTS.hantai(pixel); pixel = _TRANSITON_ELEMENTS.gravity(pixel); } ); }, function beyond_gravityB(){ TRANSITION_HANDLER(this, function(pixel){ pixel = _TRANSITON_ELEMENTS.hantai(pixel); pixel = _TRANSITON_ELEMENTS.beyond_gravity(pixel); } ); } /*, きもい function impulsWH(){ TRANSITION_HANDLER(this,_TRANSITON_ELEMENTS.impulsWH); }*//*, てんかんになりかける function impulsColor(){ TRANSITION_HANDLER(this,_TRANSITON_ELEMENTS.impulsColor); }, function Flash(){ TRANSITION_HANDLER(this,_TRANSITON_ELEMENTS.flash); } */ ]; // 各トランジションの動き var _TRANSITON_ELEMENTS = { gravity:function(pixel){ pixel.vy = (pixel.vy + 0.1); return pixel; }, beyond_gravity:function(pixel){ pixel.vy = (pixel.vy - 0.1); return pixel; }, impulsWH : function(pixel){ pixel.w = pixel.h = 30 + 10 * Math.cos(pixel.counter); return pixel; }, flash : function(pixel){ pixel.cR = pixel.cG = pixel.cB = (255 + 255 * Math.cos(pixel.counter)) % 255 ; return pixel; }, impulsColor :function(pixel){ var C = (255 + 255 * Math.cos(pixel.counter)) % 255 ; if(pixel.cR < 240){ pixel.cR = C; }else if(pixel.cG < 240){ pixel.cG += C; }else if(pixel.cB < 240){ pixel.cB += C; }else{ pixel.cR = pixel.cG = pixel.cB = 0; } return pixel; }, bounce :function(pixel){ if(pixel.x < 0){ pixel.x = 0; pixel.vx*=-1; } if(pixel.x + pixel.w > W){ pixel.x = W - pixel.w; pixel.vx*=-1; } if(pixel.y < 0){ pixel.y = 0; pixel.vy*=-1; } if(pixel.y + pixel.h > H){ pixel.y = H - pixel.h; pixel.vy*=-1; } return pixel; }, hantai : function(pixel){ // 反対側 if(pixel.x < 0){ pixel.x = W; }else if(pixel.x + pixel.w > W){ pixel.x = 0; } if(pixel.y < 0){ pixel.y = H; }else if(pixel.y + pixel.h > H){ pixel.y = 0; } return pixel; } }; // カウンターが+の場合はトランジションをキックする。-の場合はPixelの中身を洗い替え var TRANSITION_HANDLER = function(pixel,proc){ if(pixel.counter > 0) { pixel.counter -= 1; proc(pixel); }else{ pixel.init(); } }; var DESTINATIONFLG = { initial : -1, moving : 0, moved : 1, finish : FPS * 3, gaman : FPS }; // 指定場所に動かすトランジション 現状中身は一つだけ ちょっとださい var TRANSITIONS_DESTINATION = [ function(){ // counterの数でdst_x,dst_yにたどり着く this.counter -= 1; if(this.setflg == DESTINATIONFLG.initial ){ this.vx = (this.dst_x - this.x) / this.counter; this.vy = (this.dst_y - this.y) / this.counter; this.va = 120 / this.counter; this.cA = 10; this.setflg = 0; }else if(this.setflg == DESTINATIONFLG.moving){ if(this.counter < 0){ this.vx = this.vy = 0; this.setflg = DESTINATIONFLG.moved; } }else if(this.setflg >= DESTINATIONFLG.moved && this.setflg <= DESTINATIONFLG.gaman){ this.setflg += 1; this.cA = 255; _TRANSITON_ELEMENTS.flash(this); }else if(this.setflg > DESTINATIONFLG.gaman ){ DrawBG = false; // backgroundが動くように戻す this.init(); }else{ // safety this.init(); } this.cA += this.va; } ]; // 指定場所の定義 var DESTINATION = [ // キャンバス中央 [[Math.floor(W/2),Math.floor(H/2)]], // 左上隅 [[100,100]], // 右上隅 [[W-100,100]], // 左下隅 [[100,H-100]], // 左下隅 [[W-100,H-100]], // 100格子 (function kousi(interval){ var ret = []; for(var i=0,l=Math.ceil(W/interval);i<l;i++){ for(var j=0,n=Math.ceil(H/interval);j<n;j++){ ret.push([i*interval,j*interval]); } } return ret; })(100), // 十字架 (function cross(interval){ var ret = []; var cW = W/2; var cH = H/2; for(var i=0,l=Math.ceil(W/interval);i<l;i++){ ret.push([i * interval,cH]); } for(var i=0,l=Math.ceil(H/interval);i<l;i++){ ret.push([cW,i* interval]); } return ret; })(100) ]; // パーティクルオブジェクト var Pixel = function(){ this.x = Math.floor(Math.random() * W); this.y = Math.floor(Math.random() * H); this.init(); }; // コメント:トランジションの関数を内蔵するとカッコいいかもしれませんが。。。 // 各Pixelの内部が巨大になり遅くなる、かつPixel間でトランジション関数は重複する無意味さなので // トランジション関数は外に出します。 Pixel.prototype = { // 初期化関数 // x,y座標,加速度vx,vy,色cR,cG,cB,cA,トランジション,カウンターを適当にセット init : function(){ this.w = Math.floor(Math.random() * 10) + 10; this.h = this.w; var seed = Math.random(); this.vx = Math.floor(Math.random() * 10); this.vy = Math.floor(Math.random() * 10); if(seed > 0.5){ this.vx *= -1; this.vy *= -1; } this.cR = Math.floor(Math.random()* 255); this.cG = Math.floor(Math.random()* 255); this.cB = Math.floor(Math.random()* 255); this.cA = Math.floor(Math.random()* 255); this.transition = TRANSITIONS[Math.floor(Math.random() * TRANSITIONS.length)]; this.counter = 3 * (FPS + FPS * Math.random()) ; }, // 描画関数 トランジションを行ったあと描画する draw:function(){ this.transition(); this.x += this.vx; this.y += this.vy; processing.fill(this.cR,this.cG,this.cB,this.cA); processing.ellipse( Math.floor(this.x % W), Math.floor(this.y % H), this.w, this.h ); } }; // パーティクルプールにPixelをnewしてpush for(var i=0;i<PARTICLE_NUM;i++){ PARTICLE_POOL.push(new Pixel()); } // Processingのサイズやfpsを色々 processing.setup = function(){ processing.size(W, H); processing.noStroke(); processing.frameRate( FPS ); }; // トランジションが指定場所モードに変わったときに // canvasを塗り直さないようにするフラグ // モードの変更にnew Dateを利用するのでしばらくモード変更flgが立ち続けてしまうため。 DrawBG = false; var ModeIsDestination = false; // 描画関数 updateですね processing.draw = function(){ ModeIsDestination = Math.floor((new Date()/1000)) % 10 == 0; if(ModeIsDestination){ var DSTS = DESTINATION[Math.floor(Math.random()*DESTINATION.length)]; var transition = TRANSITIONS_DESTINATION[Math.floor(Math.random() * TRANSITIONS_DESTINATION.length)]; } if(!DrawBG){ processing.background(BG.r,BG.g,BG.b); } for(var i=0;i<PARTICLE_NUM;i++){ if(ModeIsDestination){ // 指定場所モードになった暁にはトランジションをすべて // 指定場所モードに変更して指定場所をセットしてcounterをFPS * 3,つまり3秒にする // 状態管理用のsetflgも初期化する。 DrawBG = true; PARTICLE_POOL[i].transition = transition; PARTICLE_POOL[i].dst_x = DSTS[i % DSTS.length][0]; PARTICLE_POOL[i].dst_y = DSTS[i % DSTS.length][1]; PARTICLE_POOL[i].counter = DESTINATIONFLG.finish; PARTICLE_POOL[i].setflg = DESTINATIONFLG.initial; } PARTICLE_POOL[i].draw(); } }; }; var canvas = document.getElementById("sketch"); canvas.width = window.innerWidth; canvas.height = window.innerHeight; // attaching the sketchProc function to the canvas var processingInstance = new Processing(canvas, sketchProc); } $(function(){ do_processing(); });