サイトトップ

Director Flash 書籍 業務内容 プロフィール
 
近日開講講座
5/26(火)HTML5 + CreateJSによるリッチコンテンツ作成講座
6/6(土)JavaScriptインタラクティブアニメーション講座
CreateJS Style Book WebクリエイターのためのCreateJSスタイルブック Away3D TypeScript in gihyo.jp gihyo.jp連載
「Away3D TypeScriptではじめる3次元表現」
■Twitter: @FumioNonaka / Facebook Page: CreateJS / Away3D

Creators MeetUp

ベレの方法ってなんですの?

ベレの方法」というのは、互いの間に力が働く粒子の動きを表す物理の考え方(方法)である。物体の運動は、速度から位置を求めるのが普通だ(「速度から位置を決めるアニメーション ー 微分により運動を考える」参照)。ところが、ベレの方法では、速度でなく位置と粒子間の位置関係から運動を定める。すると、一見複雑そうな動きが、四則演算だけで表せる。

このレジュメは、2015年5月16日土曜日に催された第28回Creators Meetupで務めた同名の高座の参加者向けとして書いた。当日のYouTube録画をつぎに掲げる。


01 ベレの方法とは

ベレの方法を使うと、一見複雑な粒子同士の動きが四則演算でつくれる(サンプル001)。

サンプル001■EaselJS 0.8.0: Verlet Octagon Draggable

ベレの方法は、つぎの方程式で表される(>>式の意味)。前の位置からつぎの位置を求める考え方だ。

ベレの方法の方程式
引用: Wikipedia「ベレの方法


02 点を動かす

普通は、加速度から速度を定めて、位置を導く(「速度から位置を決めるアニメーション ー 微分により運動を考える」04「バネのように伸び縮みする動き」参照)。

【速度から位置を求める】
加速度 = 計算式
速度 += 加速度
位置 += 速度

ベレの方法では、今の位置と前の位置の差を速度とみなして、つぎの位置を求める。

【前の位置からつぎの位置を求める】
一時預かり = (今の)位置
速度 = (今の)位置 - 前の位置
位置 += 速度
前の位置 = 一時預かり

ベレの方法で動く点をクラス(VerletPoint)として定めると、つぎのようになる。

function VerletPoint(x, y) {
  this.x = this._oldX = x;
  this.y = this._oldY = y;
}
VerletPoint.prototype.update = function() {
  var tempX = this.x;
  var tempY = this.y;
  var velocity = this.getVelocity();
  this.addCoordinates(velocity.x, velocity.y);
  this._oldX = tempX;
  this._oldY = tempY;
};

VerletPoint.prototype.getVelocity = function() {
  var velocity = new createjs.Point(this.x - this._oldX, this.y - this._oldY);
  return velocity;
};

VerletPoint.prototype.addCoordinates = function(x, y) {
  this.x += x;
  this.y += y;
};

初めに一度だけ位置を動かせば、等速運動になる。つまり、位置を動かすと、加速度が与えられる。

var _point;

var velocityX = 5;

function initialize() {

  _point = new VerletPoint(50, 50);
  _point.x += velocityX;

}

したがって、アニメーションを更新するたびに同じ動きを加えれば、等加速度運動になる。

var velocityY = 0.25;

function updatePoint() {
  _point.y += velocityY;
  _point.update();

}


03 壁の制約を加える

表示領域の外に消え去ってしまわないためには、いわゆる「壁ドン」対策が要る。速度から位置を求める場合は、ベクトルの方向を壁に対して反転させる(>>速度ベクトルを使った跳ね返り)。ベレの方法では、めり込んだら戻すだけだ。

【ベレの方法の壁ドン対策】
位置が壁を超えたら
壁の端に留める

クラス(VerletPoint)にメソッド(constrain())を加えて、引数に渡した矩形領域の外に出たら、位置を矩形領域上に戻す。

VerletPoint.prototype.constrain = function(rect) {
  var left = rect.x;
  var right = left + rect.width;
  var top = rect.y;
  var bottom = top + rect.height;
  if (this.x < left) {
    this.x = left;
  } else if (this.x > right) {
    this.x = right;
  }
  if (this.y < top) {
    this.y = top;
  } else if (this.y > bottom) {
    this.y = bottom;
  }
};

アニメーションを進めて位置を動かすたびに、前掲の表示領域の矩形内に留めるメソッド(constrain())を呼出した(サンプル002)。

var _stageRect;

function updatePoint() {

  _point.update();
  _point.constrain(_stageRect);

}

サンプル002■EaselJS 0.8.0: Verlet Point


04 ふたつの点を棒でつなぐ

ふたつの点を棒で結ぶには、距離を棒の長さに保たなければならない(図001)。そこで、ずれたふたつの点の位置は、棒の長さに均等に合わせる(>>ふたつの点の位置合わせ)。

図001■ふたつの点の距離を棒の長さに合わせる
図001左

VerletPoint.prototype.subtract = function(_point) {
  var subtractedPoint = new VerletPoint(this.x - _point.x, this.y - _point.y);
  return subtractedPoint;
};
VerletPoint.prototype.getLength = function() {
  var dx = this.x;
  var dy = this.y;
  var length = Math.sqrt(dx * dx + dy * dy);
  return length;
};

VerletStick.prototype.update = function() {
  var delta = this._point1.subtract(this._point0);
  var distance = delta.getLength();
  var difference = this._length - distance;
  var offsetX = (difference * delta.x / distance) * 0.5;
  var offsetY = (difference * delta.y / distance) * 0.5;
  this._point0.addCoordinates(-offsetX, -offsetY);
  this._point1.addCoordinates(offsetX, offsetY);
};

複数の点に位置の制約が加わって、跳ね返りが生じる(サンプル003)[*1]

サンプル003■EaselJS 0.8.0: Verlet Stick

[*1] 高座で引用したネタ画像はつぎのとおり。


05 点と棒で三角形を組立てる

点と棒を組合わせると多角形ができる。多角形でも、点と棒のクラス(VerletPointとVerletStick)は、基本的にそのまま使う。つまり、ルールは変わらないということだ。三角形は、つぎのように3点を棒で結んでつくれる(サンプル004)。

サンプル004■EaselJS 0.8.0: Verlet Triangle

しかし、4点を棒で結んだだけの四角形はつぶれてしまう(図002)。

図002■四角形が落ちるとかたちはつぶれる
図002上

図002下

筋交い」(すじかい)を加える手もある(図003)。だが、多角形に一般化しにくい。

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


06 多角形のすべての頂点を棒で結ぶ

多角形のすべての点を棒で結べば、任意の多角形がつぶれないようにつくれる(サンプル005)。

サンプル005■EaselJS 0.8.0: Verlet Square

ただし、頂点数が増えると、距離の制約を一気に解決できず、かたちが歪んでしまう(図004)。

図004■六角形のかたちが歪んで定まらない
図004上

図004下

そこで、距離の差は少しずつ縮めることにして、クラス(VerletStick)にそのためのプロパティ(elasticity)を加える(サンプル006)。

function VerletStick(point0, point1, length, elasticity) {

  this.elasticity = elasticity;

}

VerletStick.prototype.update = function() {

  var offsetX = (difference * delta.x / distance) * this.elasticity;
  var offsetY = (difference * delta.y / distance) * this.elasticity;

};

サンプル006■EaselJS 0.8.0: Verlet octagon


07 中心に点を加えてドラッグする

多角形をドラッグできるようにするため、その対象となる中心の点を加える(サンプル007)。

サンプル007■EaselJS 0.8.0: Verlet Octagon with the Center Point

点は座標データでしかないため、ドラッグできるかどうかはマウス座標から導く。中心点からの距離が半径以内であれば、ドラッグ対象とする(図005)。このようにしてドラッグ操作を加えたのが、前掲サンプル001になる。

図005■中心点からの距離でドラッグできる領域を定める
図005


Appendix ベレの方法を使ったコードサンプル

サンプルのコードについて詳しくは、gihyo.jp連載「HTML5のCanvasでつくるダイナミックな表現―CreateJSを使う」のつぎの3つの記事で解説した。

ベレの方法の応用例



作成者: 野中文雄
更新日: 2015年5月18日 YouTube録画を掲載し、若干の修正を加えた。
作成日: 2015年5月16日


Copyright © 2001-2015 Fumio Nonaka.  All rights reserved.