一週間で遊戯王風ARカードゲームを作ってみた

# AR.jsを使って遊戯王カード（アニメ版）ぽいゲームを作ってみた
初めてQiitaに投稿いたします。
10月から[G's Academy](https://gsacademy.tokyo/)という~~プログラミングスクール~~エンジニア養成学校に通っており、入学一ヶ月の成果としてARカードゲームを作りました。
昔からの夢が実現できて嬉しかったのでみんなにも見て貰いたいです。

### お前は誰だ
前職は大手SIerで保守運用SEをやってました。
元々IT技術が好きだったのですが、SIerの管理メインの業務に違和感を持って先月晴れて退職をキメました。ビバ無職

プログラミングは独学でdotinstallなどを少しだけ触ってましたが、本格的に始めたのは一ヶ月ほど前にG's Academyに入学してからです。
ちなみに前職では障害対応を通じてLinuxコマンドとSQLを叩きまくる経験を手に入れました。

##作ったもの
これです。
制作期間は約一週間です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">G’s Academyというエンジニア養成学校に通って一ヶ月目の課題で遊戯王風ARカードゲームを作りました。<br>小学校の頃からの夢が一つ叶いました。<br>見やすくするためにフィールドカードは隠してます。<br>※音が出ますのでご注意。 <a href="https://t.co/mhn2MxTAOc">pic.twitter.com/mhn2MxTAOc</a></p>&mdash; Sugiemon＠SIerを退職してエンジニア修行 (@ySugiemon) <a href="https://twitter.com/ySugiemon/status/1194992895117295617?ref_src=twsrc%5Etfw">November 14, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

フィールドカードをセットするとデュエルスタート
それぞれのマーカーを読み込ませてモンスター召喚、ターン変更、バトルを実行します。
先にモンスターを２体倒すと勝利です。やったー！

###こだわりポイント
####モンスターの攻撃モーションの多彩さ
この後出てきますが、全て`a-entity`タグに`animation`属性を付けたり外したりして実装してます。
setTimeout地獄になっています。もっとスマートにコードを書きたい。

動画に出てこなかった子たち
![ish.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532390/339f5a36-bf03-4248-2b7f-2e93fbcb6c50.gif)
![buzz.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532390/5f8df6b6-c8d1-5c08-5813-c9da6207ce1b.gif)

####状態管理
1ターンに行動（召喚・攻撃）できるのは一度までで、それを超えるとメッセージが出るようにしています。
![スクリーンショット 2019-11-15 0.21.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532390/6939e1dd-e2c5-414c-7de9-71fd463b8e01.png)

#使った技術・サービス
ここからは実装についてのお話
###[A-Frame](https://aframe.io/) / [AR.js](https://github.com/jeromeetienne/AR.js)
```game.html
<!doctype HTML>
<html>
  <head>
    <title>AR Card Game</title>
    <script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script>
    <script src="https://cdn.rawgit.com/jeromeetienne/AR.js/1.7.8/aframe/build/aframe-ar.js"></script>
  </head>
  <body style='margin : 0px; overflow: hidden;'>
    <a-scene embedded arjs="patternRatio:0.9;">
      <a-entity camera></a-entity>
    </a-scene>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="js/game.js"></script>
    </body>
</html>
```
A-Frameの後にAR.jsを読み込ませるだけでページ起動時にカメラが起動してマーカーを読み取るようになります。
DOMの操作は全てJavaScriptに寄せているため、HTMLはこれだけです。
基本的な使い方はこちらの記事を参考にしました。
[A-FrameとAR.jsで超簡単AR（PC・スマホ・マルチマーカー対応）](https://qiita.com/mkoku/items/c635566e829c303a7d3f)


```game.js
let monsters = [{
  name:'plesiomonster',
  atk:2200,
  hp:2000,
  dead:0,
},{
  name:'dimonstrodon',
  atk:2800,
  hp:2800,
  dead:0,
}]
$.each(monsters,(i,v)=>{
  let $monster = $('<a-marker class="monster" '+
                             'id="'+v.name+'" '+
                             'type="pattern" '+
                             'url="marker/pattern/pattern-'+v.name+'.patt" '+
                             'registerd-events>'+
                     '<a-entity gltf-model="model/'+v.name+'.gltf" position="0 1 0">'+
                     '</a-entity>'+
                   '</a-marker>');
  $('a-scene').append($monster);
}
AFRAME.registerComponent("registerd-events", {
  init : function() {
    let marker = this.el;
    marker.addEventListener("markerFound", function() {
      if($(marker).attr('class') == 'monster'){
        // モンスター召喚
      }
    }
  }
}
```
一部抜粋
`a-marker`タグにカスタムのpattファイルを指定して認識させ、その中に`a-entity`を置いてオブジェクトを読み込んでいます。
`registerd-events`を記載しておくと`markerFound`や`markerLost`などのイベントを拾うことができるので、モンスターの召喚の他にもフィールドカードやBattleカードのマーカーを作って、`markerFound`した時にそれに応じた処理を実行しています。

オブジェクトの動きは`animation`属性を追加して実装しています。
例えばモンスター召喚時の迫り上がってくる動きは以下ようになってます。
地道な作業でした。

```game.js
$('#'+marker.id).children('a-entity').attr('animation','property:position;from:0 -1 0;to:0 1 0;dur:2000;easing:linear;');
```

カスタムマーカーの作成は以下の記事を参考に[AR.js Marker Training](https://jeromeetienne.github.io/AR.js/three.js/examples/marker-training/examples/generator.html)を使いました。
[「AR.js」でオリジナルのマーカーを設定する方法](https://liginc.co.jp/457071)

###[google Poly](https://poly.google.com/?hl=ja) / [Blender](https://www.blender.org/)  
オブジェクトはgoogle Polyから取得しました。
![poly.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532390/68f8aaeb-7e55-8500-96e5-1ba923aa325a.gif)

もしアプリケーションを公開したい場合はアセットのライセンスを必ず確認しましょう。
Polyのアセットの多くはCC-BYライセンスで公開されています。
<img width="646" alt="poly_licence.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532390/3ca5c189-54c6-8b3b-b4de-bd9abc929fa5.png">

Polyから取得したオブジェクトはサイズや向きがバラバラなことが多いです。
最初は`a-entity`タグ内で`scale`や`rotation`を調整していたのですが、最終的にはBlenderでオブジェクト自体のサイズを調整しました。Blenderの使い方にけっこう戸惑いましたが、こっちの方が後々楽ですもんね。
![blender.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532390/0e8888cc-0a30-a460-690c-a184e43eaca1.gif)

#感想
この他にも担任の先生を最強モンスターとして登場させたりして、クラスのメンバーからはかなり好評をいただきました。

webGLに初めて触れたのが2週間ほど前でしたが、A-Frame、AR.jsはHTMLとJavaScriptの基礎知識があれば追加の学習はごく僅かで済むので、非常に効率的に開発が進められると思います。
Webの世界では当たり前なのかもしれませんが、こんなものが無料で使えるなんて凄すぎますね。

個人的には2018年のスピルバーグ監督映画の「Ready Player One」のような世界を実現できたら本当に面白そうだなと思っているので、引き続きXR系の技術で色々作っていきたいです。