ぶらんこの開発を一度で全部は無理があるので、いくつかの範囲に区分けするぶらんこに乗っている女の子のアニメーションというのが最終目標ですが、いきなりすべてを一度には難しいので、次の工程に区分けします。
1.振り子の動きを物理シミュレーションで開発。
2.ドラッグで漕ぐ機能を追加。
前方(右)に漕ぐ(ドラッグする)と前方向に勢いが増し、後方(左)に漕ぐ(ドラッグする)と後方向に勢いが増す。
3.振り子のボール部分を女の子の画像と差し替える。
4.差し替えた画像が振り子の動きに合わせて揺れるような動きを実装する
5. 漕ぐときに女の子の脚が漕ぐ動作をする。その時、脚の動きが自然に見えるようにアニメーション効果で補間する。
以上のように5つの工程に分けました。
次からそれぞれを解説。
1.振り子の動きを物理シミュレーションで開発。この物理シミュレーションは今回はCanvas 2D APIで開発しますが、HTMLとCSS、Javascriptでも可能だそうです。
機会をみて挑戦してみます。
まずはCanvasの物理シミュレーションを。
アニメーションはCSS3を使えないのでrequestAnimationFrameを使って描画していきます。
振り子の物理シミュレーションで振り子:https://labo.studio-happyvalley.com/pendulum/sym/
MDNによるCanvasのチュートリアル:https://developer.mozilla.org/ja/docs/Web/API/Canvas_API/Tutorial
//Canvas 2D APIによる振り子の物理シミュレーション
const canvas = document.getElementById('pendulumCanvas');
const ctx = canvas.getContext('2d');
// 振り子の物理パラメータ
const length = 180; // 振り子の長さ
const gravity = 0.98; // 重力加速度
let angle = Math.PI / 3; // 初期角度(45度)
let angleVelocity = 0.0; // 角速度
let angleAcceleration = 0.0; // 角加速度
const damping = 0.999; // 減衰率 0.995
// 振り子のアニメーション関数
function updatePendulum() {
// 振り子の力学方程式
angleAcceleration = (-1 * gravity / length) * Math.sin(angle);
angleVelocity += angleAcceleration;
angleVelocity *= damping; // 減衰効果
angle += angleVelocity;
// 描画のクリア
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 振り子の位置計算
const originX = canvas.width / 2;
const originY = 50;
const pendulumX = originX + length * Math.sin(angle);
const pendulumY = originY + length * Math.cos(angle);
// 支点
ctx.beginPath();
ctx.arc(originX, originY, 5, 0, Math.PI * 2);
ctx.fillStyle = 'black';
ctx.fill();
// 振り子の棒
ctx.beginPath();
ctx.moveTo(originX, originY);
ctx.lineTo(pendulumX, pendulumY);
ctx.strokeStyle = '#3498db';
ctx.lineWidth = 2;
ctx.stroke();
// 振り子の重り
ctx.beginPath();
ctx.arc(pendulumX, pendulumY, 15, 0, Math.PI * 2);
ctx.fillStyle = '#3498db';
ctx.fill();
}
// アニメーションループ
function animate() {
updatePendulum();
requestAnimationFrame(animate);
}
animate();
2.漕ぐ機能を追加。振り子の物理シミュレーションは時間がたつと自然に止まってしまいます。
そのため、マウスドラッグで振り角度を追加できるようにします。いわゆる“ぶらんこを漕ぐ”です。
マウスドラッグを使用して、振り子の角速度(angleVelocity)にドラッグによる加速を追加します。
マウスドラッグで振り子を漕ぐ:https://labo.studio-happyvalley.com/pendulum/push/
3.振り子のボール部分を女の子の画像と差し替える。Canvas 2D APIでは画像を描画するにはdrawImage() メソッドを使用します。
基本はdrawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)となっていて、
引数は、imageは事前に読みこんんだ画像オブジェクト、接頭語のsとdで始まる座標系と寸法系の値となっています。
通常sの接頭語の値は省略して、d接頭語の値を使用します。
それぞれ、x座標、y座標、画像の横幅、画像の高さとなっています。
この工程でのポイントは画像と振り子棒の接続支点の調整です。今回は実測して設定しました。
振り子のボールを画像と差し替えサンプル:https://labo.studio-happyvalley.com/pendulum/swing/
MDNによるCanvasRenderingContext2D: drawImage() メソッド解説:https://developer.mozilla.org/ja/docs/Web/API/CanvasRenderingContext2D/drawImage
4.差し替えた画像が振り子の動きに合わせて揺れるような動きを実装する振り子の角度に合わせて画像を回転させるには、canvas の save(), translate(), rotate(), drawImage() および restore() メソッドを組み合わせて画像を描画します。要は振り子の回転値を使って画像も回転させることになります。
以下の様にrequestAnimationFrameに呼ばれるたびに画像の再描画を繰り返します。
ここでのポイントは画像の位置決めの座標と、回転軸の支点の座標をそれぞれ設定することです。
画像を振り子に合わせて揺らす:https://labo.studio-happyvalley.com/pendulum/swingR/
//ctxはCanvasRenderingContext2D のインスタンス、いわゆるコンテキスト。
ctx.translate(x座標, y座標);//回転時の支点、transform-originみたいな座標
//angleは振り子の角度
ctx.rotate(angle*-.5); // 振り子の角度に合わせて画像の回転角度を半分程度に調整
ctx.drawImage(ぶらんこ画像オブジェクト, オフセットX, オフセットY); // オフセットを加えた位置に画像を描画
5. 漕ぐときに女の子の脚が漕ぐ動作をする。その時、脚の動きが自然に見えるようにアニメーション効果で補間する。マウスドラッグで漕ぐ時、ほんとに漕いでるのか、また、どっち向きに漕いでるのかわかるように、前方向には足を延ばし後方には足を曲げるという動作を入れてみました。
これまでのぶらんこの画像だけではなく脚先だけの画像を追加。代わりにぶらんこを漕ぐ女の子の画像から脚先を削除しました。
この工程のポイントは上半身と下半身の接合支点です。
やはり脚画像の位置決め座標と回転軸の二種類の座標指定が重要です。
ピクセル測量ツールで実測しました。ほんとは計算でやりたかったのですが・・・。
次はスマホ対応の開発ですね。
ぶらんこを漕ぐデビルプリンセス:https://labo.studio-happyvalley.com/pendulum/swingCmp/