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

数字だけのゲームに3Dの敷地を足したら、canvasが秒間60回消えた

「画面上でキャンプ場を作れるようにしたい」という一言から、Three.jsで敷地を作ることにした。
ところが既存のUIの作りと3Dは、そのままでは同居できなかった。

キャンプ場経営ゲームをつくる第3回 / 全3回目次

公開したあと、「もっとやりこみ要素が欲しい。画面上でキャンプ場が作れるようにできないか」という要望をもらった。料金や集客をスライダーで決めるだけだったこのゲームに、3Dの敷地を足して、区画や施設を自分で建てられるようにする。マス目に吸着させず、好きな場所に置ける形にした。

canvasが毎フレーム作り直されていた

最初につまずいたのはここだった。このゲームのUIは、状態が変わるたびにinnerHTMLで画面をまるごと描き直す作りになっている。素直に3Dのcanvasをその中へ置いたところ、スライダーをドラッグしている間じゅうcanvasが作り直され、WebGLの描画コンテキストが秒間60回捨てられていた。

直し方は2つ重ねた。ひとつは、canvasを画面の再生成に巻き込まれない場所に置くこと。モジュールが持ち続けるDOMノードにしておき、画面側には空の受け皿だけを描いて、あとからappendChildで移し替える。同じページ内でのappendChildは「移動」なので、描画コンテキストは保たれる。

// 画面の構造が変わるときだけ全部描き直す\nif (key !== mountedShell) {\n  stage.innerHTML = renderShell();\n  mountYard();   // canvas を新しい受け皿へ移す\n}\npatch();         // 毎回:中身だけ差し替える

もうひとつは、描き直しそのものを2段階に割ったこと。「構造が変わるときだけ全部書き換える」処理と「毎回中身だけ差し替える」処理を分けた。これで、スライダーを動かしても3Dの世界は生き続けるようになった。

詰め込むほど儲かるゲームになってしまった

置き方を「便利さ・広さ・自然・静けさ」の4つで採点し、それを稼働率と満足度に効かせる設計にした。ところが最初のバランスでは、区画を詰め込めば詰め込むほど得をした。区画数が売上に直結する一方で、評価が落ちても稼働率が少し下がるだけだったからだ。

区画を増やすとコストも増える構造を入れ、レイアウト評価の効き方を強くして、ようやく「詰め込み24区画」と「ゆとり16区画」がどちらもB評価に届くところまで持ってきた。どちらの経営も成立して、最適解が一つに定まらない状態がいちばん面白いと思っている。

このトレードオフが崩れていないかは、テストで固定してある。「同じ区画数なら間隔を空けたほうが総合点が高い、ただし詰め込めば区画数では勝つ」という関係そのものを検査している。

見た目をよくしようとして、いちど白飛びさせた

質感を上げるため、空から環境マップを作ってマテリアルに反射を効かせてみた。結果は全体が真っ白に飛んで、テントの色も地面の色も失われた。映り込みが効くのは金属やガラスで、テントと土と芝生でできたこの風景には見合わない。素直に外した。

代わりに効いたのは地味な積み重ねのほうだった。テクスチャは画像を持たずCanvasで描いて生成し(単一HTMLに全部埋め込む作りなので、画像を持つとそのままファイルサイズになる)、敷地の外に起伏と森と遠くの山を置き、季節ごとに地面と光の色を変えた。冬になると敷地が雪で白くなり、遠くに雪山が見える。

ランキングでは、送られてきた数字を信じない

全国ランキングも足した。ブラウザの中だけで完結していたこのゲームが、初めてサーバーへ数字を送ることになる。

スコアをそのまま受け取ると、開発者ツールで書き換えた値がそのまま1位になる。なので、スコアだけでなく最終資金・平均稼働率・平均満足度・シーズン数も一緒に送らせ、サーバー側で同じ式を使って計算し直し、一致しなければ弾くことにした。手取りシミュレーターで使っている「額面 − 社会保険料 − 税 ≒ 手取り」の検算と同じ考え方だ。

この方式には正直な代償がある。スコアの計算式がゲーム側とサーバー側の2か所に存在することになる。バランス調整で重みを変えるときに片方だけ直すと、全員の登録が弾かれる。コードにも引き継ぎメモにも警告を書いたが、いつか踏む気がしている。

会員登録は要らない。ニックネームだけで登録できて、メールアドレスのような個人を特定できる情報は、そもそもテーブルに列を作っていない。

まる子パパ

まる子パパ

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

ほかにも書いています

note・スタンプ

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

技術ブログ一覧へ戻る