だら$ちっぷす

仕事の覚書です

matter.jsを使ってみる

タワーバトルっぽいのを作ってみようと思ったんで、物理演算ライブラリとかないかなーとググってたら「物理エンジン」というワードを見つけた
物理エンジンで探してみたら、PhysX とか Bullet とかの名前を見かけたんだけど、これらはVSとかpythonのようだ
別にそれでもいいんだけど鯖なくても使えるのがいいなー。javascriptでないかなー?
で、matter.jsを見つけました!あと、Box2D。行き詰まったらこっちも試してみよう


brm.io


トップページの「Source Code」をクリック

  f:id:daralib:20201116114039j:plain

「releases」をクリック

  f:id:daralib:20201116114330j:plain

zipなりtarなり落として解凍

  f:id:daralib:20201116114530j:plain

解凍したフォルダの下のbuildの下のmatter.min.jsを任意の場所に置いて、htmlにインクルードしてやればOK

HTML部分は、こんな感じ

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>matter.js 使ってみる</title>
   <script src="matter.min.js"></script>
</head>
<body>
    <div id="id_container" style="width:640px;height:480px;border:solid 2px #008000">
        <!-- 描画コンテナ -->
    </div>
</body>
</html>



スクリプト部分

<script>
//---------------------
// 画面起動時
//---------------------
window.addEventListener("DOMContentLoaded", function()
{
    //matter初期設定
    matter_init();

    //床とか壁を作る
    make_static();

    //イベントリスナ作成(左ボタンを押下すると箱が出現する)
    id_container.addEventListener("mousedown", mousedown, {passive: true, capture: true});
});


//---------------------
// matter初期設定
//---------------------
var engineWorld; //物理エンジン

function matter_init()
{
    //物理エンジン作成
    const engine = Matter.Engine.create();
    engineWorld = engine.world;
    Matter.Engine.run(engine);

    //レンダラ作成
    const render = Matter.Render.create(
                {
                    element:    id_container,   //描画コンテナ
                    engine:     engine,         //物理エンジン
                    options:
                    {
                        width:      640,        //カンバスWidth(コンテナのサイズは反映されない)
                        height:     480,        //カンバスHeight(コンテナのサイズは反映されない)
                        background: "#ffffff",   //背景色(コンテナの色は反映されない)
                        wireframes: false,     //ワイヤフレームにしません
                    }
                });
    Matter.Render.run(render);
}


//---------------------
// 床とか壁を作る
//---------------------
function make_static()
{
    const table = Matter.Bodies.rectangle
    (
        320, 400, 100, 10,  //中心x, 中心y, 幅, 高さ
        {
            isStatic: true //固定する
        }
    );
    Matter.World.add(engineWorld, [table]);
}


//--------------------------------
// 左ボタンを押下したら箱を生成する
//--------------------------------
var click_cnt = 0;
function mousedown(ev)
{
    if(ev.button != 0)
        return;

    const block = Matter.Bodies.rectangle //四辺形
    (
        ev.offsetX, ev.offsetY, 80, 40,     //中心x, 中心y, 幅, 高さ
        {
            /* このあたりの数値が設定できると思われる。まだ試し中
           density         :   密度
           restitution     :   弾力
           friction        :   動摩擦
           frictionStatic  :   静止摩擦
           frictionAir     :   空気抵抗
           motion          :   運動
           slop            :   揺れ
           torque          :   ねじり
           */
            render:
            {
                sprite:
                {    //箱の表面に番号を描いた画像を貼り付ける
                    texture: make_image("" + ++click_cnt, 80, 40)
                }
            }
        }
    );
                        
    Matter.World.add(engineWorld, [block]);
}

//--------------------------------
// 番号を描いた画像を用意する
//--------------------------------
function make_image(str, w, h) 
{
    //カンバス作成
    let canv = document.createElement("canvas");
    canv.width = w;
    canv.height = h;

    //コンテキスト取得
    let ctx = canv.getContext("2d");

    //背景塗る
    ctx.fillStyle = "#ffc0cb";
    ctx.fillRect(0, 0, w, h);

    //字を描く
    ctx.fill();
    ctx.fillStyle = "#000000";
    ctx.textAlign = "center";
    ctx.fillText(str, w / 2, h / 2);

    //画像をurlに変換して返す
    return canv.toDataURL("image/png");
}
</script>



上記、実行できるやつそのままなんだけど、matter.jsが置けないので、はてな上で動かすんは無理かーと思いました。残念。