
こんにちは、WEBの佐野です。
今回は、自分で実装すると凄く大変そうな物理演算を行ってくれるMatter.jsをご紹介したいと思います。
一般的なWEBサイトの制作では出番が少ないかもしれませんが、ミニコンテンツを制作する機会があれば、スマホにも対応しているので色々と幅が広がるかと思います。
Matter.jsとは
簡単に言うと、アニメーションやWEBゲームを作る際に使う物理演算を行ってくれるライブラリになります。
スマートフォンも対応してくれており、非常にありがたいものとなっています。
ダウンロードやデモはこちら
今回の実装機能
今回実装する機能は本家サイトのデモを見た時に印象に残った3機能にしたいと思います。
①落下
②バウンド
③要素を掴む
フォルダ構成
今回はのサンプルは下記の構成で作成しました。
/index.html
/jsフォルダ
┗matter.js
サンプルコード
こちら参考程度に作ったもので、複数のボールが対応範囲内で設定した挙動をします。
①の落下のみ動作が止まるの防ぐ為、四方に移動する様にしています。
See the Pen EZmBra by otwo (@otwo) on CodePen.
①~③を含んだソースコードはこちらです。
個別の記述は後述します。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>matter.js demo/title>
<script src="./js/matter.js">/script>
</head>
<body>
<script>
// 変数宣言
const engWidth = 680; // 表示領域(幅)
const engHeight = 400; // 表示領域(高)
const wall = 10; // 表示領域周辺を囲む壁の厚み
const ball = 30; // 表示するボールの数
const density = 0.1; // 質量
const frictionAir = 0.1; // 空気抵抗
const restitution = 0.5; // 弾力性
var ballSize = 20; // ボールのサイズ
var gravityx = 0.5; // 重力方向x
var gravityy = 0.5; // 重力方向y
var objs = []; // 作成オブジェクト管理用
// Engine生成(表示領域)
var engine = Matter.Engine.create(document.getElementById("matter"), {
render: {
options: {
wireframes: false, // ワイヤー表示
width: engWidth, // canvasの横幅
height: engHeight, // canvasの高さ
background: "rgba(0, 0, 0, 1)"
}
}
});
engine.world.gravity.y = gravityy;
engine.world.gravity.x = gravityx;
// 四方に壁を作成(10pxで生成)
// Matter.Bodies.rectangle(x, y, width, height, options)
// 補足:x,yともに表示オブジェクトの中心位置を指定
objs.push(Matter.Bodies.rectangle(engWidth/2, wall/2, engWidth, wall, {isStatic: true})); // 上
objs.push(Matter.Bodies.rectangle(engWidth-wall/2, engHeight/2, wall, engHeight, {isStatic: true})); // 右
objs.push(Matter.Bodies.rectangle(engWidth/2, engHeight-wall/2, engWidth, wall, {isStatic: true})); // 下
objs.push(Matter.Bodies.rectangle(wall/2, engHeight/2, wall, engHeight, {isStatic: true})); // 左
// ボールを作成
for (var i = 0; i < ball; i++) {
var x = Math.random()*engWidth; // ボールの初期表示位置:xをランダムで生成
var y = Math.random()*engHeight;
objs.push(Matter.Bodies.circle(x, y, ballSize, {
density: density, // 質量
frictionAir: Math.random()*frictionAir, // 空気抵抗
restitution: Math.random()+restitution, // 弾力性
}));
}
// 作成オブジェクトをワールドに追加
Matter.World.add(engine.world, objs);
// ドラッグ処理
var MouseConstraint = Matter.MouseConstraint;
var mousedrag = MouseConstraint.create(engine, {
element: document.getElementById("matter").childNodes[0],
});
Matter.World.add(engine.world, mousedrag);
// 物理演算実行
Matter.Engine.run(engine);
// 重力方向の更新
function update(){
if(Math.random() > 0.5){
// 重力方向を反転させる
gravityy = gravityy * -1;
}
if(Math.random() > 0.5){
// 重力方向を反転させる
gravityx = gravityx * -1;
}
engine.world.gravity.y = gravityy;
engine.world.gravity.x = gravityx;
}
// 2秒毎に重力方向の切り替え判定
setInterval(update , 2000);
</script>
</body>
</html>
①落下
今回はデモ用に、ボールを動かし続けているので、落下している様には見えにくいですが、
engine.world.gravity.y = gravityy; engine.world.gravity.x = gravityx;
で重力の向きを設定しています。
・gravity.y
+数値指定:右方向に要素が動きます
-数値指定:左方向に要素が動きます
・graviry.x
+数値指定:下方向に要素が動きます
-数値指定:左方向に要素が動きます
②バウンド
objs.push(Matter.Bodies.circle(x, y, ballSize, {
density: density, // 質量
frictionAir: Math.random()*frictionAir, // 空気抵抗
restitution: Math.random()+restitution, // 弾力性
}));
上のソースコードで配置する要素を作成していて、質量や弾力性などのパラメーターを設定できます。
変数のfrictionAirとrestitutionはソース上部の変数宣言で数値を設定しているので、色々な数値を入れて動かしてみてください!
なかなか面白い動きをしてくれます!!
③要素を掴む
上のデモでは、ボールを掴んで振り回すことができます。
ボール同士が衝突する際の勢いも判定していて、面白くて少しの間遊んでしまうくらい良く出来ています!
デモでは掴んだボールがわかる様に線が出ていますが、こちらは以下の方法で消すこともできます。
var mousedrag = MouseConstraint.create(engine, {
element: document.getElementById("matter").childNodes[0],
constraint: {
render: {
strokeStyle: "rgba(0, 0, 0, 0)" //マウス操作の表示を隠す
}
}
});
最後に
バウンドするアニメーションを自作する事も出来るかと思いますが、実際に作り出すと時間も手間も凄くかかります。
そう言った時に今回の様な既存のものを使って時間短縮が計るのは大いに助かりますよね!
使用頻度が関わらず「知ってる」「知らない」での違いは大きいと思うので、アイデアの引き出しの1つとして覚えたら嬉しいです。
canvasもですがwebGLを使った面白いサイトも多くあるので、そちらも今後触れていきたいなと思います!
それではまた!!

























ピックアップ
