LoginSignup
17

More than 5 years have passed since last update.

A-FrameでVR迷路を移動する

Posted at

A-Frameの勉強として、VR迷路を作ってみました。
ソースコードはgithubで公開しています。

作るもの

A-Frameを使ったVR迷路

"スマートフォン(iOS,Android)+Cardboard"だけで操作できるようlook-controlsで視点を変えることで、camera(カメラ)の向いている方向に移動させます。

迷路の配置

碁盤目状の9×9マスに壁と通路を作るイメージで、<a-plane>の上に<a-box>を並べているだけです。
class="collidable"は、当たり判定のために付与しているクラスです。詳しくは、後で説明します。

index.html
<a-entity id="maze" position="-4 1 -10">
    <a-box class="collidable" position="0 0 0" width="1" height="2" depth="1" color="#4CC3D9"></a-box>
    <a-box class="collidable" position="0 0 1" width="1" height="2" depth="1" color="#4CC3D9"></a-box>
    <a-box class="collidable" position="0 0 2" width="1" height="2" depth="1" color="#4CC3D9"></a-box>
    <a-box class="collidable" position="0 0 3" width="1" height="2" depth="1" color="#4CC3D9"></a-box>
    ...
    <a-box class="collidable" position="8 0 7" width="1" height="2" depth="1" color="#4CC3D9"></a-box>
    <a-box class="collidable" position="8 0 8" width="1" height="2" depth="1" color="#4CC3D9"></a-box>
</a-entity>
<a-plane  rotation="-90 0 0" width="100" height="100" color="#7BC8A4" static></a-plane>

上から見ると、こんな感じです。
localhost-8383-aframe-sample-index.html(iPad) (2).png

プレイヤーの移動

camera(カメラ)の向きからベクトルを計算し、移動速度(speed)を掛けることで移動量とします。
上下は考慮しないので、y軸の回転角から三角関数(あまり自信はない)で求めます。

index.js
var speed = 0.01;
var isIntersect = false;

function movePlayer() {
    var camera = document.getElementById('camera');

    if (camera && !isIntersect) {
        var position = camera.getAttribute('position');
        var rotation = camera.getAttribute('rotation');

        position.x += -Math.cos((rotation.y - 90) * Math.PI / 180) * speed;
        position.z += Math.sin((rotation.y - 90) * Math.PI / 180) * speed;
        camera.setAttribute('position', position);
    }
}

A-FrameはHTMLで記述されているため、getAttributesetAttributeで移動・回転ができます。
isIntersectは壁との当たり判定の結果を格納する変数です。こちらも後で説明します。

movePlayer()は、くり返し実行する必要があるので、renderメソッドを作成してループさせます。

index.js
var t = 0;

function render() {
    t += 0.01;
    requestAnimationFrame(render);
    movePlayer();
}
render();

プレイヤーと壁の当たり判定

camera(カメラ)にraycasterを追加して、視線(=進行方向)と交差するオブジェクトの有無を判定します。

index.html
<a-entity id="camera" camera look-controls raycaster="objects: .collidable; far: 0.5;" collider-check rotation="0 0 0" position="0 0.3 0"></a-entity>

まず、raycasterのプロパティについて説明します。

  • objects: .collidable;
    当たり判定の対象を指定するプロパティです。
    class="collidable"が付与されたオブジェクトを対象にしており、迷路の壁にあたる<a-box>は当たり判定の対象、床にあたる<a-plane>は対象外となります。
  • far: 0.5;
    当たり判定を行う距離です。
    デフォルト値が"Infinity"となっていて、変更しないと視線に壁があるだけで衝突と判定されてしまいます。

次に、当たり判定用のコンポーネントとして、collider-checkを設定します。

index.js
AFRAME.registerComponent('collider-check', {
    dependencies: ['raycaster'],
    init: function () {
        this.el.addEventListener('raycaster-intersection', function () {
            isIntersect = true;
        });
        this.el.addEventListener('raycaster-intersection-cleared', function () {
            isIntersect = false;
        });
    }
});

raycasterのプロパティで設定した距離内に交差オブジェクトがある場合、raycaster-intersectionイベントが発生します。この間、isIntersecttrueになるようにします。
同様に、交差オブジェクトがない場合、raycaster-intersection-clearedイベントが発生しますので、isIntersectfalseにします。

先程、プレイヤーの移動を行う条件式に!isIntersectを入れていたので、"壁に近付くと止まる"、"前方に壁がなければ前進する"という挙動になります。

これで、コーディングは完了です。

ビルド&デプロイ

gulpを使ってビルドしました。
記事の内容から逸れるので、詳細は割愛します。

$ gulp default

動作確認のためにWebサーバを用意するのも面倒なので、Amazon S3に必要なファイルだけアップしました。

  • dist/app.min.js
  • index.html

迷路に入ってみる

スマートフォン実機(iPhone SE)で、index.htmlにアクセスします。
IMG_1326 (1).png

向きを変えることで、ちゃんと迷路を抜けられました。
ただ、アドレスバーが邪魔ですね。

気を取り直して、VRモードに切り替えます。
視差効果で左右の表示が異なっているのがわかります。
IMG_1327.png

最後に、以前に自作したCardboard初号機にセットして見てみます。
IMG_1328.JPG

立体的に見えた!
...けど、没入感はあまりないかな。

まとめ

A-Frameを使ってVR体験できる迷路を作りました。

ほとんどJavaScriptを書かずに実装できたので、three.jsと比べて、スッキリと見やすく記述できそうです。
移動や当たり判定は、ゲームやナビゲーション等にも応用できそうですし、何かの役に立てば幸いです。

余力があれば、スタート・ゴール時の処理を追加してタイム計測したり、ステージを切り替えられるようにすると、ミニゲームっぽくなるかなと思います。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17