Help us understand the problem. What is going on with this article?

初心者だけどElmでVRがしたい

はじめに

みなさんも一度は思ったことがあるでしょう

簡単にWebアプリが作れるElmと簡単にWeb-VRができるA-frameが一緒に使えたらなぁ…

わお、ちょうど良いところにelm-aframeなんていうピッタリなパッケージがあるじゃないですか!

でもよく見てみると最後のコミットのほとんどが3年前。作者のhalfzebraさんはcreate-elm-appを作るのに忙しそう
スクリーンショット 2019-12-22 7.46.43.png

閑古鳥が鳴くissue

スクリーンショット 2019-12-22 7.47.00.png

もうこうなったら自力でやるしかない

ということで、まだElmでまともなアプリを作ったことがない初心者がElmでVRを動かそうと試みてみました。

まずはGet started

まずはA-frameの公式ドキュメントにあるGet startedをElm上で実現してみましょう
A-Frame:Introduction

<html>
  <head>
    <script src="https://aframe.io/releases/1.0.1/aframe.min.js"></script>
  </head>
  <body>
    <a-scene>
      <a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
      <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
      <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>
  </body>
</html>

スクリーンショット 2019-12-22 5.08.47.png

A-frameはこんな感じでタグを書いていくだけでお手軽にVR空間にオブジェクトを置けます。とっても便利!

これをElmで再現するために、elm-aframeにはタグに対応する関数が既に用意されているんですが、いかんせん3年前のElmで書かれたものだからまともに動かない。てことでこんな感じで自分で一個一個作っていきます。

sphere : List (Attribute msg) -> List (Html msg) -> Html msg
sphere =
    node "a-sphere"

cylinder : List (Attribute msg) -> List (Html msg) -> Html msg
cylinder =
    node "a-cylinder"

scene : List (Attribute msg) -> List (Html msg) -> Html msg
scene =
    node "a-scene

あとはmainにベタ書きして

main =
  scene [ ] 
    [ box [ position -1 0.5 -3, rotation 0.0 45.0 0.0, color "#4CC3D9" ] [] 
    , sphere [ position 0.0 1.25 -5, radius 1.25, color "#EF2D5E" ] []
    , cylinder [ position 1 0.75 -3, radius 0.5, height 1.5, color "#FFC65D" ] []
    , plane [ position 0 0 -4, rotation -90 0 0, width 4, height 4, color "#7BC8A4" ] []
    , sky [ color "#ECECEC" ] [] 
    ]

スクリーンショット 2019-12-22 5.28.21.png

完成!ということでElmでA-frameのGet startedができました!お疲れさまでした!

いやElmいらなくない?

はい、これではHTMLに書いたのとあまり変わりないです。むしろElm挟んでるんで面倒くさくなってるだけです。てことで次はElmらしいTEAを使ったWebアプリ、Elmの門を開いた時に誰もが必ず通るカウンターアプリを作ってみましょう。

A-frameは普通にクリックイベントを定義できません。方法は様々あるのですが、Javascriptを使う場合はEventListenerを内包したコンポーネントを定義して、目的のオブジェクトと結び付けなければいけません。またJS側でイベントを発火させてるので、Elm側にそのことを伝えるためにportsを設定します。またVR上でクリックイベントを起こすためには<a-camera><a-cursor>も必要なので追加しています。

A-Frame:Interactions & Controllers

JS側

//クリックするとカウントアップするbox
AFRAME.registerComponent("plus-box", {
        init: function() {
          this.el.addEventListener("mousedown", function() {
            app.ports.calculate.send("Increment");
          });
        }
      });

//クリックするとカウントダウンするbox
AFRAME.registerComponent("minus-box", {
        init: function() {
          this.el.addEventListener("mousedown", function() {
            app.ports.calculate.send("Decrement");
          });
        }
      });

Elm側

-- VIEW

scene []
        [   
            atext [ avalue (String.fromInt model) , position 0 2 -4, color "black", width 8] []
        ,   box [color "#EF2D5E", position 1 0.5 -4, attribute "plus-box" "" ] []
        ,   box [color "#EF4533", position -1 0.5 -4, attribute "minus-box" ""] []
        ,   plane [ position 0 0 -4, rotation -90 0 0, width 4, height 4, color "#7BC8A4"  ] []
        ,   camera [] [ cursor [] [] ]
        ]

--SUBSCRIPTIONS

subscriptions : Model -> Sub Msg
subscriptions model = calculate Calculate 

port calculate : (String -> msg) -> Sub msg

--UPDATE

type Msg
  = Calculate String
  | Nothing


update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
    case msg of
        Calculate string    ->
            case string of
                "Increment"     ->
                    (model + 1, Cmd.none)
                "Decrement"     ->
                    (model - 1, Cmd.none)
                _               ->
                    (model, Cmd.none)

        Nothing             ->
            (model, Cmd.none)

こんな感じで、クリックイベントを起こしたいオブジェクトにコンポーネントを作って結びつけて、クリックしたらportsを通してElmに教えるようにします。portsではJSからElmに送る時に何かしら値を送らなければいけないらしい(間違ってたらごめんなさい)ので、送られてきた文字列でパターンマッチしてます。

さてどうなるでしょうか
画面収録-2019-12-22-8.03.02.gif

できました!(オブジェクトの形とか色とか適当だけど)なんとかElm + A-frameでカウンターアプリを作ることができました!やったね!!

感想

いやあElm自体初心者なのに、他のJSライブラリを併用したアプリを作るのはきつかったです。というか主にElmの基礎知識が足らなすぎて時間と労力かかりました。余裕があったら本当はOculusを使ったVRアプリまで作ってみたかったんですけどね…

結論を言うと、多分A-FrameはElmに向きません。やってる最中に「これ普通にHTMLでやればよくね…?」って何回も思いました。Elmの恩恵を受けた気は全然しないです。大体の操作はJS側でやるし、コンポーネントに状態持たせるし、そりゃ作者も更新止めますわ。

今回はこういうマイナスな感想になりましたが、Elmはちゃんと適所で使えばものすごい恩恵を受けられると思うので、JSライブラリを使う時はElmとの相性を吟味したほうが良いと思います。

ありがとうございました!

adoringonion
Unityと仲良くなれない大学生です
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした