HTML5のCanvasでつくるダイナミックな表現―CreateJSを使う

第35回 たくさんのパーティクルに弾けるようなアニメーションをさせる

この記事を読むのに必要な時間:およそ 5 分

前回の第34回パーティクルの弾けるような動きをつくるは,ステージにパーティクルをひとつ置き,マウスポインタの座標に向けて弾けるように動かした。今回は,この数を増やして,パーティクルらしいアニメーションにしたい。パーティクルのような多くのオブジェクトを,配列でどう扱うかにも触れたい。

たくさんのパーティクルをステージのランダムな位置に置く

前回の第34回コード6に手を加えよう。パーティクルのクラス(Particle)を定めた第34回コード5ほぼそのまま用いる。まず,パーティクルをひとつだけ置いた関数(createParticle())は,引数の数だけステージのランダムな位置に描く関数(createParticles())に書き替える。初期化の関数(initialize())から,以下のように新たな関数にパーティクル数(numParticles)を渡して呼び出す。

// var particle;
var particles = new Array();
var numParticles = 3000;
function initialize() {

  // createParticle();
  createParticles(numParticles);

}

// function createParticle() {
function createParticles(amount) {
  for (var i = 0; i < amount; i++) {
    var _x = Math.random() * stageWidth;
    var _y = Math.random() * stageHeight;
    // particle = new Particle(stageWidth / 2, stageHeight / 2, stageWidth, stageHeight);
    var particle = new Particle(_x, _y, stageWidth, stageHeight);
    particles.push(particle);
    stage.addChild(particle);
  }
}

呼び出された関数(createParticles())は,上記のようにforループで引数(amount)の数だけパーティクルのインスタンスをつくって,ステージのランダムな位置に置く。そして,インスタンスは変数(particles)に定める配列に納めた。これで,ステージのランダムな位置にたくさんのパーティクルが描かれる(図1)。ただし,まだアニメーションの処理を書き替えていないので,このまま試したのではエラーになる。確かめたいときは,Ticker.tickイベントのリスナーは一時的に外しておかなければならない。

// createjs.Ticker.addEventListener("tick", updateAnimation);

図1 ステージのランダムな位置にたくさんのパーティクルが描かれる

図1 ステージのランダムな位置にたくさんのパーティクルが描かれる

すべてのパーティクルを弾けるように動かす

つぎは,いよいよすべてのパーティクルに弾ける動きを与える。前項でTicker.tickイベントのリスナーを外して試した人は,必ず戻そう。こういうつまらない誤りにかぎってハマりやすいものだ。スクリプトはとくに難しいことはない。つぎのように,アニメーションの関数(updateAnimation())に手を加える。パーティクルが納められた配列(particles)からforループで取り出したすべてのオブジェクト(particle)に対して,引数のマウス座標(mouseXとmouseY)をアニメーションのためのメソッド(accelerateTo())に渡せばよい。

function updateAnimation(eventObject) {
  var count = particles.length;

  // particle.accelerateTo(mouseX, mouseY);
  for (var i = 0; i < count; i++) {
    var particle = particles[i];
    particle.accelerateTo(mouseX, mouseY);
  }

}

クラス(Particle)からたくさんのパーティクルをつくって,弾けるようにアニメーションさせるスクリプトは,まとめると以下のコード1のとおりだ。また,粉雪が舞い散るような表現にするため,クラス(Particle)のコンストラクタで定めるパーティクルの大きさ(radius)を縮めて,1辺1ピクセル(= 0.5×2)にした図2)。他は,前回と変わっていない。それも,コード2として併せて掲げた。また,jsdo.itのサンプルも添えよう。

図2 たくさんのパーティクルがマウスポインタを追って粉雪のように舞い散る

図2 たくさんのパーティクルがマウスポインタを追って粉雪のように舞い散る

コード1 クラスからつくったたくさんのパーティクルを弾けるようにアニメーションさせる

var stage;
var stageWidth;
var stageHeight;
var mousePoint = new createjs.Point();
var particles = [];
var numParticles = 3000;
function initialize() {
  var canvasElement = document.getElementById("myCanvas");
  stageWidth = canvasElement.width;
  stageHeight = canvasElement.height;
  stage = new createjs.Stage(canvasElement);
  mousePoint.x = stageWidth / 2;
  mousePoint.y = stageHeight / 2;
  createParticles(numParticles);
  stage.update();
  stage.addEventListener("stagemousemove", recordMousePoint);
  createjs.Ticker.timingMode = createjs.Ticker.RAF;
  createjs.Ticker.addEventListener("tick", updateAnimation);
}
function recordMousePoint(eventObject) {
  mousePoint.x = eventObject.stageX;
  mousePoint.y = eventObject.stageY;
}
function updateAnimation(eventObject) {
  var count = particles.length;
  var mouseX = mousePoint.x;
  var mouseY = mousePoint.y;
  for (var i = 0; i < count; i++) {
    var particle = particles[i];
    particle.accelerateTo(mouseX, mouseY);
  }
  stage.update();
}
function createParticles(amount) {
  for (var i = 0; i < amount; i++) {
    var _x = Math.random() * stageWidth;
    var _y = Math.random() * stageHeight;
    var particle = new Particle(_x, _y, stageWidth, stageHeight);
    particles[i] = particle;
    stage.addChild(particle);
  }
}

コード2 マウスポインタの後を追って弾けるように動くパーティクルのクラス

function Particle(x, y, right, bottom) {
  this.initialize();
  this.x = x;
  this.y = y;
  this.right = right;
  this.bottom = bottom;
  this.velocityX = 0;
  this.velocityY = 0;
  this.friction = 0.95;
  this.radius = 0.5;
  this.drawParticle();
}
Particle.prototype = new createjs.Shape();
Particle.prototype.drawParticle = function () {
  var size = this.radius * 2;
  this.graphics.beginFill("white")
  .drawRect(-this.radius, -this.radius, size, size);
};
Particle.prototype.accelerateTo = function (targetX, targetY) {
  var _x = this.x;
  var _y = this.y;
  var _velocityX = this.velocityX;
  var _velocityY = this.velocityY;
  var differenceX = targetX - _x;
  var differenceY = targetY - _y;
  var square = differenceX * differenceX + differenceY * differenceY;
  var ratio;
  if (square > 0) {
    ratio = 50 / square;
  } else {
    ratio = 0;
  }
  var accelerationX = differenceX * ratio;
  var accelerationY = differenceY * ratio;
  _velocityX += accelerationX;
  _velocityY += accelerationY;
  _velocityX *= this.friction;
  _velocityY *= this.friction;
  _x += _velocityX;
  _y += _velocityY;
  if (_x < 0) {
    _x += this.right;
  } else if (_x > this.right) {
    _x -= this.right;
  }
  if (_y < 0) {
    _y += this.bottom;
  } else if (_y > this.bottom) {
    _y -= this.bottom;
  }
  this.x = _x;
  this.y = _y;
  this.velocityX = _velocityX;
  this.velocityY = _velocityY;
};

著者プロフィール

野中文雄(のなかふみお)

ソフトウェアトレーナー,テクニカルライター,オーサリングエンジニア。上智大学法学部卒,慶応義塾大学大学院経営管理研究科修士課程修了(MBA)。独立系パソコン販売会社で,総務・人事,企画,外資系企業担当営業などに携わる。その後,マルチメディアコンテンツ制作会社に転職。ソフトウェアトレーニング,コンテンツ制作などの業務を担当する。2001年11月に独立。Web制作者に向けた情報発信プロジェクトF-siteにも参加する。株式会社ロクナナ取締役(非常勤)。

URLhttp://www.FumioNonaka.com/

著書

コメント

コメントの記入