13
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ElmAdvent Calendar 2019

Day 22

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

Last updated at Posted at 2019-12-21

はじめに

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

簡単に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との相性を吟味したほうが良いと思います。

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

13
1
0

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
13
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?