2026.09.23 泊まれる場所4,223 立ち寄りスポット59,693 営業中を確認したキャンプ場1,005 note を読む

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ゲームを1本作るときの進め方を、noteにまとめています(書いているのは私です)。
noteで読む

まる子パパ

まる子パパ

会社員。受託開発のエンジニアを15年以上続けていて、その前は寿司職人・長距離運転手・農業。 技術ブログは、キャンプの合間に踏んだバグと、AI・Web開発の運用の失敗を書いています。 このサイト自体が、開発に携わっているCMS「コンテナ」の稼働中の実例です。 このサイトについて / 小さな自動化の相談

—

ほかにも書いています

受託・note・スタンプ

※受託の相談とnoteは、運営者が個人で受けている・書いているものです。

技術ブログ一覧へ戻る