ひとりゲーム開発のがんばりのまとめ 2020年5月

ひとりでつくってるゲームがこんな感じになってきました。

最初のコミットから数えると、見せられる情報量の割にけっこうな時間が経ってしまいました。
ゲームをつくりたいというよりも、画面に出ると「なんか良いぜ」 と思える部品をくっつけたりこねたりを延々とやってるような感じなためです。つくりかけのゲームというよりは、五歳児が砂場でのびのび遊んで家に帰った後の、夕方の暗がりに残された散らかった砂場を目の前にしているような気分です。

僕はプログラマを生業にしているので、絵を描いたり3Dモデルをつくったりするよりも、プログラマブルな手法で画面に絵を出すほうが楽なはずだ。と最近までは考えていました。
ところが、やってみると、何かを完成させるためには どんな手を使うかっていうのは実はかなりどうでも良いことだとわかりました。視力2.0 でゴールをはっきりと見据え、そこに近付くためにあらゆる 手を尽くすことが本当の効率であって、手法を先に決めたりゴールがぼんやりしていることは効率の逆を行く殺人的な時間の浪費につながってしまったみたいです。

そんなこんなで、暗闇の中を徘徊しているんですが、なんとなく光ってる方向に手探りで向かっていった結果、最近はようやくゲームとしての基盤ができてきたので、前向きにできたことを振り返ってみようと思います。 将来の僕が何かの参考にしてくれたら幸いです。

つくってるもの

ファイナルファンタジータクティクスというゲームが好きで、「ああいうの」がつくりたいと思っていました。
「ああいうの」の説明はむずかしいですが、ゲームとしての性質や戦略性/競技性ではなくて、情緒の部分、掌サイズの小さな豆粒のようなキャラクターたちが、絶対に出ることも認識することもできない箱庭の中で、生き死にをやっている「あの感じ」です。

フィールドはチーズケーキを包丁でまっすぐ切ったみたいに端が途切れていて、画面は俯瞰した視点で将棋盤を見ているよう。しかしそこにはなぜか雨が降っている。草も生えている。廃墟には時間の流れがある。どんな気持ちでそこにいるのか、こちらの内面を投影する余白の残されたごくごく豆なキャクターたちが、そのマス目を生きている。それが僕にとっては、写実的な見た目の絵が涙を流して演技をしているよりも、よほど悲しいと思ったし、「良い」と思いました。

RPGは主に、武器をもって敵を殺すことを目的として与えられますが、僕は殺し合いじゃないものがつくりたいと思ってました。
ゲームの中で戦ったり殺し合ったりするのは楽しいんだけど、「モンスターが登場した」というだけで何故、彼を殺す理由になるのか。その説明がされない文脈に僕はいまいちノれないためです。

「敵と殺し合う」をゲームの目的として置くことはわかりやすいし、誰でも理解できます。その手を捨てるとすると、いきなりRPGとして成立させるのがむずかしくなってしまいます。最初からそういいうむつかしいことをやろうとするべきではなかったんですが、内容を考えれば考えるほどなぜかハードルが上がってしまいました。

最初に考えていたのは、「地獄に落ちたキャラクターたちが、自分の「罪」を他のマスのキャラに投擲してなすりつけることで天国へ上っていく」という内容でした。
罪には重さがあり、重いほど射程距離が短く、持っているとスコアが悪くなる、みたいな感じのルールを考えてました。ただ、地獄を舞台にすると、状況をわからせるために画面に出さないといけない情報量が多くなってしまうので、早々に没に。

現在は、上のツイートのように、原っぱで素っ裸の人間がいるだけで成立する内容になってます。

キャラクター

f:id:hadashia:20200527162236g:plain

f:id:hadashia:20200527162321g:plain

キャラクターは手で描いています。

動きは Live 2D でつけてみました。
2Dの絵を パーツ分けして動きをつけるツールはたくさんありますが、Live2D の場合、身体のパーツのつなぎめのない線画をなめらかに動かす能力が抜群です。
エディタやワークフローにかなり難があると思っているのですが、代替のツールをみつけられませんでした。

全コマを手で描いてパラパラアニメさせるのもやってみたいのですが、描く絵の枚数を抑えたくてあきらめることに。

手描きのパラパラ感を出したくて、Unity側で Live2Dのシェーダを改造して、線にノイズを入れています。

Live2D のシェーダにパスを追加して、影が地面に落ちるようにしています。
( この辺、Unityがどのパスを使って影を描いているかよくわからなくて結構苦労した覚えがあります……

影の塗りは、鉛筆スケッチ調にしてみました。 濃いパターン、薄いパターンの 素材をテクスチャとして複数用意しておいて、影の濃さを閾値にして混ぜる、みたいなことをやってみています。

地形

地形は3Dでつくることにしました。
3Dであれば描き直さずとも簡単に複数のアングルを見せられるし、楽なのでは。と考えたためです。

案の定、マップの形をつくること自体は、Unity の ProBuilder を使うとすぐにできたのですが、そこからはけっこう苦労しました。
きちんと見せたいものをつくるのは 結局は 手描きより簡単、ということはないからです。

どうにか手抜きをする方法を考えた結果、近所の森を撮影してテクスチャとして貼りつける方法を試してみました。

こういうのをテクスチャにして貼ってみると、それなりに土は土、芝生は芝生と 視認できるようにはかろうじてなりました。
ただ、省略の効いてない絵を貼ってるだけだと均質な見た目になり、逆に情報量がめちゃ少ない感じになってしまいます。

そこで、考えた結果、デジタルで絵を描き込むのではなく、水彩絵の具を使ってみることに。

これは、アクリル板に絵の具を塗り、こすり合わせて模様をつくった後、版画の要領で紙に写しったものです。

こんなかんじで、偶発性に頼った模様をつくると、以外と自然物の表面のようなテクスチャになります。
板に絵の具を塗るやりかたは、レオ・レオーニ展でたまたまみかけて真似しました。

これらのテクスチャを混ぜ混ぜすることで、原っぱや自然物の背景をつくろうと試みています。
絵の具のぐちゃぐちゃな模様はけっこう気に入っています。ただ、もうちょっと見せたいものをちゃんとコントロールするべきかな、という気はしています。

グリッド

マス目のあるゲームなので、地形には、指定した矩形の範囲を塗り潰す機能があります。

でこぼこした表面も色をつけるために、地形のシェーダに グリッドを塗る機能をつけました。
ただ、シェーダのみで色をつけようとすると分岐やループが入ってきてしまうので、別パスで色のついたテクスチャをつくって、それを地形に貼る、というやりかたにしてみてます。

「気持ち」キューブ

f:id:hadashia:20200529181904g:plain
なんでやねん

このゲームでは、キャラクタの「気持ち」や「思い出」をフィールド上のマスに置くことができます。
これは、そのときに画面上に出す、気持ち1マスぶんのオブジェクトです。

水の塊のようなもの中に、言葉が揺れてるみたいな見た目にしたくて色々やってみました。

キャラクタの「気持ち」が飛んでいくとき、非言語のエフェクトを見せるのではなくて、できるだけ 言葉を文字 としてそのまま画面に出すような表現にしたいと思ってました。
コンピュータ上になにか絵をだすとき、あらかじめつくった絵素材をだすより、入力によってバリエーションが無限になるようなものがやっぱりおもしろいとおもうし、「言葉」を投げつけていることが視覚的にもわかるようにしたかったのです。

よくある川や水面のシェーダを参考に、水っぽい見た目のシェーダをつくってみました。
「流れ」のマップをテクスチャで持っておいて、複数の動きでuvを動かしたり、法線に沿って向こう側の景色が歪んで映るような機能を入れています。 あと、法線に沿って 光が 玉虫色っぽくなる しゃぼん球風の表現も入ってます。

立方体の各面には、「気持ち」のテキストが一文字ずつ、モーフィングしつつ表示されます。

文字が絵として出て動くようすは、言葉に表情をつけてるみたいで好きです。
テキストを動かす表現はこの他にも色々と実験してました。


全体的に、視認しずらい、という課題はあります……

「気持ち」UI

キャラクタが持っている「気持ち」をリスト表示する際に、キャラクタの脳の中身がぐにょっと出てくる、みたいな感じをつくりたくて自作を試みました。
やってみたものの、UI がこんなにぐにゃぐにゃしていると認知が難しいのでこれは没にするかもしれないです。

上記のデモでは、実行時に UIのメッシュをプログラマブルに生成して、キャラクタを中心にして放射状に広がる形状をつくっています。

また、UIに別パスを追加して、ポストエフェクト的な演出をいくつかくっつけています。

全体の輪郭線を描いているのも、後からエッジ検出をして描き足しています。
ぐにょぐにょしている動きは、あらかじめ速度ベクトルを頂点に描き込んでいて、最終的なパスで uv を歪ませてサンプルリングしてます。ソースコード内では「おばけブラー」と呼んでいます。

これの前は、もっともっちりさせるようなものも考えていました。

ふきだし

ふきだしもメッシュを実行時に生成して、角丸の矩形を生成しています。
しっぽも 実行時に ベジェ曲線を計算してメッシュをつくっています。

ふきだしには輪郭線がついていてほしいという強い希望があったので、ここれも別の描画パスでエッジ検出してますね。

ふきだしの本体としっぽのつなぎめをなめらかにするためにメタボール的な手法でぼかしたりもしてます。
尖っているところがない形状が好きなので、 メタボールは汎用性が高いです。

被写界深度

f:id:hadashia:20200529212332g:plain

被写界深度を自分で実装してました。
ピントが合う範囲からあふれたオブジェクトはピントがぼけて見えます。

Unity の Post Processing Stack や URP にも 被写界深度エフェクトはあるのですが、正射影カメラに対応されていなかったため、お手製のものになってます。

お手製のものをつくった結果、カメラの Far と Near に関係なく 恣意的に範囲を調整できたり、
ボケの形を自前で変えられたりできるようになったので気に入ってます。

データの扱いとエディタ

現状のシステムでは、ゲームのデータやイベントは全て neuecc/MessagePack-CSharpシリアライズできるようにしています。

Unity がなくてもデータのシリアライズ/デシリアライズ が行えると、独自ツールを書いたり他ツールとの連携ができて便利です。 将来的にサーバもつくったりしたいのでそれも想定しています。

また、シーンをまるごとシリアライズしなくても、ドメインロジックの最小限のデータがあれば 完全に ゲームの状態を再現できるため、データ層が軽量になります。

ドメインロジックとプレゼンテーションとの分離もうまくいきます。

キャラクタのパラメータ等のマスタデータ は、 Airtable で 作成/編集しています。
型の同じデータが延々と並ぶやつは、テーブル形式で 一覧できるとやっぱ良いかなと思います。

Airtable は エクセルとか Google Spreadsheet に似たWebアプリですが、各列に明示的な「型」の概念があり、Enum や 他テーブルのレコードへの参照などもつくることができます。
生データはエクセルよりもRDBに近いです。クラウド上にあってREST API でアクセスできるエディタつきのRDBみたいなもんですね。

Unityで使うときは、 Cysharp/MasterMemory 形式のワンバイナリでエクスポートできるようにして読み込んでます。

各フィールドの設定は、こんなかんじで Unity上のカスタムエディタで色々と編集できるようにしています。 これは シーン を編集して保存しているのではなくて、アプリケーション独自形式の、見た目に依存しないデータを 出力します。

キャラクタたちの演技は Unity のタイムラインを使っています。 Unityのタイムラインは、原則として「シーン上にあるものを操作する」という仕組みにな過ぎず、実行時に動的に生成されるオブジェクトとうまく連携することができません。
そのため、エディタと再生の仕組だけ利用し、トラックやクリップは全て自作しました。

全体として、ゲーム内のドメインロジックは、すべて シリアライズできるコマンドで表現できる設計になっています。
タイムラインは、ただ時系列にコマンドを飛ばすだけって感じです。

AI

NPCは自律的に行動する仕組みが必要ですが、この辺を参考に Utility ベースの 行動選択AI を実装しています。 http://www.gameaipro.com/GameAIPro/GameAIPro_Chapter09_An_Introduction_to_Utility_Theory.pdf

そんなこんなで

仕組みはできたので、後はリリースに向けて、コンテンツをつくったり、妙にプログラマブルな手法にこだわらないで、もうちょっと普通に絵素材を拡充したりしていきたいです。
先は長そう。