はじめに
今回紹介する書籍は平山 尚氏著のゲームプログラマになる前に覚えておきたい技術という本です。
↓↓↓秀和システムの商品ページ↓↓↓
ゲームプログラマになる前に覚えておきたい技術
こちらの本ではゼロからゲームを作っていく作業を通じて、深く丁寧にゲームプログラミングについて学ぶことができます。
正直私などが紹介するまでもない、普通に知名度がある良書ですね。
ではなぜ改めて紹介記事など書くのかというと、それは私の備忘録とするためです。
そして、理解をアウトプットすることでご意見をもらえたらと思っているからです。
また、個人製作者はUnityなどのエンジンの使い方、要はツールに偏った情報を収集しがちだと感じるので、本書のようなゲームプログラミングの教本の良さを発信したくなったためでもあります。
本書で使用する物
VisualStudio
C++
数学(高校一年生までの知識は必要、との記載)
目次
私のスキルについて
本を読んだ私のスキルについて軽く触れておきます。
この程度のやつが楽しく読めたなら自分も、という感じで指標にしてくださいね。
- C#とUnityを趣味で5~6年。
- デスクトップアプリ製作と競プロ(白色コーダー)をC#で少々。
- C++の経験はほぼなし。(前にDirectXの本を読んだ時にちょっと文法を学んだ)
- 半年くらいのSE経験。
- 破滅的に低い数学力。
- 基本情報所持。
- ビット演算やn進法に関する基礎知識。
以上のような感じですが、数学については本で説明してくれたのでなんとか読めました。
というより、数学に関する解説が異様に上手く、この本を読んで初めて三角関数などについて理解できました。
これは説明の巧みさもそうですが、ゲームプログラミングでの役割や必要性と絡めて教えてくれたから意欲を持って取り組めたことも大きいかと思います。
しかしそれでも発展的な内容(本の中で飛ばしてもいいと書かれているような部分)については理解できないこともありました。
いつかリベンジしたいですね。
本の長所・おすすめポイント
以下ではこの本のどのような点が優れているのか、何故お勧めするのか、ということをまとめてみました。
【最小のケースを拡張しながら説明してくれる】
これは簡単なやり方から始めて、徐々に手法を高度にしていくため理解しやすいということです。
この最小のケースについて、描画を例に説明します。
まず、描画の最小ケースでは画面に出す絵を一枚の画像として考えます。
その一枚の画像は色を塗られた点の集合体です。
要はドット絵に近いものですね。
ここで描画する画像は無数の点(色データ)の集まりでできています。
だから、点に一つずつ色を塗ることが描画処理になります。
最初はこの状態からスタートします。
しかし、ゲーム作りを進めるとこのやり方では実現できないことが出てきます。
あるいは著しく処理効率が悪いという問題が発生します。
その時初めて、もっといい方法を探してみようということになります。
これがこの本の基本的な流れです。
最初は非効率的ながら分かりやすくシンプルなやり方で、「描画」や「ファイルのロード」、「当たり判定」などについて説明してくれます。
そして必要になったタイミングで高度な手法についての解説が始まるため、それが何のために存在するのかを理解することができます。
これが個人的には一番有難かった点でした。
全ての解説がシンプルなやり方の延長線上にあるおかげで、「最初は理解できた、だから次も頑張って理解する」というように、挫折しにくい造りになっていたと思います。
【現実を教えてくれる】
見出しの通り、この本ではあまり理想を語らなかった印象です。
エンジニアはミスをするし、多くの処理に完璧なやり方はないし、製品のプログラムは妥協まみれである。
そうした前提でこの本は書かれていると感じました。
しかしそれは決して実装の放棄ではなく、現実に向き合った上で最高の成果を出すための『割り切り』に近いものです。
もちろん割り切るとは言ってもただ諦めるのではなく、目的のために取捨するという意味ではあります。
特にライティングや当たり判定、最適化の項での解説には考えさせられるものがありました。
現実の問題としてコンピューターの計算力には限りがあるため、捨てるべきを適切に捨てることも大切なのだと学べます。
そしてこうした記述が本書に単なる技術書以上の価値を持たせていると私は思いました。
技術について教えてくれる本は他にもあるかもしれませんが、現実と割り切りについて教えてくれる本は中々ないのではないでしょうか。
具体的に何を学んだか
ゲーム制作の基礎知識
ゲームプログラミングの本ですので、当然のようにこうした部分の解説はあります。
uv座標、テクスチャ、線形変換、座標系、フレーム、ゲーム数学、物理演算など、基本となる知識に関しては全て教えてくれます。
C++に習熟している人であれば、入門書としても利用できるのではないでしょうか。
また応用的な部分に踏み込んだ解説もあり(飛ばして良いとの添え書きがあることもしばしばですが)単なる基礎に留まらない内容を学ぶこともできます。
メモリ管理
私はC#で開発をするため、メモリ管理という意味ではC++を使う人より活かせそうな教訓は少なかったかもしれません。
実際、本書のあちこちで言及されていたポインタのDeleteと0代入による解放はC#とは縁遠い感があります。(C#でもnull代入して明示的に参照を破棄したりはしますが)
しかしメモリ管理とは必ずしも確保・解放の流れだけに限ったことではないようです。
本書を読んだことで、キャッシュメモリの活用という視点を得ることができました。
これがどういうことかというと、アクセス頻度が高いデータはキャッシュされるため読み込みの負荷を減らせるということです。
そしてデータが小さい方がキャッシュされやすいということも考慮する必要があります。
また、メモリに連続して配置されているデータにアクセスする場合もキャッシュは効果を発揮しやすくなります。
そしてこれらのことは配列の活用やクラス・構造体の定義など、プログラムの設計から考えるべき内容だと思われます。
私はリソースの確保や解放といった側面以外ではメモリの運用について考えたことがなかったため、本書で学ぶことができた教訓は得難いものでした。
ファイルのロード
これは正確にはファイルの圧縮やバンドル化(本書においてはファイルの結合と言われる)の意義、と言うべきかもしれません。
私はこれまでそれをあまり理解せずに使用していました。
せいぜいがファイルが小さくなるからゲームのロードが速くなる(原理は分かっていない、というより気にしてもいない)というくらいの認識でいました。
しかしこの本を読んだことで、その意味がもう少し明確なイメージとして理解できました。
つまり、機械にとってファイルの読み書きはボトルネックになるということです。
HDDを引き合いに出すとかなりわかりやすいでしょう。
色んなファイルを読み書きするために、ディスク上を機械が行ったり来たりするため、見るからに遅いということが分かります。
これを少しでも速くするためにファイルの圧縮や結合が行われていたということです。
以前から読み込みを早くするために圧縮する、ということはふんわり知っていたのですが、ファイルのロードがボトルネックであるという認識は欠けていたように思います。
ここが欠けていると個人的にはかなり違うと思います。
非同期・マルチスレッド処理の危険性
私は非同期・マルチスレッド処理はやればやるだけいいというように勘違いしていました。
たとえばn秒ごとに繰り返す処理、というようなものは全て非同期でやってもいいと思っていました。
メインループから「待ち」の処理を排除して負担を軽減できる(気がした)からです。
ですがそういうわけでもないようです。
その理由は以下の三つです。
- CPUやコンパイラは別スレッドからのアクセスを想定していない。
- 非同期の処理やスレッドが切り替わるタイミングは制御できない。
- スレッドを増やしすぎると管理できない。
一番上はCPUの動作やコンパイラのコード生成がマルチスレッド処理を想定していないため、最適化の結果意図した挙動とは異なる結果になるということです。
二つ目は複数のスレッドでの処理がいつ切り替わるか分からないため、意図した順番で処理が行われるとは限らないということです。
最後はスレッドを増やしすぎるとプログラミングコストが跳ね上がり、収拾がつかなくなるということです。
思えばUnityのAPIをメインスレッドでしか呼べないのは、最後の問題をケアした結果なのかもしれないですね。
ともかく、こうした不安要素があるため、非同期処理・マルチスレッド処理を濫用すべきではないと思われます。
この件に関しては近いうちに検証記事を出して、運用法を探っていけたらと思います。
最高の最適化 = それをしないこと
見出しの通りです。
どんな高度な最適化よりも、その処理自体をしない・省く、ということがずっと大事で効果的だということです。
文中で語られていた例によれば、これは無駄なオブジェクトを消す(あるいはモデルの頂点数を減らすなど)ということでした。
そうすればその分描画の負荷が減りますし、衝突判定や物理演算も不要になりますから当然軽くなるということです。
身もふたもないように感じる人もいるかもしれませんが、描画や当たり判定、ライティングの章を見るとその正しさを認識できるでしょう。
なにしろ、当たり判定にせよ物理演算にせよ描画にせよライティングにせよ、実際に何をやっているのかを見るとかなりの脳筋実装だからです。
莫大な計算量を必要とする作業を必死に効率化して、嘘を混ぜたりもして、だましだましやっているに過ぎないというような印象を強く受けました。
だから最高の最適化は「それをしないこと」になるというのはかなり説得力があります。
また、少し話は逸れるのですが、UnityにCorgiEngineというアセットがあるのはご存じでしょうか?
完全に余談なので読み飛ばしても大丈夫です。
こちらはUnity上で動作するゲーム制作ツールで、便利なAPIがたくさん積んであるアセットです。
Engineというように、これ自体ゲームエンジンに近いところがあるかもしれません。
そしてCorgiEngineではUnityの物理処理を無効化して、レイキャストとトリガーをベースにした独自の物理処理を実装しています。
かつての私はこれが不思議で仕方がなかったのですが、この本を読んだ今となっては納得がいきます。
要は物理演算が重すぎるのです。
だからレイキャストで衝突を検知し、足りない部分をトリガーで補うという実装にしてあるのでしょう。
そしてこれは恐らく大変合理的です。
処理の内容からして、Unityにおける接触判定の負荷の大きさは コライダー>トリガー>レイキャスト という順になるでしょう。
いつかちゃんと検証したいですが、そうであればこのコライダーと物理演算を使わないという「割り切り」はかなりの効果があるはずです。
私もこうした「割り切り」をコードに組み込めるように、柔軟な思考を持ってゲーム制作を続けたいと思いました。(小学生並みの感想で申し訳ございません)
終わりに
読み終えてみて、改めて振り返ると私はこの本の内容を完全には理解できなかったと思います。
先にお話したように、発展的な内容の数学は理解せずに雰囲気で読みました。
また、C++の分からない用語に関してはググったりしつつも、実際に手は動かさずに文中のコードを読むだけで済ませました。
正直、あまり良い学びの姿勢ではなかったと思います。
多くの教訓を得たとも思いますが、それでも完全に身にできたとは思えないです。
競プロの勉強をしたいとか、自作ゲームの作業を進めたいとか、検証記事を書きたいとか、やりたいことが多くて書いたことがないC++の実装をやる気になれなかったのが理由です。(言い訳ですね)
ただ私はこの本を一度読んで終わりにしようとも思っていないです。
この本は繰り返し読み返せば、その度に学びがあるような本だと思っているからです。
古い本ではありますが、だからこそゲームエンジンの上では身につかない知識が詰まっていると思います。
ページ数も多くただ読むだけでも苦労はするかもしれませんが、ぜひ一度手に取ってみてほしい書籍です。
以上で読書感想文を終わります。
ご意見やご指摘、あるいは『こんな本があるよ』とか『私も読んだよ』的なコメントなどあれば是非書き込んでください。