モナドのまほう　第13話『ネオアームストロングCannon.js砲じゃねえか完成度高けーなオイ』

[第一話](http://qiita.com/hiruberuto/items/5321d8cebce7b87851f6) / [前回](http://qiita.com/hiruberuto/items/cdf2a7bb66fdcbf1a78c)

ゲームを作る日記です。古代の宗教家の誕生日に世間は沸いているようですが、私は無宗教なので特に感慨はないです。

# PureScript By Exampleスペイン語版


<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">A big thanks to Jorge Acereda for translating the PureScript book into Spanish!<a href="https://t.co/eq6Lg6MSOE">https://t.co/eq6Lg6MSOE</a></p>&mdash; Phil Freeman (@paf31) <a href="https://twitter.com/paf31/status/811702284732100608">2016年12月21日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

我々PureScripterの聖典たる"PureScript By Example"に、スペイン語版が登場したようです。スペイン語は四億人以上の話者がいて、割合では[インターネット全体の8%](https://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E8%A8%80%E8%AA%9E%E3%81%AE%E4%BD%BF%E7%94%A8)。英語、中国語に次いで第3位だそうです。これを機にもっとユーザが増えるといいですね。




# Cannon.jsを導入しました


衝突判定にCannon.jsを導入しました。今まではテキトーに実装したガバガバ判定だったので、簡単に地面にめり込んだりジャンプもせずに段差にぴょんと飛び乗ったりしていましたが、これでキャラクターが地形にめり込んだりしなくなりました。地形にめり込むと上方に弾き飛ばすという実装になっていたので、以前は地下に潜ると壁にぶつかっただけで地上にはじき出されたりしていたんですが、これでちゃんと地底探検ができるようになりました。

一方で高いところから飛び降りて着地すると反発係数がゼロなのにぴょんと跳ね返ったりとか、自分がいる場所にブロックを置くとキャラクターが弾き飛ばされて上空高く吹っ飛んだり、Havok神ならぬCannon神の威光を感じさせます。見た目に変化はないのでスクリーンショットはありません。

Cannon.jsのサンプルにちょうど[ボクセル形状のフィールドを歩きまわるサンプル](http://schteppe.github.io/cannon.js/examples/threejs_voxel_fps.html)があったので、これをそっくり借りて改造して使っています。1チャンクが16*16*16ですから、それぞれのボクセルについて一対一で衝突形状を生成してしまうと、たった1チャンクで最大で4096個もの立方体形状を使う可能性があります。平均的には半分の2000程度でしょうか。これはあまりに多すぎますが、このサンプルでは近傍のボクセル同士を連結して形状を減らす仕組みが使われていて、1チャンクあたり30～50個程度と衝突形状の数を大きく削減できます。それでも3*3*3個のチャンクについて物理シミュレーションを行うので、500個程度の衝突形状が衝突判定に使われ、かなり重いというのは確かです。もう少しチューニングを加えないと快適にプレイできないと思います。cannon本体側でボトルネックになっていそうな部分も見かけたので、もしかしたらcannon.js本体に手を入れてチューニングする必要があるかもしれません。それでも効率面は今のところなんとかなりそうな気がします。ゲーム開発は本当にチューニングがつらいです。

Cannon.jsの使いかたは難しくありません。まずは`World`オブジェクトと`Body`オブジェクトを作り、`Body`を`World`に追加します。`mass`プロパティは文字通り質量ですが、デフォルト値の`0`にすると一切移動しない静的な物体になり、ゼロより大きい値にすると重力に引かれてたりして力を受けると動くようになります。適当にサンプルコードっぽいもので示せばこんなかんじです。

```js
// ワールドを作る
var world = new CANNON.World();

// 物体を作る
var shape = new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5));
var body = new CANNON.Body({ mass: 1.0 });
body.addShape(shape);

// ワールドに追加
world.addBody(body);
```

ワールドが作成できたら、キー入力などに応じて物体に位置や速度、力などをプロパティで設定し、それから`World.step`を呼び出すと、シミュレーションが指定した時間のぶんだけ進みます。それが終わると物体の位置や速度などが更新されているので、これを読み取って描画に反映させます。

```js
// プレイヤーキャラクターの状態
var playerPosition, playerVelocity;

// ゲームループ的なものがあるとして
gameloop(function(){

    // キー入力などに合わせてプレイヤーの次の状態を決める
    if(isKeyPressed("w")){
        playerVelocity.z = 1.0;   // 進む
    }else{
        playerVelocity.z = 0.0;   // 止まる
    }

    // 現在の状態をbodyに書き込む
    body.position = playerPosition;
    body.velocity = playerVelocity;

    // 時間を進める
    world.step(1 / 60);

    // 状態が変わっているので取り出す
    playerPosition = body.position;
    playerVelocity = body.velocity;

    // キャラクターのメッシュをその位置に移動する
    playerMesh.position = playerPosition;
})
```

基本的にはこれだけです。さほど難しくはないので、ゲームを作りたい人は使ってみるといいと思います。僅かなコーディングで複雑な動きが生まれるので、ゲームのプレイにも一気に幅が生まれます。




# オプションを直しました

今までオプション設定のボリュームが壊れていたんですが直しました。BGMを切り替えた時に、自然にフェードアウトしてから切り替わるようにもなっています。再生中のサウンドをいきなり切るとプチッというノイズになるので、サウンドを切るときは必ずフェードアウトさせましょう。

影の設定とかも再読み込みしないと反映されなかったのですが、設定を変えるとすぐに反映されるように直しました。シャドウはほんとに重いんですが、見た目だけでなくプレイアビリティに影響してくるので省略するわけにいきません。ゲームの技術レポートとかに載っていそうな比較画像：

シャドウと頂点カラーなし
![ss1.png](https://qiita-image-store.s3.amazonaws.com/0/64695/f9186021-7754-e419-6cf8-543dc4e0075b.png)

頂点カラーあり
![ss2.png](https://qiita-image-store.s3.amazonaws.com/0/64695/6211b08c-87be-7453-2d8a-2336bc38122d.png)

両方あり
![ss3.png](https://qiita-image-store.s3.amazonaws.com/0/64695/cef77182-7dcb-df04-1b93-abf8aa804619.png)

頂点カラーなしだと平面が同じ色でベターッとなってしまい、凹凸がよくわからなくなってしまいます（これはテクスチャをちゃんと描いていないせいでもありますが）。頂点カラーで凹凸を強調すると形状がだいぶわかりやすくなりますし、シャドウはキャラクターの足元の位置を示すという役割もあります。ジャンプした時の着地点の目安なんかにもなるので必要です。


# ツクールMV下調べメモ

RPGアツマールでの公開を検討するためのメモ：

* [RPGツクールMVのプラグイン開発環境の作り方](http://qiita.com/sifue/items/517a443e6a05a1737b3d)
* [RPGツクールMVでアプリリリースを目指す開発室](http://fanblogs.jp/tabirpglab/archive/130/0)
* [RMMV Script Calls](https://docs.google.com/spreadsheets/d/1-Oa0cRGpjC8L5JO8vdMwOaYMKO75dtfKDOetnvh7OHs/edit#gid=0) 

たとえば、メッセージを表示するには`$gameMessage.add`でいいみたいです。公式のAPIドキュメントが見当たらないのですが、どうも本体にも付属していないらしく、有志がコードを直接読んで解読しているようです。公式ドキュメントくださいよ！




# 純粋関数型プログラミング言語の効率について

PureScriptはすべてのデータ型が不変な純粋関数型プログラミング言語であり、オブジェクトの状態を変更したいときは、オブジェクトを直接変更するのではなく新しい状態のオブジェクトを新たに作成します。これを聞くとかなり効率面が心配になる人も多いと思います。

でも、今回PureScriptの効率できつかったのは、データ型の不変性が原因ではなく、PureScriptの関数がすべてカリー化されているせいで大量の関数オブジェクトが作成されてガーベージコレクタが動いてカクつく、というものでした。具体的には、地形を生成する関数、地形のボクセルデータから３Dメッシュの形状を計算する関数のふたつは、個々のボクセルにアクセスするので大量のループ処理が入るのですが、ここで大量のクロージャが作成されてどうにもならず、おとなしくJavaScriptで書きなおしました。この大量の`Eff`のクロージャは、もしコンパイラがインライン化をするようになれば将来的には解消されるかもしれません。

現状の実装のCPUプロファイルをとって見ると、一番支配的なのが`(program)`で、これのほとんどはwebglによるレンダリングでしょう。それから`ArrayCollesionMatrix.reset`などのcannon.jsの関数や、`MaterialDefines.isEqual`のようなbabylonjsの関数が並びます。

![reset.png](https://qiita-image-store.s3.amazonaws.com/0/64695/f92a25ab-9ef9-d439-f338-292099ccba87.png)

ある程度の最適化を加えたら、どんなゲームであろうと効率はグラフィックスと物理シミュレーションにほとんど支配されてしまい、プログラミング言語が純粋であろうがなかろうがあまり関係なくなってしまいます。もちろん一部では純粋関数型言語の特性によってボトルネックが生じた部分の最適化は必要なものの、今回の例でいえば２つの独立した純粋な関数をJavaScriptに書きなおしただけで、PureScriptが原因のボトルネックは解消されました。純粋関数型プログラミング言語ではデータ型が不変なので効率が心配というのはわかるんですが、実際のところあまり心配はいらないでしょう。ちゃんとプロファイルを取ってボトルネックをひとつひとつ潰していくという、どんなプログラミング言語にでもいえることをちゃんと丁寧に実施することが大切なんだと思います。







<!--

ボツ原稿メモ：

# 関数

もちろん今回ゲームを作り始めた最大の理由は単に『ゲームを作りたかった』なんですが、おまけの目的として『**純粋関数型プログラミング言語が実用的であることを、まったく前知識のない人にもわかる形で実例を示す**』というものもあったりします。『百聞は一見にしかず』というように、人間だれでも理屈で説明されても納得などしないものですが、不思議なことに目で見せられるとコロッと信じてしまうものです。

べつにマサカリを投げる意図はないのですが、関数型プログラミング言語がどのようなイメージを持たれているかがわかりやすい記事があったのかを紹介しておきます。なぜその結論に至ったのかという理由がちゃんと説明されているという点でも参考になります。

* http://qiita.com/GeneralD/items/8e865c21aace0446e688

> しかし大抵のゲームで扱われるゲームオブジェクトの座標は変わりうる数値で持っておく必要があると思う。
ゲームの世界が100*100程度のマス目でできていれば大丈夫かもしれないが、全部が全部そうはいかない。座標は少数が使われる場合も多く、イミュータブルにすべての座標を作成しておくとすればメモリーエラーが起こり得るだろうし効率的とは言えない。

私がいま作っているゲームは26万\*6万\*26万のマス目で出来ています。このマス目それぞれについて座標を生成すると、三次元座標を64ビット浮動小数点数３つで表すとして、260000\*60000\*260000\*3\*8バイトで100ペタバイトくらいになるでしょうか。私の型落ちパソコンのメモリはそんなに大きくありませんが、不思議なことにメモリエラーは起きていません。また、キャラクターの座標はもちろん整数でない値も取りますが、エラーにはなりません。不思議ですね。

> 一方、関数型ではある機能や関数において任意の引数に対して毎度同じ結果を返すことが求められる。（関数などの挙動や結果が状態などの影響を受けない）
それをこの件に関しても適応するならば、ゲームが開始してから任意のオブジェクトに加わった一連の力や要因を（毎フレーム）初期位置に置かれたオブジェクトに対し作用させて現在位置を（毎フレーム）一から計算させるということだ。

そうなると純粋関数型プログラミング言語で書かれている私のゲームはプレイ時間が伸びるに連れてあっという間に重くなっていくはずですが、実際には数時間放置しても大丈夫です。不思議不思議。

『難しいこと細かいこと抜きで頼むわ』といってるくらいで、たぶん長い話は聞きたくないんだと思いますし、そういう人はとても多いと思います。だから『**純粋関数型プログラミング言語ではゲームは作れないのではないか。でも難しい理屈や長い話は聞きたくない**』という人に今回私が用意した答えは、『**でもこのゲームは純粋関数型プログラミング言語で書かれてるよ？**』です。純粋関数型言語が非効率で実用的でないと考える人たちがこの矛盾をどう受け止めるかは私にはわかりませんが、これなら難しい理屈もないのでわかりやすいかと思います。

# プログラミング言語とイメージ戦略

> あと、自分の勝手な感想だが、関数型プログラミングの界隈にはあまり親切な人が少なく、だいたい初学者に対しては冷たい印象を受ける。

* http://anopara.net/2015/10/21/%E9%96%A2%E6%95%B0%E5%9E%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E5%85%A5%E9%96%801-%E3%81%BE%E3%81%88%E3%81%8C%E3%81%8D/

-->



# 次のお話

* [第14話](http://qiita.com/hiruberuto/items/910354220d14d597b876)