窓に明かりを灯した。建物ごとに参照を持たずに昼夜を切り替える

配列で持ち回らない設計が、結果的に一番楽だった。

日本進化シミュレーション第9回 / 全16回目次

昼間はそれなりに見られる街並みになってきたけれど、夜になると建物がただの黒い塊になった。
現実の街は、夜になると窓から明かりが漏れて、それだけで生活している感じが出る。
僕は、このゲームにもそれが欲しかった。

素朴にやると、建物ごとの参照を配列で持つことになる

最初に思いついたのは、街灯や窓ガラスのマテリアルを作るたびに、その参照をどこかの配列に積んでおいて、昼夜が切り替わるタイミングでその配列を回して明るさを書き換える、というやり方だった。

単純だけど、これには弱点がある。
建物は建て替えられたり、時代が進んで消えたりする。
配列に積みっぱなしにしていると、無くなった建物のマテリアル参照がいつまでも残り、配列が際限なく伸びていく。
解放し忘れるたびに、少しずつメモリを食いつぶす作りになってしまう。

「タグを付けておいて、後から拾う」方式にした

代わりに選んだのは、マテリアルを作る側が自分で目印を付けておき、更新する側はシーン全体を毎回探しに行く、という方式だった。

窓ガラスや街灯のランプを作るglassMat()lanternMat()という関数の中で、マテリアルのuserData.nightGlowBaseに、ベースとなる明るさの値を積んでおく。
それだけ。配列に登録する処理は、どこにも書かない。

昼夜の切り替えを処理している場所では、約32フレームに1回、シーン全体をscene.traverse()でたどって、userData.nightGlowBaseを持っているマテリアルだけを見つけ、その値をもとに発光の強さを書き換える。

「持ち回らない」設計が、結果的に一番楽だった

この方式のいいところは、建物が建て替わっても消えても、何も後始末をしなくていいことだ。
無くなった建物のマテリアルは、シーンから消えた時点でtraverse()の対象からも自然に外れる。
配列を管理する必要が、そもそも存在しない。

「作った側が参照を配って回る」より、「探す側が毎回シーン全体を見に行く」ほうが、この規模のゲームでは扱いやすかった。
32フレームに1回という頻度も、探しに行くコストと反応の滑らかさのバランスを見て決めた値で、もっと頻繁にする理由は特に無かった。

この後、街灯・窓明かり・提灯へと広げた

この仕組みを一度作ってしまえば、あとは光らせたいものを増やすだけでよかった。
病院や学校、駅の窓をガラス化して同じ方式に乗せ、町家や市場の軒先には提灯を追加した。
新しく「夜だけ光る」ものを作るときは、必ずこのuserDataにタグを積むやり方を踏襲することにしている。
一度決めた設計の型からあえて外れないようにするのも、後で自分を助けることになる。

スタンプラリーに挑戦する 行った場所・気になる場所は、現地チェックインでスタンプに残せます。 みんなのコースを見てみる 会員が作ったスポット巡りのコースを都道府県から探せます。自分だけのコースも作れます。 運営者の個人noteも書いています AI活用やサイト運営で気づいたことを、もう少し個人の視点で掘り下げています。

※運営者が個人で書いているnoteです。

技術ブログ一覧へ戻る