UnityエンジニアがTypeScript+WebGLで3Dダンジョンゲーム作ってみた結果

![スクリーンショット 2018-04-22 14.11.01.png](https://qiita-image-store.s3.amazonaws.com/0/252430/6cf699ff-309c-b4e9-a099-cccf90ecfe79.png)

## TL; DR

- WebGLで3Dダンジョンを実装してみました。
    - https://nonchang-net.github.io/20180304_webglTest/
- ソースもアップしときました。
    - https://github.com/nonchang-net/20180304_webglTest

## この記事の対象読者

- Three.jsとTypeScriptでゲーム作りかけ挫折の事例ポエムを斜め読みしたい人
- UnityとWebGL比較ポエムを斜め読みしたい人
- 
僕の音楽を聴きたい人

    - 聞きたいだけなら[こちら](https://github.com/nonchang-net/20180304_webglTest/tree/master/assets/sounds/bgm)で直で落とせます

## これは何

**ゲームにはなってませんのでご容赦ください。**

- 主にTypeScript+Three.jsによる3Dダンジョン実装です。
    - 後は右上のミニマップが2D Canvas。UI類はHTML+CSSです。
- 昔ながらの方眼紙マップな3Dダンジョンです。
- バトルはできません。敵は出るけどパラメータもルールも設定してないです。
    - 「戦う」押すと倒せます。
- レイアウトはスマホ専用で、iPhoneSEでしか動作確認してません。
    - Chrome Dev Toolを見る限り、最近のスマホなら大丈夫そう？
    - 「ホーム画面に追加」して全画面表示しないと縦の長さが足りず、敵表示が残念なことになります。
    - PCやiPadではレイアウトが残念なことになります。横長画面ではレスポンシブにしたいのだけど、どうしたもんかと悩んで放置中。
- たまにクリスタルっぽいオブジェが出ますが、取れません。Blenderで作成したモデルの読み込みテストです。


## なぜ作ったのか

- Three.jsを触っておきたかった
- Unityと比べてWebGLの開発周りがどんな具合なのか把握しておきたかった
- TypeScript+htmlでゲームやUI作るとどんな感じか検討しておきたかった


## 中身をざっくり説明

### Three.jsによるダンジョンの表現

- [knockknock.js様](http://www.knockknock.jp/archives/394)のenchant.js+Three.js実装サンプルをもとに、スマホで操作できるように整形したものです。

- 迷路は棒倒し法による自動生成を行なって、ブロックと天井・床を貼ってます。
    - 昔からある有名なアルゴリズムです。[Algoful様の記事](http://algoful.com/Archive/Algorithm/MazeBar)がわかりやすいです。動作サンプルが素敵。
- Three.js自体の解説は省きますが、特に難しいこともなく実装できました。Unity触ったことがあれば、[公式document](https://threejs.org/docs/index.html#manual/introduction/Creating-a-scene)と[example](https://threejs.org/examples/)眺めていけばやりたい表現の実現方法はすぐ見つかるかと。また、[its media様のThree.js入門](https://ics.media/tutorial-three/index.html)が非常にわかりやすいです。

### TypeScriptで型安全なイベント実装

ゲーム作成となるとイベントドリブンを徹底したいところですが、DOMのカスタムイベントって若干冗長。今回はせっかくのTypeScriptなので、subscribe/broadcastできるだけの、型安全に引数を定義できる、簡単なイベントシステムを作成して随所で利用しています。

https://github.com/nonchang-net/20180304_webglTest/blob/master/src/Event/Event.ts

```TypeScript
//イベント定義（実際はevents.Common）
const PlayerStepToForward = new Event()
//購読の例
events.Common.PlayerStepToForward.subscribe(this.constructor.name, () => {
  events.UI.AddMessage.broadcast("あなたたちは前に進んだ。")
})
//ブロードキャストの例
events.Common.PlayerStepToForwardSuccess.broadcast()
```

`this.constructor.name`渡さないといけないのが微妙ですね……。（購読解除のため、誰が購読してるのか管理するために渡してます。現時点でunsubscribeしてるところはないんですが、ゲームのリセット時には必要になるしなぁ）

### Tween実装

ゲームに限らずUI表現でも必須なやつですね。
TypeScriptで手軽なTweenライブラリが見つからなかったので、jquery.easingやsimple tweenを参考に実装してみました。

https://github.com/nonchang-net/20180304_webglTest/blob/master/src/Common/Tween.ts

Promiseで包んでawait呼び出しできるようにすればより便利に使えそうですね。（やんなきゃ。忘れてた）

### 設計まずったところ

- DOM生成やCSS適用はコードでやるもんじゃないなと思いました。
    - TypeScriptのおかげで型の混乱はなかったけど、冗長すぎる感。
    - 仕切り直す際には、React(.jsx)やvueの採用などを検討した方が良さそうです。
- 今回は練習がてらjQuery撤廃したけど、ぶっちゃけReactとか採用しないんならjQueryは使った方が楽だろうなと思いました。結局StylerなるjQuery代用クラスを自作して、二度手間感を味わうなど。

## Unityとの比較ポエムとか

- TypeScript（+Webpack）の開発環境はなかなか快適でした。VSCodeでサクサク開発できますね。トランスパイルもこの程度の規模のプロジェクトならMac mini 2012モデルでも一瞬で処理してくれます。もう少し大規模なプロジェクトでどうなるのか見てみたいですね。
    - webをターゲットにしてよくて、Unity使うほどじゃない規模のゲームでしたら、TypeScriptはより良い選択肢になり得そうです。まあ、ターゲットがスマホのストアアプリであれば、webviewでできることが限られるのでUnity使うのが妥当かと思いますが。

- 3DツールとしてのUnityにはまだかなわない。
    - Chrome Dev Toolsでプロファイラなども充実してますが、実行時にEditorビューからGameObjectの状況確認できるUnityのようなことはできませんね。ゲーム制作環境としてのUnityはやはりまとまってるなと思います。あとパーティクルライブラリ欲しい。パーティクルはできれば自前実装はしたくない＞＜;
    - Unityだと圧縮テクスチャとか変換してくれるのが楽ですね。あとアトラス化とか。
        - この辺りはWebGLの需要次第で、webpackプラグインやgulp taskなどが整備されていく可能性もありそうですね。
    - 現実問題として、WebGLではデザイナーさんとの協業が難しいなと思います。Unityならデザイナーさんに触っていただくことも現実的だと思いますが。
        - UIデザインについてはReactやVueをうまく導入できれば、デザイナーさんに.jsx/.vueを編集いただくような切り分けは可能かも。

TypeScript+WebGLでのゲーム制作環境は、思いのほかいい環境でした。しかしゲーム制作に特化したUnityを置き換えるほどの環境は揃えられないという認識です。
この辺りは、Unity自身がWebAssembly+WebGLに取り組んでいるので、そちらに期待した方が早いかも。

実案件ではWebGLとかPWAの依頼が来るのはまだ先かなと思いますが、その時にはUnityでWebゲームを書き出す案件が定着しているかもしれませんね。

## C# vs TypeScript 設計面での比較ポエム

- どっちもよく考えられた、いい言語です。人材レベルが一緒なら開発効率も一緒じゃないですかね。多分。
- ハードルはTypeScriptの方が高いかも？ TypeScriptはJavaScriptの
変態性を受け継いだ
上位互換なだけに自由度が高いので、コーディングルールなどをしっかり整備できる方がチームにいないと混乱を生みそうです。**TypeScriptのEffective本が欲しい**。。
- C#(net4.6)とTypeScriptでasync/awaitに慣れてくると、もう、**async/await相当の仕組みがない言語ではゲーム書きたくないなぁ**と感じました。。ポップアップなんかも閉じるのを待つことで同期的にかけたりと、むしろUIの設計面で楽できますね。
    - Unityから.net 4.6のexperimentalが外れる日が待ち遠しいです。
- TypeScriptの型システムは後付けゆえの利点を徹底活用してて不思議な感じがしました。C#より柔軟で強力な印象。なんだよ**`number | string型`**って。文字列まで型にできるし。`createElement("div")`の返り値を`HTMLDivElement`に絞れる理由がわからず右往左往しました。この型システムにはもっと知見を深めたいです。
- `strictNullChecks`でnull安全に書けるのはいいですねぇ……。潜在的な不安に怯えずにコードを書ける乗って大事です。
    - C#にもnull安全に書く方法があると良いのですが。現状では無理みたいですね。
    - 参考: [null安全でない言語は、もはやレガシー言語だ - C#](https://qiita.com/koher/items/e4835bd429b88809ab33#c)
        - Static null checking in C#というプロポーサルがあるんですね。将来に期待。

個人的好みはTypeScriptですが、普及度や安心感ではC#が鉄板かなと思いました。個人的にはnull安全性については残念ですが、同じmicrosoftの言語ですので今後に期待。

## 本作品の今後

うーん。一旦はお蔵入りかなぁ。

ゲームにしていく上で必要な実装としては、「バトルシステム実装」「インベントリ（アイテム・魔法など）実装」「マスターデータ整備」「ゲームバランス調整」……といったあたりでしょうか。うーん、大変なところばっかり残ってますね。

システム面でもリソースダウンロード管理の実装が必要です。また、オフライン動作のためのservice-workerの実装ができてないので調べなきゃな感じです。やること沢山あります。

とはいえ、平日日中はフルタイムで現場出てるので、このままでは完成の見通しが立たない感じ。
で、見切りつけるためにこの記事を書いて見た感じです。

当初にイメージした操作性をそれなりに実装できた感じはありますので、そこそこ満足してます。
でも設計も雑ですし、我ながら笑えるコードがたくさんあります（マサカリ歓迎です。……お手柔らかにお願いします）。

多分、ちゃんとしたゲームにしていくにはプランナーさんやゲームデザイナーさんとガチ協議する必要があるかなぁ。過去のwizの名作や世界樹シリーズなどに詳しい人にプラン練ってもらわないといけない予感。

また、もし予算をもらって売り物を開発する目処が立ったとしても、TypeScript+WebGLでの実装はやめて、Unityで作り直す判断をすると思います。

webアプリにしてapp store/Google Playの審査やレビュー対策から解放されるのは夢がありますが、IAPの代わりを探さなきゃいけないし、PWAでpush通知とか検証したこともないので工数感が見えない感じです。あとアセットバンドル相当のリソース制御やんなきゃか。。

app storeから離れるってことは、宣伝方法も一から考えないといけないかなと。悩ましい。
エロゲ作るか？



誰かこれフォークして面白いハクスラ作って公開してください。多少なら課金するんで



## 謝辞

- 顔グラフィックスは <a href="http://roughsketch.en-grey.com/%E7%B4%A0%E6%9D%90%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9" target="_blank">三日月アルペジオ</a>様の無料素材を利用しています。可愛いです。つい目パチ実装してしまったなど。
- モンスターグラフィックスは <a href="http://raineru03.web.fc2.com/" target="_blank">HI-TIME様</a>様の無料素材を利用しています。かっこいいです。sinobi.pngに首はね実装して絶望したかった。