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

第34回 パーティクルの弾けるような動きをつくる

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

パーティクルにバネのような弾む動きを与える

つぎは,ステージの真ん中に置いたパーティクルにアニメーションを加える。そこで,クラス(Particle)にアニメーションさせるためのメソッド(accelerateTo())を定めよう。つぎのように,マウスポインタのxy座標を引数に与えて,弾みのついた動きにする。

Particleオブジェクト.accelerateTo(x座標, y座標)

といって,いきなりお題の動きを式に書いてもわかりづらいだろう。第24回マウスポインタの動きに弾みがついた曲線を滑らかに描くで似たようなアニメーションをつくった。このときと同じ,バネのような弾む動きから始めてみる。

とりあえず,クラス(Particle)のアニメーションのメソッド(accelerateTo())はできてしまったことにして,オブジェクトをアニメーションさせるJavaScriptコードから書き加える。Ticker.tickイベントのリスナー関数(updateAnimation())で,マウスポインタの座標に向けて,アニメーションのメソッドが呼出される。そして,マウスポインタの座標は,Stage.stagemousemoveイベントのリスナー関数(recordMousePoint())で変数(mousePoint)にPointオブジェクトとして与えることとした。なお,Pointオブジェクトの初期xy座標値は,ステージ中央だ。

var mousePoint = new createjs.Point();

function initialize() {

  mousePoint.x = stageWidth / 2;
  mousePoint.y = stageHeight / 2;

  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 mouseX = mousePoint.x;
  var mouseY = mousePoint.y;
  particle.accelerateTo(mouseX, mouseY);
  stage.update();
}

クラス(Particle)のメソッド(accelerateTo())は,つぎのように定めた。移動先のxy座標は,第24回「マウスポインタの動きに弾みがついた曲線を滑らかに描く」弾みのついた軌跡を描くと基本的に同じ式で求めている。マウスポインタとパーティクルのxy座標のそれぞれの差(differenceXとdifferenceY)に減速率(0.1)を乗じて,xyの加速度(accelerationXとaccelerationY)とする。それらをxyの速度(_velocityXと_velocityY)に足し込んで減衰率(friction)で割り引く。その速度を,それぞれxy座標(_xと_y)に加えればよい。

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 accelerationX = differenceX * 0.1;
  var accelerationY = differenceY * 0.1;
  _velocityX += accelerationX;
  _velocityY += accelerationY;
  _velocityX *= this.friction;
  _velocityY *= this.friction;
  _x += _velocityX;
  _y += _velocityY;
  this.x = _x;
  this.y = _y;
  this.velocityX = _velocityX;
  this.velocityY = _velocityY;
};

前掲コード1コード2にこれらの手直しを加えたのが,以下のコード3およびコード4だ。マウスポインタの座標をパーティクルが,弾みのついたバネのような動きで追いかける。jsdo.itのコードも併せて掲げたので,アニメーションを確かめてほしい。例によって,クラス(Particle)は[HTML]の欄に定めている。

コード3 ステージのパーティクルにバネのようなアニメーションを与える

var stage;
var stageWidth;
var stageHeight;
var mousePoint = new createjs.Point();
var particle;
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;
  createParticle();
  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 mouseX = mousePoint.x;
  var mouseY = mousePoint.y;
  particle.accelerateTo(mouseX, mouseY);
  stage.update();
}
function createParticle() {
  particle = new Particle(stageWidth / 2, stageHeight / 2);
  stage.addChild(particle);
}

コード4 バネのように弾みをつけて動くメソッドが備わったパーティクルのクラス

function Particle(x, y) {
  this.initialize();
  this.x = x;
  this.y = y;
  this.velocityX = 0;
  this.velocityY = 0;
  this.friction = 0.95;
  this.radius = 4;
  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 accelerationX = differenceX * 0.1;
  var accelerationY = differenceY * 0.1;
  _velocityX += accelerationX;
  _velocityY += accelerationY;
  _velocityX *= this.friction;
  _velocityY *= this.friction;
  _x += _velocityX;
  _y += _velocityY;
  this.x = _x;
  this.y = _y;
  this.velocityX = _velocityX;
  this.velocityY = _velocityY;
};

著者プロフィール

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

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

URLhttp://www.FumioNonaka.com/

著書