2019-06-17に更新

A-Frameでキーボード操作のラジコンを作ってみる

A-FrameでVR上で動くラジコンを作ってみようと思ったが、とりあえずブラウザ上でテストできないとデバッグ辛いかなと思い、まずはVRではなく普通にブラウザの3D空間上でキーボード操作ができるようにしてみた。

単にVR機器を持ってない人もブラウザ上で体験できたらいいかなというのもあるし、そうでなくてもプログラムを変える度にOculus Questをつけたり外したりするのは結構面倒なので。

キーボード操作の事前準備

デフォルトでWASDキーが空間移動に使われているので、下記の方法で無効にする。

A-Frameでデフォルトのキーボード操作を無効にする

3Dモデル用のコンポーネントを作成

とりあえず3Dモデルの位置や角度を調整したりするために、動かすオブジェクト用のコンポーネントを作成する。

何をやっているかというと、キーボードイベントを設定し、キーが押されたらステータスを変更する処理を追加し、tickという常時呼ばれ続けるメソッドの中でそのステータスに応じて車を動かしている。

    AFRAME.registerComponent('car', {
      init: function () {
        window.addEventListener('keydown', this.onKeyDown.bind(this))
        window.addEventListener('keyup', this.onKeyUp.bind(this))
        this.rotating = null
        this.speeding = null
        this.speed = 0.0
      },
      onKeyDown: function (e) {
        if (e.keyCode == 65) {
          this.rotating = 'left'
        } else if (e.keyCode == 68) {
          this.rotating = 'right'
        } else if (e.keyCode == 87) {
          this.speeding = 'up'
        } else if (e.keyCode == 83) {
          this.speeding = 'down'
        }
      },
      onKeyUp: function (e) {
        if (e.keyCode == 65 && this.rotating == 'left') {
          this.rotating = null
        } else if (e.keyCode == 68 && this.rotating == 'right') {
          this.rotating = null
        } else if (e.keyCode == 87 && this.speeding == 'up') {
          this.speeding = null
        } else if (e.keyCode == 83 && this.speeding == 'down') {
          this.speeding = null
        }
      },
      tick: function () {
        if (this.speeding != null) {
          const direction = this.speed > 0 ? 1 : -1
          if (this.rotating == 'left') {
            this.el.object3D.rotateY(direction * Math.PI / 120)
          } else if (this.rotating == 'right') {
            this.el.object3D.rotateY(direction * -Math.PI / 120)
          }
        }
        if (this.speeding == 'up') {
          this.speed = Math.min(this.speed + 0.02, 0.2)
        } else if (this.speeding == 'down') {
          this.speed = Math.max(this.speed - 0.02, -0.2)
        }
        const position = this.el.getAttribute('position')
        const rotation = this.el.getAttribute('rotation')
        const angle = Math.PI * rotation.y / 180
        position.x += this.speed * Math.sin(angle)
        position.z += this.speed * Math.cos(angle)
        this.el.setAttribute('position', position)
        if (this.speed > 0) {
          this.speed = Math.max(this.speed - 0.01, 0)
        }
        if (this.speed < 0) {
          this.speed = Math.min(this.speed + 0.01, 0)
        }
      }
    })

あとはこれを実際の3Dモデルに紐付けるだけ。

        <a-obj-model src="#car-obj" mtl="#car-mtl" car></a-obj-model>

下記が実際にブラウザ上で試してるところ。

GitHubページで実際に試せる。WASDキーで操作。

https://dala00.github.io/a-frame-car-sample/

ソースはGitHubにもアップしてある。

dala00/a-frame-car-sample: Car control sample with A-Frame

物理エンジンを使う場合

今回は物理エンジンを使っておらず、直接計算して要素の属性を更新する方法で試している。物理エンジンを使う場合、内部の角度やvelocityを利用して動かす形にする必要があるので今回の形では動かせない。

まとめ

とりあえずブラウザ上でキーボードを使って操作できるようにした。VR用にスティック操作などを入れる場合はデバッグが必要な箇所が多いと非常に大変なので、このようにして基本的な処理はなるべく使いまわすことでなるべく簡単に開発ができるようにした感じ。

スティック操作ももうできているのでまた近日中に記事を書く。


だら@Crieit開発者

Crieitの開発者です。 主にLAMPで開発しているWebエンジニアです(在宅)。大体10年程。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel5, CakePHP3, JavaScript, RoR 趣味:Elixir, Phoenix, Node, Nuxt, Express, Vue等色々

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

関連記事

コメント