🧹

Unity1週間ゲームジャムふり返り

に公開

概要

Unity1週間ゲームジャムとは、Unityで1週間でゲームを作り、unityroomに投稿するイベントです。

今回のテーマは「あい」でした。

作ったもの

ロボット掃除機になって部屋を掃除するゲームを作成しました。
https://unityroom.com/games/eyeofaicleaner

制作日程

月曜にアイデア出しをし、技術的に不安な部分があったので、検証をしていました。
大体実現目処が立ったので、火曜あたりから制作を進めました。
基本的に月〜土は20~25時くらいの作業時間でした。
日曜は提出期限である20時ギリギリまで作業していました。

工夫した点

軌跡の記録及びカバー率の計算

ロボット掃除機が通過(掃除)した跡を表示したいなと思っていました。
「掃除した」と思ってもらえるような表現はいくつかあると思います。

  • スプラトゥーンみたいに床を塗る
  • マイクラみたいに床をブロックに分け、通過したブロックの色を変える
  • 床にゴミを配置し、通過したら消す

ですが、やはりどうしても塗りつぶしがしたかったので、実現方法を探ることにしました。
絵を描く仕組みを作り、インクを自機から出すことで、結果的に通った場所を記録できるのではと考えました。
また、塗る前と塗った後のテクスチャを比較し、色のピクセルを数えることで、カバー率の計算もできました。

基本的にChatGPTが提示した方法で進め、都度修正を重ねることで、なんとかそれっぽい実装にできました。
最初に技術検証を厚めに行なっていたおかげで、そこまで不安なく制作を進められました。
余談ですが、最初はテストのためリアルタイムでカバー率を計算していましたが、全ピクセルを走査する必要があるので、かなり処理が重かったです。
スプラトゥーンは計算時はダウンサンプリングしたテクスチャを使用しているとか…。

壁の記録

ロボット掃除機は部屋のマッピング(学習)をしているものが多いと思います。
その学習とは、おそらく間取り(壁)の把握かなと思ったので、壁を検知したらそれをミニマップに記録したいなと思いました。
壁の検知も色々方法はあると思いますが、今回は自機から壁にレイを飛ばし、当たった地点から地面に向かってもう一度レイを飛ばし、当たった地点を塗ることにしました。

if (Physics.Raycast(transform.position, transform.forward, out var sightHit, RayLength))
{
    if (Physics.Raycast(sightHit.point, -transform.up, out var floorHit))
    {
        var uv = floorHit.textureCoord;
        PaintMaterial.SetVector("_UV", new Vector4(uv.x, uv.y, 0, 0));

        Graphics.Blit(previousRenderTexture, tempRenderTexture, PaintMaterial);
        Graphics.Blit(tempRenderTexture, previousRenderTexture, PaintMaterial);
    }
}

軌跡の記録と同じ仕組みにしたことで、比較的実装しやすかったです。
レイを飛ばす関係で最初は建物のメッシュをそのまま判定にしようと思いましたが、思ったようなコリジョンになりませんでした。
そこで、見た目の綺麗さと軽量化のため、BoxColliderを手動で配置することにしました。

通れるエリア

最初は建物の床の部分を全て通ったら100%にしていました。
ですが、それだと自機が通れない場所が発生してしまい、100%が難しくなりました。
通れる箇所だけ塗れるようにするために、NavMeshを使用し、NavMeshのエリアだけ塗れるようにしました。
NavMeshのエリアだけを撮影しテクスチャにする仕組みを作成し、そのテクスチャをリザルトで表示したり、カバー率の判定に使用しています。

苦労した点

NavMeshは自動生成なので便利ですが、微調整が大変でした。
NotWalkableのオブジェクトを追加で配置すればある程度は調整できるものの、ペイントの要領でちょっと増減させたり形を整えたりしたかったです。
このあたりは大味の調整だったので、操作性が悪かったかと思います…。

WebGLでPostProcessにDepthTextureが使えなかった

本当は、自機の視界はDepthTextureにしたかったです。
最近のロボット掃除機はRGBカメラを搭載しているものも多いかと思いますが、障害物の判定であれば、IRカメラを搭載しているものも多いかと思います。
ロボット掃除機の視界を表現したかったので、色々なシェーダーを試しましたが、物体との位置関係を把握するためであれば、DepthTextureが最もシンプルでふさわしいのではと思い、PostProcessでDepthTextureを表示することにしました。
Editor上ではうまくいっていましたが、WebGLに書き出したものはうまく表示されませんでした。
まさかそんなことになるとは思わず、提出1時間前のビルドだったので、かなり困りました。
調べても有益な情報が見つからず、ChatGPTに聞いたものの解決できず、結局通常のカメラ映像で妥協することとなりました。
自機のカメラ演出は試行錯誤を重ねたポイントであり、壁の記録は自機の視界がよくない代わりの機能で作っていたので、本当に悔しかったです。

改善点

塗りや壁の記録にテクスチャを多く使っており、テクスチャサイズが大きめなので、小さくできそうです。
開始場所を複数地点にし、ランダムに抽選するのもアリかなと思います。
欲を言えば、複数ステージ用意したかったです。
WebGLのPostProcessでDepthTextureが使えない理由は未だに分かりませんが、最近はRenderGraphが推奨されているかと思うので、RenderGraphでPostProcessを行う方法は知っておきたいなと思いました。

結果

評価が高かった作品のページに載りました。
https://unityroom.com/unity1weeks/66/top
Unity1週間ゲームジャムは4回参加しましたが、載ったのは初めて(途中で評価の形式は変わりましたが)なので嬉しかったです。
どうやら斬新さで評価してもらえたようです。
ですが、自機の視界がDepthTextureだったらどんな評価だっただろうと思うと、やはり悔しさが残ります。

まとめ

いつもながら、このゲームでいいのかという不安がありました。
ですが、今回は評価いただけたようなので、少しだけ自信に繋がりました。
本当はAIで何かしたかったのですが、APIの料金がかかるので、断念しました。
お金をかけずにAIで何かできたらなと思っています。
繰り返しになりますが、ゲームの肝の部分に技術的要素があるなら、最初に検証を行うべきだなというのを改めて感じました。
無事完成はしたものの、原因不明の症状に悩まされたり、結果的に妥協したりと、今回もやはりつらかったです。
前回の件もあり、ゲームジャムでメンタル的につらくなることが続いたので、しばらくはゲームジャムを控えるかもしれません…。
(誰かから制作のお誘いをいただいた場合は参加しますが、一人ではしばらくやらないかも…)

Discussion