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

第6回 アニメーションする粒子間に引合う力を加える

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

今回のお題は,ランダムに動く粒子の間に相互作用を加えたアニメーションだ。ランダムな動きにオブジェクト同士のインタラクションを交えると,有機的なアニメーションになってくる。Jared Tarbell氏がかつてNode Gardenという作品を発表された。Keith Peters氏はそのノード間にバネ運動を加えて,著書ActionScript 3.0アニメーションで解説している。本稿はその表現をCreateJSで書いてみようと思う。

ステージのランダムな位置に,ランダムな方向と速さで動く小さなオブジェクトをたくさん置く。それらのオブジェクトの間に引っぱり合うバネのような力を与え,さらに互いを線で結ぶ図1)。できあがりのコードは,jsdo.itに上げてある(例によって後で書き直すかもしれないが)。

図1 ランダムに動くオブジェクトの間に引合う力を与えて線で結ぶ

図1 ランダムに動くオブジェクトの間に引合う力を与えて線で結ぶ

ランダムに置いたオブジェクトをランダムな向きと速さで動かす

取りあえず,オブジェクトの互いの間にかかる力は脇に置いておこう。ステージ上のランダムなところから,ランダムな向きと速さで等速に動かす。まず,予め定めた数のオブジェクトをステージ領域のランダムな位置につくるのが,次のscript要素だ。

body要素のonload属性で呼出す初期化の関数(initialize())は,for文であらかじめ定めた数(ballCount)のインスタンス(ball)をステージ領域のランダムな位置に置く。円形のShapeインスタンスをつくる関数(createBall())は別に定め,引数に半径と色,およびxy座標を渡している。また,インスタンスのShape.graphicsプロパティに円を描くのも別関数(drawBall())とした。引数には,Graphicsオブジェクトと半径,および色を渡す。


<script src="http://code.createjs.com/easeljs-0.6.0.min.js"></script>
<script>
var stage;
var stageWidth;
var stageHeight;

var ballCount = 25;
function initialize() {
  var canvasElement = document.getElementById("myCanvas");
  stage = new createjs.Stage(canvasElement);
  stageWidth = canvasElement.width;
  stageHeight = canvasElement.height;
  for (var i = 0; i < ballCount; i++) {
    var nX = Math.random() * stageWidth;
    var nY = Math.random() * stageHeight;
    var velocityX = (Math.random() - 0.5) * 5;
    var velocityY = (Math.random() - 0.5) * 5;
    var ball = createBall(3, "black", nX, nY);
    // ...[中略]...
    stage.addChild(ball);
  }
  stage.update();
}
function createBall(radius, color, nX, nY) {
  var ball = new createjs.Shape();
  drawBall(ball.graphics, radius, color);
  ball.x = nX;
  ball.y = nY;
  // ...[中略]...
  return ball;
}
function drawBall(myGraphics, radius, color) {
  myGraphics.beginFill(color);
  myGraphics.drawCircle(0, 0, radius);
}
</script>

つぎに,オブジェクトをランダムな向きと速さで動かす。つくったオブジェクトは変数の配列(balls)に入れ,Ticker.tickイベントのリスナー関数(move())でアニメーションさせる。xy軸方向に進む向きと速さは,インスタンスごとに変えるので,速度のプロパティ(velocityXとvelocityY)としてもたせる。そのため,インスタンスをつくる関数(createBall())の引数に,これらの値を加えた。

Ticker.tickイベントのリスナーに定めたアニメーションの関数(move())は,オブジェクト(ball)の速度のプロパティ値(velocityXとvelocityY)をそれぞれの座標に加えて動かす。ただし,座標値がステージの端を超えたら反対側の端に戻るよう,周期化する関数(roll())で補正している。


var balls = [];

function initialize() {
  // ...[中略]...
  for (var i = 0; i < ballCount; i++) {
    // ...[中略]...
    // var ball = createBall(3, "black", nX, nY);
    var ball = createBall(3, "black", nX, nY, velocityX, velocityY);
    balls.push(ball);
    // ...[中略]...
  }
  // stage.update();
  createjs.Ticker.addEventListener("tick", move);
}
// function createBall(radius, color, nX, nY) {
function createBall(radius, color, nX, nY, velocityX, velocityY) {
  // ...[中略]...
  ball.velocityX = velocityX;
  ball.velocityY = velocityY;
  return ball;
}

function move(eventObject) {
  for (var i = 0; i < ballCount; i++) {
    var ball = balls[i];
    var nX = ball.x;
    var nY = ball.y;
    nX += ball.velocityX;
    nY += ball.velocityY;
    ball.x = roll(nX, stageWidth);
    ball.y = roll(nY, stageHeight);
  }
  stage.update();
}
function roll(value, length) {
  if (value > length) {
    value -= length;
  } else if (value < 0) {
    value += length;
  }
  return value;
}

これらのsctipt要素をまとめたのが,次のコード1だ。ステージにランダムに散らばったオブジェクトは,ランダムな向きと方向に等速で動き続ける図2)。オブジェクトがステージの外に出ると,反対側の端から表れる。オブジェクトの間には,とくに相互作用はない。

図2 ステージにランダムに散らばったオブジェクトがランダムな向きと速さで動く

図2 ステージにランダムに散らばったオブジェクトがランダムな向きと速さで動く

コード1 ステージにランダムに置いたオブジェクトをランダムな向きと速さで等速に動かす


<script src="http://code.createjs.com/easeljs-0.6.0.min.js"></script>
<script>
var stage;
var stageWidth;
var stageHeight;
var balls = [];
var ballCount = 25;
function initialize() {
  var canvasElement = document.getElementById("myCanvas");
  stage = new createjs.Stage(canvasElement);
  stageWidth = canvasElement.width;
  stageHeight = canvasElement.height;
  for (var i = 0; i < ballCount; i++) {
    var nX = Math.random() * stageWidth;
    var nY = Math.random() * stageHeight;
    var velocityX = (Math.random() - 0.5) * 5;
    var velocityY = (Math.random() - 0.5) * 5;
    var ball = createBall(3, "black", nX, nY, velocityX, velocityY);
    balls.push(ball);
    stage.addChild(ball);
  }
  createjs.Ticker.addEventListener("tick", move);
}
function createBall(radius, color, nX, nY, velocityX, velocityY) {
  var ball = new createjs.Shape();
  drawBall(ball.graphics, radius, color);
  ball.x = nX;
  ball.y = nY;
  ball.velocityX = velocityX;
  ball.velocityY = velocityY;
  return ball;
}
function drawBall(myGraphics, radius, color) {
  myGraphics.beginFill(color);
  myGraphics.drawCircle(0, 0, radius);
}
function move(eventObject) {
  for (var i = 0; i < ballCount; i++) {
    var ball = balls[i];
    var nX = ball.x;
    var nY = ball.y;
    nX += ball.velocityX;
    nY += ball.velocityY;
    ball.x = roll(nX, stageWidth);
    ball.y = roll(nY, stageHeight);
  }
  stage.update();
}
function roll(value, length) {
  if (value > length) {
    value -= length;
  } else if (value < 0) {
    value += length;
  }
  return value;
}
</script>

著者プロフィール

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

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

URLhttp://www.FumioNonaka.com/

著書

コメント

コメントの記入