canvasタグを使ったJavaScriptのパーティクル

2008/12/22

こんにちは。きんくまです。

以前にJavaScriptでDOMを用いたパーティクルを作ってみました。
→JavaScriptでパーティクル

それで今回はcanvasタグを使って同じことをしたらどんな感じになるのか作ってみました。

→デモを見る

canvasタグは、よくわかってなかったんですが調べてみるとFlashでいうBitmapDataみたいな扱いなんでしょうかね?
毎描画ごとに一度クリアして、オブジェクトごとにひとつずつ描画していくあたりが似ていますね。
なんか3Dもできるっぽいんですが、とりあえず矩形を描画することしか学習しなかったんで、デモもそのままです。

あと実行速度なんですが、前回のDOMよりも重い気がします。とくに画面サイズを広げたときです。同じパーティクルの数でも画面サイズを広げただけで動きがすごく重くなります。
やっぱり前回と同じく実行速度は
Chorome>Firefox3>>IE7
ですね。そして同じくFirefoxではときどきガベコレ?のためか止まります。

今回のデモ作っての感想としては、静止画とか動きのゆっくりしたものはこれでもOKだと思うんですが、動きが大きかったり全画面だったりパーティクルみたいのを使うときは、まだ実用段階じゃない気がしました。って、でもスクリプトを見直せばもう少し速くなるかも、、。

canvasタグは標準ではIEでは描画できないようなんですが、google?が公開しているライブラリを使うと見ることができるようです。今回使ってみました。標準じゃないんでやっぱりIEは重いです。
→ExplorerCanvas

以下今回のソースです。

var ctx;
var WIDTH;
var HEIGHT;
var gravity;
var total = 0;

//Perticle
var Perticle = function(x, y) {
  this.vx = Math.random() * 5 * (Math.random() * 2 < 1 ? 1 : -1);
  this.vy = Math.random() * 50 * gravity * -1;
  this.width = Math.floor(Math.random() * 27) + 3;
  this.x = x - this.width / 2;
  this.y = y - this.width / 2;
  this.id = "ptc" + Perticle.initID;
  var r = Math.floor(Math.random() * 256 * 2 / 5 + 0xff * 3 / 5);
  var g = Math.floor(Math.random() * 256 * 4 / 5 + 0xff * 1 / 5);
  var b = Math.floor(Math.random() * 256 * 3 / 5 + 0xff * 2 / 5);
  this.rgb = "rgb(" + r + "," + g + "," + b + ")";
  Perticle.initID++;
};
Perticle.initID = 1;
Perticle.prototype = {
  update: function() {
    this.vy += gravity;
    this.x += this.vx
    this.y += this.vy;
    if (this.y + this.width > Base.height) {
      this.y = Base.height - this.width;
      this.vy *= -0.3;
      if(Math.abs(this.vy) < 1)
      {
        Perticles.remove(this.id);
      }
    }
    else if(this.y < 0)
    {
      this.y = 0;
      this.vy *= -0.3;
      if(Math.abs(this.vy) < 1)
      {
        Perticles.remove(this.id);
      }
    }
    else{
      ctx.fillStyle = this.rgb;
      ctx.fillRect (this.x, this.y, this.width, this.width);
    }
    if(this.x < 0)
    {
      this.x = 0;
      this.vx *= -1;
    }
    else if(this.x > Base.width)
    {
      this.x = Base.width;
      this.vx *= -1;
    }
  }
}

//Perticles
var Perticles = function() { };
Perticles.data = {};
Perticles.add = function(perticle) {
  Perticles.data[perticle.id] = perticle;
}
Perticles.remove = function(perticleID) {
  total--;
  delete Perticles.data[perticleID];
}

//Enterframe
var Enterframe = function() {}
Enterframe.timer = null;
Enterframe.start = function() {
  clearInterval(Enterframe.timer);
  var fps = Math.floor(1000 / 60);
  Enterframe.timer = setInterval(Enterframe.update, fps);
}
Enterframe.update = function() {
  ctx.clearRect(0, 0, WIDTH, HEIGHT);
  for (var perticle in Perticles.data) {
    Perticles.data[perticle].update();
  }
  $('#numberof').text('total: ' + total);
}

//Base
var Base = function() { }
Base.height = 0;
Base.prototype = {
  update: function() {
    FPS.getFPS();
    Base.width = $('body').width();
    Base.height = $('body').height();
  }
}

var FPS = function(){};
FPS.current = (new Date()).getTime();
FPS.baseTime = FPS.current;
FPS.count = 0;
FPS.getFPS = function(){
  FPS.count++;
  FPS.current = (new Date()).getTime();
  if(FPS.current - FPS.baseTime > 1000)
  {
    $('#fps').text("fps: " + FPS.count);
    FPS.baseTime = FPS.current;
    FPS.count = 0;
  }
}


$(function() {
  $('#canvas').attr('width', $('body').width());
  $('#canvas').attr('height', $('body').height());
  ctx = $('#canvas')[0].getContext("2d");
  WIDTH = $("#canvas").width();
  HEIGHT = $("#canvas").height();

  Enterframe.start();
  Perticles.add(new Base());
  $('#canvas').bind('click', function(e) {
    var p;
    for (var i = 0; i < 10; i++) {
      Perticles.add(new Perticle(e.clientX, e.clientY));
      total++;
    }
  });

  $('#canvas').bind('mousemove', function(e){
    var vector = e.clientY - $('body').height() / 2;
    gravity = vector * 0.001;
    $('#vy').text("gravity: " + gravity * -1);
  });

});
LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る