WEBOPIXEL

HTML5+Canvasで学ぶ物理アニメーションの基礎

Posted: 2015.07.28 / Category: javascript / Tag: ,

HTML5+Canvasを使用して物体が落下するという簡単な物理アニメーションを作成してみます。

Sponsored Link

Canvasアニメーションの基礎については下記を参考にしてください。
この記事は下記をベースとして進めます。

HTML5で作るCanvasアニメーションの基礎
HTML5+Canvasでパーティクルっぽいのを作ってみる

基本となるオブジェクトを作成する

前回作成したParticleオブジェクトを少し編集します。

var Particle = function(scale, color, vx, vy) {
    this.scale = scale; //大きさ
    this.color = color; //色
    this.vx = vx; //X速度
    this.vy = vy; //Y速度
    this.position = {   // 位置
        x: 0,
        y: 0
    };
};

Particle.prototype.draw = function() {
    ctx.beginPath();
    ctx.arc(this.position.x, this.position.y, this.scale, 0, 2*Math.PI, false);
    ctx.fillStyle = this.color;
    ctx.fill();
};

Particle.prototype.update = function() {
    // ここにアニメーション処理を書く
    this.position.y -= this.vy;
    this.draw();
};

主な変更点はアニメーション処理を「update」としてParticleに持たせたことです。

作成したParticleオブジェクトを使用して動かしてみましょう。
ループ関数ではupdateをParticleのupdateを実行するだけになります。

var particle = new Particle(12, '#D0A000', 5, -6);
particle.position.x = (canvas.width / 2) - 6;
particle.position.y = 0;

loop();

// ループ処理
function loop() {
    requestAnimFrame(loop);
    // 描画をクリアー
    ctx.clearRect(0,0, ctx.canvas.width, ctx.canvas.height);

    particle.update();
}

とりあえず落下はしてますけど、一定の速度なので全然リアルな動きではないですね。

加速度を付ける

落下すると物体のスピードは重力の影響を受けて徐々に速くなります。
なのでupdateで徐々に速くなるような仕組みを作ってあげましょう。

var Particle = function(scale, color, vx, vy, gv) {
    this.scale = scale; //大きさ
    this.color = color; //色
    this.vx = vx; //X速度
    this.vy = vy; //Y速度
    this.gv = gv; //重力 [追加]
    this.position = {   // 位置
        x: 0,
        y: 0
    };
};

 Particle.prototype.update = function() {
    this.vy += this.gv;
    this.position.y += this.vy;
    this.draw();
};

gvという重力値を設定してvyをプラス処理をしています。

加速度がついてそれらしくなってきましたが、ちょっとわかりづらいのでX方向にも動かしてみましょう。

Particle.prototype.update = function() {
    this.vy += this.gv;
    this.position.x += this.vx;
    this.position.y += this.vy;
    this.draw();
};

var particle = new Particle(12, '#D0A000', 5, -5, 0.4);
particle.position.x = 0;
particle.position.y = 100;

さらにnew時にYをマイナス方向にすることで、最初に上方向に上昇した後に放物線を描くように落下します。

バウンドさせる

今の状態は落下すると画面外に出てしまいますが、Canvasの下を地面と仮定してバウンドさせてみましょう。

Particle.prototype.update = function() {
    this.vy += this.gv;
    this.position.x += this.vx;
    this.position.y += this.vy;

    // 地面の衝突判定
    if (this.position.y > canvas.height - this.scale) {
        this.vy *= -0.6;
        this.vx *= 0.85;
        this.position.y = canvas.height - this.scale;
    }

    this.draw();
};

7〜11行目を追加しています。
vyにマイナス数値を掛けるることで逆方向(バウンド)の動きをします。
xxに小数点を掛けることで速度は減速します。

パーティクルっぽくしてみる。

最後に前回やったようにParticleオブジェクトを大量生成してみます。

var density = 100;  //パーティクルの密度
var particles = []; //パーティクルをまとめる配列
var colors = ['#D0A000', '#6DD0A5', '#E084C5'];

for (var i=0; i<density; i++) {
    var color = colors[~~(Math.random()*3)];
    var scale = ~~(Math.random()*5)+3;
    var x = Math.random() * 10 - 5;
    var y = Math.random()* 9 + 4;
    var g = Math.random()* 0.2 + 0.3;

    particles[i] = new Particle(scale, color, x, -y, g);
    particles[i].position.x = canvas.width / 2;
    particles[i].position.y = 200;

}

function loop() {
    requestAnimFrame(loop);
    // 描画をクリアー
    ctx.clearRect(0,0, ctx.canvas.width, ctx.canvas.height);

    for (var i in particles) {
        particles[i].update();
    }
}

爆発みたいな感じになりましたね。
動き的に奇妙なところもありますが、なかなか面白くないですかね。