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

第32回 弾力のある多角形を放物線状に落とす

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

4つの点から四角形をつくって落とす

三角形ができたら,つぎは四角形だ。もっとも,前掲コード1の頂点をつくる関数(makePoints())には,頂点数を引数で与えられるようにした。したがって,初期化の関数(initialize())内から呼び出すとき渡す頂点数の引数値を書き替えるだけで,四角形がつくれる。つくれるけれども,残念ながらでき上がるアニメーションは情けない。Canvas下端に落ちたときかたちを保てず,四角形がつぶれてしまうのだ図1)⁠

function initialize() {

  makePoints(100, 70, 50, 4);   // 3);

}

図1 四角形が落ちるとかたちはつぶれる

図1 四角形が落ちるとかたちはつぶれる

図1 四角形が落ちるとかたちはつぶれる

問題は,4つの点の隣同士の間にしか棒が加えられていないことだ。それでは,いくら4つの棒の長さを保っても,つぶれてしまう。姑息(ことばの意味を取り違える人が増えているそうなので辞書にリンクした)解決法として,筋交い⁠すじかい)を加えることが考えられる図2)⁠前掲コード1の棒をつくる関数(makeSticks())に,以下のように1行書込めば済む。

図2 筋交いを加えてつぶれないようにする

図2 筋交いを加えてつぶれないようにする

function makeSticks() {
  var count = _points.length;
  for (var i = 0; i < count - 1; i++) {
    _sticks.push(new VerletStick(_points[i], _points[i + 1]));
  }
  _sticks.push(new VerletStick(_points[i], _points[0]));
  _sticks.push(new VerletStick(_points[0], _points[2]));   // 追加
}

しかし,これで四角形はかたちが保てても,さらに頂点数を増やせば,また筋交いの棒をどこに加えるか考えるはめになる。それでは,せっかく頂点数を関数(makePoints())の引数で自由に決められるようにした意味がない。そこで,すべてのふたつの頂点の組を棒で結ぶことにする。棒をつくる関数(makeSticks())for文をつぎのように二重にして,外側のループで始めの点を選び,内側のループは選んだ点のインデックスより後の点を順に棒でつないでいる。

function makeSticks() {
  var count = _points.length;
  for (var i = 0; i < count - 1; i++) {
    // _sticks.push(new VerletStick(_points[i], _points[i + 1]));

    for (var j = i + 1; j < count; j++) {
      _sticks.push(new VerletStick(_points[i], _points[j], null, 0.1));
    }
  }
  // _sticks.push(new VerletStick(_points[i], _points[0]));
}

この修正を前掲コード1に加えたのが,以下のコード2だ。動きを確かめるためにjsdo.itのサンプルも掲げよう。これで,頂点をつくる関数(makePoints())の引数で任意の多角形が定められる。もちろん,落ちてもかたちはつぶれない。

コード2 点と棒でつくった四角形を放物線状に落とす

var stage;
var drawingGraphics;
var _points = [];
var _sticks = [];
var _stageRect;
var velocityX = 5;
var velocityY = 0.25;
var _radius = 50;
function initialize() {
  var canvasElement = document.getElementById("myCanvas");
  var shape = new createjs.Shape();
  stage = new createjs.Stage(canvasElement);
  stage.addChild(shape);
  drawingGraphics = shape.graphics;
  _stageRect = new createjs.Rectangle(
    _radius / 8,
    _radius / 8,
    canvasElement.width - _radius / 4,
    canvasElement.height - _radius / 4
  );
  makePoints(100, 70, 50, 4);
  makeSticks();
  _points[0].x += velocityX;
  createjs.Ticker.timingMode = createjs.Ticker.RAF;
  createjs.Ticker.addEventListener("tick", draw);
}
function draw(eventObject) {
  updatePoints();
  updateSticks();
  drawingGraphics.clear();
  renderPoints();
  renderSticks();
  stage.update();
}
function makePoints(centerX, centerY, radius, vertices) {
  var angle = -Math.PI / 2;
  var theta = 2 * Math.PI / vertices;
  for (var i = 0; i < vertices; i++) {
    var x = centerX + radius * Math.cos(angle);
    var y = centerY + radius * Math.sin(angle);
    _points.push(new VerletPoint(x, y));
    angle += theta;
  }
}
function makeSticks() {
  var count = _points.length;
  for (var i = 0; i < count - 1; i++) {

    for (var j = i + 1; j < count; j++) {
      _sticks.push(new VerletStick(_points[i], _points[j]));
    }
  }

}
function updatePoints() {
  var count = _points.length;
  for (var i = 0; i < count; i++) {
    var point = _points[i];
    point.y += velocityY;
    point.update();
    point.constrain(_stageRect);
  }
}
function updateSticks() {
  var count = _sticks.length;
  for (var i = 0; i < count; i++) {
    var stick = _sticks[i];
    stick.update();
  }
}
function renderPoints() {
  var count = _points.length;
  for (var i = 0; i < count; i++) {
    var point = _points[i];
    point.render(drawingGraphics);
  }
}
function renderSticks() {
  var count = _sticks.length;
  for (var i = 0; i < count; i++) {
    var stick = _sticks[i];
    stick.render(drawingGraphics);
  }
}

著者プロフィール

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

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

URLhttp://www.FumioNonaka.com/

著書