質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.81%

JavaScriptによるボイド(Canvasでのアニメーション)への背景画像の適用

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,581

ItoKyohei

score 11

Javascriptでボイド(群れのシミュレーション)が背景画像を塗りつぶすようにしたいのですが、背景画像をボイドを重ね合わせたり、ボイドに対してbackground-imageを設定することが出来ませんことが出来ません。

<!DOCTYPE html>
<meta charset="utf-8">
<title>BakuBag(MemoryEater)</title>
<style>body{margin:0;padding:0;}</style>
<canvas id="world"></canvas>
<link rel="stylesheet" href="stylesheet.css">
<div>
 <script src="bakubag.js"></script>
</div>
var FPS = 30;                   // フレームレート
var SCREEN_SIZE = 500;          // 画面サイズ
var NUM_BOIDS = 150;            // ボイドの数
var BOID_SIZE = 10;              // ボイドの大きさ
var MAX_SPEED = 600;              // ボイドの最大速度
var canvas = document.getElementById('world');
var ctx = canvas.getContext('2d');
var boids = [];                 // ボイド



window.onload = function() {
    /* 初期化 */
    canvas.width = canvas.height = SCREEN_SIZE;
    ctx.fillStyle = "rgba(0, 0, 0, 0.2)"; // ボイドの色
    for (var i=0; i<NUM_BOIDS; ++i) {
        boids[i] = {
            x: Math.random()*SCREEN_SIZE, // x座標
            y: Math.random()*SCREEN_SIZE, // y座標
            vx: 0,                        // x方向の速度
            vy: 0                         // y方向の速度
        }
    }
    /* ループ開始 */
    setInterval(simulate, 1000/FPS);
};

var simulate = function() {
    draw();                     // ボイドの描画
    move();                     // ボイドの座標の更新
};
/**
 * ボイドの描画
 */
var draw = function() {
    // 画面をクリア
    // 全てのボイドの描画
    for (var i=0,len=boids.length; i<len; ++i) {
        ctx.fillRect(boids[i].x-BOID_SIZE/2, boids[i].y-BOID_SIZE/2, BOID_SIZE, BOID_SIZE);
    }
};
/**
 * ボイドの位置の更新
 */
var move = function() {
    for (var i=0,len=boids.length; i<len; ++i) {
        // ルールを適用して速さを変更
        rule1(i);    // 近くの群れの真ん中に向かおうとする
        rule2(i);    // ボイドは他のボイドと距離を取ろうとする
        rule3(i);    // ボイドは他のボイドの平均速度に合わせようとする
        // limit speed
        var b = boids[i];
        var speed = Math.sqrt(b.vx*b.vx + b.vy*b.vy);
        if (speed >= MAX_SPEED) {
            var r = MAX_SPEED / speed;
            b.vx *= r;
            b.vy *= r;
        }
        // 壁の外に出てしまった場合速度を内側へ向ける
        if (b.x<0 && b.vx<0 || b.x>SCREEN_SIZE && b.vx>0) b.vx *= -1;
        if (b.y<0 && b.vy<0 || b.y>SCREEN_SIZE && b.vy>0) b.vy *= -1;
        // 座標の更新
        b.x += b.vx;
        b.y += b.vy;
    }    
};
/**
 * ルール1: ボイドは近くに存在する群れの中心に向かおうとする
 */
var rule1 = function(index) {
    var c = {x: 0, y:0};        // 自分を除いた群れの真ん中
    for (var i=0,len=boids.length; i<len; ++i) {
        if (i != index) {
            c.x += boids[i].x;
            c.y += boids[i].y;
        }
    }
    c.x /= boids.length - 1;
    c.y /= boids.length - 1;
    boids[index].vx += (c.x-boids[index].x) / 100;
    boids[index].vy += (c.y-boids[index].y) / 100;
};
/**
 * ルール2: ボイドは隣のボイドとちょっとだけ距離をとろうとする
 */
var rule2 = function(index) {
    for (var i=0,len=boids.length; i<len; ++i) {
        if (i != index) {
            var d = getDistance(boids[i], boids[index]); // ボイド間の距離
            if (d < 5) {
                boids[index].vx -= boids[i].x - boids[index].x;
                boids[index].vy -= boids[i].y - boids[index].y;
            }
        }
    }
};
/**
 * ルール3: ボイドは近くのボイドの平均速度に合わせようとする
 */
var rule3 = function(index) {
    var pv = {x: 0, y: 0};      // 自分を除いた群れの平均速度
    for (var i=0,len=boids.length; i<len; ++i) {
        if (i != index) {
            pv.x += boids[i].vx;
            pv.y += boids[i].vy;
        }
    }
    pv.x /= boids.length - 1;
    pv.y /= boids.length - 1;
    boids[index].vx += (pv.x-boids[index].vx) / 8;
    boids[index].vy += (pv.y-boids[index].vy) / 8;
};
/**
 * 2つのボイド間の距離
 */
var getDistance = function(b1, b2) {
    var x = b1.x - b2.x;
    var y = b1.y - b2.y;
    return Math.sqrt(x*x + y*y);
};
div {
    background-image: url(https://rr.img.naver.jp/mig?src=http%3A%2F%2Fimgcc.naver.jp%2Fkaze%2Fmission%2FUSER%2F20150327%2F67%2F6958377%2F2%2F1593x900x25ac922fae9c3d7642663d7.jpg%2F300%2F600&twidth=300&theight=600&qlt=80&res_format=jpg&op=r);

}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

質問文のCSSで背景画像が表示されない原因はdiv要素に幅、高さが設定されていないためです。

<!DOCTYPE html>
<meta charset="utf-8">
<title>BakuBag(MemoryEater)</title>
<style>
    html, body {
        width: 100%;
        height: 100%;
    }

    body {
        margin: 0;
        padding: 0;
    }

    div {
        background-image: url();
        width: 100%;
        height: 100%;
    }
</style>
<canvas id="world"></canvas>
<div>
    <script>
        var FPS = 30;                   // フレームレート
        var SCREEN_SIZE = 500;          // 画面サイズ
        var NUM_BOIDS = 150;            // ボイドの数
        var BOID_SIZE = 10;              // ボイドの大きさ
        var MAX_SPEED = 600;              // ボイドの最大速度
        var canvas = document.getElementById('world');
        var ctx = canvas.getContext('2d');
        var boids = [];                 // ボイド


        window.onload = function () {
            /* 初期化 */
            canvas.width = canvas.height = SCREEN_SIZE;
            ctx.fillStyle = "rgba(0, 0, 0, 0.2)"; // ボイドの色
            for (var i = 0; i < NUM_BOIDS; ++i) {
                boids[i] = {
                    x: Math.random() * SCREEN_SIZE, // x座標
                    y: Math.random() * SCREEN_SIZE, // y座標
                    vx: 0,                        // x方向の速度
                    vy: 0                         // y方向の速度
                }
            }
            /* ループ開始 */
            setInterval(simulate, 1000 / FPS);
        };

        var simulate = function () {
            draw();                     // ボイドの描画
            move();                     // ボイドの座標の更新
        };
        /**
         * ボイドの描画
         */
        var draw = function () {
            // 画面をクリア
            // 全てのボイドの描画
            for (var i = 0, len = boids.length; i < len; ++i) {
                ctx.fillRect(boids[i].x - BOID_SIZE / 2, boids[i].y - BOID_SIZE / 2, BOID_SIZE, BOID_SIZE);
            }
        };
        /**
         * ボイドの位置の更新
         */
        var move = function () {
            for (var i = 0, len = boids.length; i < len; ++i) {
                // ルールを適用して速さを変更
                rule1(i);    // 近くの群れの真ん中に向かおうとする
                rule2(i);    // ボイドは他のボイドと距離を取ろうとする
                rule3(i);    // ボイドは他のボイドの平均速度に合わせようとする
                // limit speed
                var b = boids[i];
                var speed = Math.sqrt(b.vx * b.vx + b.vy * b.vy);
                if (speed >= MAX_SPEED) {
                    var r = MAX_SPEED / speed;
                    b.vx *= r;
                    b.vy *= r;
                }
                // 壁の外に出てしまった場合速度を内側へ向ける
                if (b.x < 0 && b.vx < 0 || b.x > SCREEN_SIZE && b.vx > 0) b.vx *= -1;
                if (b.y < 0 && b.vy < 0 || b.y > SCREEN_SIZE && b.vy > 0) b.vy *= -1;
                // 座標の更新
                b.x += b.vx;
                b.y += b.vy;
            }
        };
        /**
         * ルール1: ボイドは近くに存在する群れの中心に向かおうとする
         */
        var rule1 = function (index) {
            var c = {x: 0, y: 0};        // 自分を除いた群れの真ん中
            for (var i = 0, len = boids.length; i < len; ++i) {
                if (i != index) {
                    c.x += boids[i].x;
                    c.y += boids[i].y;
                }
            }
            c.x /= boids.length - 1;
            c.y /= boids.length - 1;
            boids[index].vx += (c.x - boids[index].x) / 100;
            boids[index].vy += (c.y - boids[index].y) / 100;
        };
        /**
         * ルール2: ボイドは隣のボイドとちょっとだけ距離をとろうとする
         */
        var rule2 = function (index) {
            for (var i = 0, len = boids.length; i < len; ++i) {
                if (i != index) {
                    var d = getDistance(boids[i], boids[index]); // ボイド間の距離
                    if (d < 5) {
                        boids[index].vx -= boids[i].x - boids[index].x;
                        boids[index].vy -= boids[i].y - boids[index].y;
                    }
                }
            }
        };
        /**
         * ルール3: ボイドは近くのボイドの平均速度に合わせようとする
         */
        var rule3 = function (index) {
            var pv = {x: 0, y: 0};      // 自分を除いた群れの平均速度
            for (var i = 0, len = boids.length; i < len; ++i) {
                if (i != index) {
                    pv.x += boids[i].vx;
                    pv.y += boids[i].vy;
                }
            }
            pv.x /= boids.length - 1;
            pv.y /= boids.length - 1;
            boids[index].vx += (pv.x - boids[index].vx) / 8;
            boids[index].vy += (pv.y - boids[index].vy) / 8;
        };
        /**
         * 2つのボイド間の距離
         */
        var getDistance = function (b1, b2) {
            var x = b1.x - b2.x;
            var y = b1.y - b2.y;
            return Math.sqrt(x * x + y * y);
        };
    </script>
</div>


また、質問文から質問者さんが想像している動作は以下のようなものだと思うのですが、いかがでしょうか?

<!DOCTYPE html>
<meta charset="utf-8">
<title>BakuBag(MemoryEater)</title>
<style>
    html, body {
        width: 100%;
        height: 100%;
    }

    body {
        margin: 0;
        padding: 0;
    }

    canvas {
        background-image: url();
    }
</style>
<canvas id="world"></canvas>
<div>
    <script>
        var FPS = 30;                   // フレームレート
        var SCREEN_SIZE = 500;          // 画面サイズ
        var NUM_BOIDS = 150;            // ボイドの数
        var BOID_SIZE = 10;              // ボイドの大きさ
        var MAX_SPEED = 600;              // ボイドの最大速度
        var canvas = document.getElementById('world');
        var ctx = canvas.getContext('2d');
        var boids = [];                 // ボイド


        window.onload = function () {
            /* 初期化 */
            canvas.width = canvas.height = SCREEN_SIZE;
            ctx.fillStyle = "rgba(0, 0, 0, 0.2)"; // ボイドの色
            for (var i = 0; i < NUM_BOIDS; ++i) {
                boids[i] = {
                    x: Math.random() * SCREEN_SIZE, // x座標
                    y: Math.random() * SCREEN_SIZE, // y座標
                    vx: 0,                        // x方向の速度
                    vy: 0                         // y方向の速度
                }
            }
            /* ループ開始 */
            setInterval(simulate, 1000 / FPS);
        };

        var simulate = function () {
            draw();                     // ボイドの描画
            move();                     // ボイドの座標の更新
        };
        /**
         * ボイドの描画
         */
        var draw = function () {
            // 画面をクリア
            // 全てのボイドの描画
            for (var i = 0, len = boids.length; i < len; ++i) {
                ctx.fillRect(boids[i].x - BOID_SIZE / 2, boids[i].y - BOID_SIZE / 2, BOID_SIZE, BOID_SIZE);
            }
        };
        /**
         * ボイドの位置の更新
         */
        var move = function () {
            for (var i = 0, len = boids.length; i < len; ++i) {
                // ルールを適用して速さを変更
                rule1(i);    // 近くの群れの真ん中に向かおうとする
                rule2(i);    // ボイドは他のボイドと距離を取ろうとする
                rule3(i);    // ボイドは他のボイドの平均速度に合わせようとする
                // limit speed
                var b = boids[i];
                var speed = Math.sqrt(b.vx * b.vx + b.vy * b.vy);
                if (speed >= MAX_SPEED) {
                    var r = MAX_SPEED / speed;
                    b.vx *= r;
                    b.vy *= r;
                }
                // 壁の外に出てしまった場合速度を内側へ向ける
                if (b.x < 0 && b.vx < 0 || b.x > SCREEN_SIZE && b.vx > 0) b.vx *= -1;
                if (b.y < 0 && b.vy < 0 || b.y > SCREEN_SIZE && b.vy > 0) b.vy *= -1;
                // 座標の更新
                b.x += b.vx;
                b.y += b.vy;
            }
        };
        /**
         * ルール1: ボイドは近くに存在する群れの中心に向かおうとする
         */
        var rule1 = function (index) {
            var c = {x: 0, y: 0};        // 自分を除いた群れの真ん中
            for (var i = 0, len = boids.length; i < len; ++i) {
                if (i != index) {
                    c.x += boids[i].x;
                    c.y += boids[i].y;
                }
            }
            c.x /= boids.length - 1;
            c.y /= boids.length - 1;
            boids[index].vx += (c.x - boids[index].x) / 100;
            boids[index].vy += (c.y - boids[index].y) / 100;
        };
        /**
         * ルール2: ボイドは隣のボイドとちょっとだけ距離をとろうとする
         */
        var rule2 = function (index) {
            for (var i = 0, len = boids.length; i < len; ++i) {
                if (i != index) {
                    var d = getDistance(boids[i], boids[index]); // ボイド間の距離
                    if (d < 5) {
                        boids[index].vx -= boids[i].x - boids[index].x;
                        boids[index].vy -= boids[i].y - boids[index].y;
                    }
                }
            }
        };
        /**
         * ルール3: ボイドは近くのボイドの平均速度に合わせようとする
         */
        var rule3 = function (index) {
            var pv = {x: 0, y: 0};      // 自分を除いた群れの平均速度
            for (var i = 0, len = boids.length; i < len; ++i) {
                if (i != index) {
                    pv.x += boids[i].vx;
                    pv.y += boids[i].vy;
                }
            }
            pv.x /= boids.length - 1;
            pv.y /= boids.length - 1;
            boids[index].vx += (pv.x - boids[index].vx) / 8;
            boids[index].vy += (pv.y - boids[index].vy) / 8;
        };
        /**
         * 2つのボイド間の距離
         */
        var getDistance = function (b1, b2) {
            var x = b1.x - b2.x;
            var y = b1.y - b2.y;
            return Math.sqrt(x * x + y * y);
        };
    </script>
</div>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/15 07:43

    本当にありがとうございますっ・・・!完璧に動作しました。要領を得ない質問だったと思うのですが、意図を汲んで手稲に回答して頂きとても分かりやすかったです。
    一つのHTMLファイル内に全て記述するのもスマートで感動しました

    キャンセル

  • 2017/08/15 08:00

    すみません、もう一件質問させて頂いてよろしいでしょうか?
    画像が何枚も連なるように表示するのではなく、一枚で画面全てを覆うようにするにはどうすれば良いでしょうか?
    自分で少し挑戦してみたのですが分かりませんでした

    キャンセル

  • 2017/08/15 22:12

    回答文のコードを以下のように変更することで可能です。
    ```CSS
    canvas {
    background-image: url();
    background-size: cover;
    background-position: center;
    }
    ```

    キャンセル

+2

その位置のdivに背景をつけても高さが無いので表示されません。

canvas {
    background-image: url(/*省略*/);
}

HTMLは、htmlとheadとbodyくらい使いましょう。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>BakuBag(MemoryEater)</title>
    <style>body{margin:0;padding:0;}</style>
    <link rel="stylesheet" href="stylesheet.css">
    <script src="bakubag.js"></script>
  </head>
  <body>
    <canvas id="world"></canvas>
  </body>
</html>

動くサンプル:https://jsfiddle.net/y88s3634/

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/15 07:46

    ありがとうございます!
    おっしゃる通りですね(*_*)
    HTMLの基本の作法のようなものを学べて助かりました

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.81%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る