☝️ 「汎用化したい」という衝動と、開発の現実

📌 この記事は Zenn に投稿した内容のアーカイブです。 プログラマーを数年やっていると、おそらく全員が一度は同じことを考える。 「これ、他のプロジェクトでも使える形にしたい」 最初はただ動けばよかったコードが、だんだん気持ち悪く見えてくる。 コピペも増える。責務も混ざる。依存も汚くなる。 すると自然に、 共通化したい 抽象化したい 再利用可能にしたい という欲求が出てくる。 これは悪いことではない。むしろ健全だと思う。 “設計”を意識し始めた証拠だから。 ただ、この感覚はかなり危ない。 一歩間違えると、 簡単に「過剰設計」に転がり始める。 「将来使うかもしれない」 この一言が、 過剰設計の始まりになることはかなり多い。 今回は、自分がゲーム開発をやる中で感じた、 なぜ人は汎用化したくなるのか なぜそれが失敗しやすいのか 実際どう考えるとちょうどいいのか について書いてみる。 汎用化したくなるのは、実はかなり自然なこと 例えば、最初の頃のコードってかなり局所的になる。 if (isBoss) { hpBar.color = Color.red; } みたいな、「今必要だから書いたコード」が大量にある。 でも経験を積むと、 こういうコードを見るだけで“変更コスト”を想像するようになる。 「これ別のボス出たらどうするんだろう」 「色変えるたびに if 増えるの?」 「そもそも UI が敵情報知ってるのおかしくない?」 みたいなことを考え始める。 つまり汎用化欲求の正体って、単なる意識高い設計趣味ではなく、 “変更に弱いコードへの違和感” なんだと思う。 だからある程度コードを書いた人ほど、自然と抽象化に向かう。 実際、汎用化にはかなり強いメリットがある これは間違いない。 1. 「依存」に敏感になる 再利用を意識すると、まずベタ結合が気になり始める。 直接参照 Singleton ベタ依存 MonoBehaviour 神クラス Inspector 配線地獄 みたいなものを避けたくなる。 結果として、 責務分離 Interface 化 データ駆動 疎結合 みたいな方向へ進む。 ...

2026年5月18日 · 2 分 · 238 文字 · Wuyukwi

🧊 【Unity】10万オブジェクトを回転させたらどこがボトルネックになるのか(後編:ISystemで一桁msへ)

📌 この記事は Zenn に投稿した内容のアーカイブです。 はじめに 前回は、Job System + Burst を使って 10万オブジェクトの回転処理(46ms → 3.5ms) まで最適化しました。 ただしその時点でも、フレーム全体としてはまだ重く、 ボトルネックはレンダリング側に残っていました。 なぜJob Systemだけでは不十分だったのか 前回の時点で回転処理自体はかなり軽くなっていましたが、 それでもフレーム全体としては大きな負荷が残っていました。 原因は、描画周りの処理です。 たとえロジック(Job)が高速でも、メインスレッド側では依然として 10万個の MeshRenderer を個別に処理する必要があります。 具体的には以下のような処理です: Culling(可視判定) Bounding Volume(バウンディング更新) RenderQueue(描画順の整理) これらがすべて「オブジェクト単位」で実行されるため、 結果として大きなCPU負荷になっていました。 この問題に対するアプローチが、Entities Graphicsです。 目標: → GameObjectベースのオブジェクトをEntityに変換する 仕組み: → 変換後は、これらの処理を Entities Graphics が内部的に管理し、 BatchRendererGroup を利用して描画処理をまとめて実行します。 その結果: 数万〜数十万単位のオブジェクトでも、 ごく少数のバッチとして扱えるようになります。 ■ 結果 今回は DOTS(Entities + Entities Graphics)に移行した結果: フレーム時間:約120ms → 約9ms 110FPS前後で安定 ほぼ別物レベルまで改善しています。 ■ 比較 指標 改造前(GameObject) 改造後(Pure DOTS) 改善 Batches ~120,000 74 約1486倍削減 SetPass Calls 56 26 約2.1倍改善 Tris / Verts 不安定 安定 描画の一貫性向上 Frame Time 120ms(8FPS) 9ms(110FPS) 約13倍高速化 ■ Profilerを見ると何が起きているか Profilerを確認すると: ...

2026年4月1日 · 3 分 · 612 文字 · Wuyukwi

🧊 【Unity】10万オブジェクトを回転させたらどこがボトルネックになるのか(前編:LateUpdateとJob System)

📌 この記事は Zenn に投稿した内容のアーカイブです。 最近、DOTS(Data-Oriented Tech Stack)が実際どのくらい効果があるのか気になっていたので、 簡単な検証を兼ねて触ってみることにしました。 せっかくなので「大量のオブジェクトを動かした場合にどこがボトルネックになるのか?」も含めて、 段階的に確認していこうと思います。 この記事ではまず、LateUpdateでの回転処理のボトルネックと、 Job Systemによる最適化の効果にフォーカスします。 レンダリング周り(CullingやDrawCall)については、次回以降で触れる予定です。 ■ 検証環境 CPU:i7-12700K GPU:RTX 3070 Unity:URPの新規プロジェクト オブジェクト数:10万(Cube) ■ テスト内容 シンプルに「10万個のCubeを生成して回転させるだけ」です。 BoxColliderは削除 ランダム位置に配置 各オブジェクトにランダムな回転軸 void Start() { var root = new GameObject(“CubeRoot”).transform; for (int i = 0; i < spawnCount; i++) { var go = Instantiate(prefab, Random.insideUnitSphere * 50f, Quaternion.identity, root); transforms.Add(go.transform); } } void LateUpdate() { float dt = Time.deltaTime; for (int i = 0; i < transforms.Count; i++) { transforms[i].Rotate(rotationAxes[i], 100f * dt); } } ...

2026年3月31日 · 2 分 · 362 文字 · Wuyukwi

🙌 なぜ Unity は C# を選び、Unreal は選ばなかったのかについての個人の考察

📌 この記事は Zenn に投稿した内容のアーカイブです。 はじめに ゲームエンジンの言語の話になると、よくこんな対比が出てきます。 Unity は C#。 Unreal は C++ と Blueprint。 この違い、ただの好みではありません。 エンジンの設計思想そのものに関わっています。 C# が優れているとか、C++ が古いとか、そういう単純な話ではない。 両者はそもそも目指している開発体験が違うのです。 Unity が辿った言語統一の歴史 今でこそ「Unity といえば C#」という印象がありますが、最初からそうだったわけではありません。 初期の Unity では、開発者のバックグラウンドに合わせて複数の言語を選択できるのが特徴でした。 具体的には次の3つです。 C# UnityScript (JavaScript 風の独自言語) Boo (Python 風の言語) 当時の Unity は「スクリプト言語の自由度」を売りの一つにしており、Web 開発者は UnityScript、Python 系に慣れている人は Boo、という具合に選べるようになっていました。 しかし、この方針は長くは続きませんでした。 Unity 2017 頃から段階的に非推奨となり、 Unity 2019.1 を最後に UnityScript と Boo は完全に削除 されます。 結果として、Unity のスクリプト言語は C# のみ に統一されました。 参考 https://discussions.unity.com/t/which-release-removed-support-unityscript-and-boo/1624299 なぜこうなったのか。理由はいくつかあります。 まず、複数言語の維持コストです。 エンジン側はコンパイラ、ツールチェーン、デバッグ環境などをすべてサポートし続ける必要があります。 さらに重要なのは、UnityScript と Boo の実態です。 これらは見た目こそ別言語でしたが、内部では Mono 上で動作するスクリプトでした。 ...

2026年3月11日 · 2 分 · 397 文字 · Wuyukwi

🎉 Git を「完全に理解」するためのデータ構造の話

📌 この記事は Zenn に投稿した内容のアーカイブです。 はじめに Git を使っていて、こんな感覚になったことはありませんか? コマンドは打てるけど、何が起きているか分からない merge と rebase の違いを、説明しろと言われると詰まる conflict が出ると、なぜ衝突したのか理解できない 多くの Git 解説記事は、 「何を打つか」 は丁寧に教えてくれますが、 「なぜそうなるか」 までは踏み込んでくれません。 その結果、 なんとなく使えているが、仕組みはよく分からない という状態に陥りがちです。 この記事では、コマンドの説明はほぼ行いません。 代わりに、Git の内部構造をデータ構造として捉え直す ことで、 「あ、そういうことだったのか」 と腑に落ちる理解を目指します。 少しだけ グラフ理論 と ポインタの概念(C 言語) の素養があると、 かなりスムーズに理解できると思います。 Git の正体:木構造ではなく DAG(有向非巡回グラフ) 多くの人は、Git の履歴を「木構造」としてイメージしています。 しかし、これは正確ではありません。 Git の本質は 有向非巡回グラフです。 Commit は「ノード」 すべての commit は、グラフ上の ノード です。 各 commit は、 ファイルのスナップショット 親 commit への参照(1 個または 2 個) を持っています。 親が 2 個になる瞬間 = merge 通常の commit は親が 1 つですが、 merge commit は 親を 2 つ 持ちます。 ...

2026年2月25日 · 3 分 · 437 文字 · Wuyukwi

☝️ デバッグ UI を書かずに Unity のデバッグ環境を成立させる設計と実装

📌 この記事は Zenn に投稿した内容のアーカイブです。 はじめに Unity で開発していると、 実行中にパラメータを触りながら挙動を確認したい という場面は、ほぼ毎日のように出てきます。 最初のうちは、Unity 標準の仕組みを使って 簡単な Runtime Debug UI を用意すれば十分でした。 ただ、プロジェクトが進み、 デバッグ項目が増える 調整対象が増える 複数人で同時に触る という状況になるにつれ、 「その場しのぎ」で作ったデバッグ UI が、確実に足を引っ張る ようになってきます。 この段階で欲しくなったのが、 壊れにくく、拡張しやすく、 プロジェクトと一緒に「育てていける」デバッグ基盤 でした。 この記事では、 そのために設計した 自作 Runtime Debug システム について、 設計意図と実装の要点 を中心にまとめます。 何が問題だったのか 問題の本質は、「UI をどう実装するか」 ではありませんでした。 本当に困っていたのは、 Debug 項目の追加・削除が面倒 どこに何のデバッグ設定があるのか分からない 不要になった項目が整理されず、蓄積していく という 運用面の破綻 です。 特に後半になると、 「デバッグ環境のせいで、デバッグそのものがやりにくい」 という、本末転倒な状態になりがちでした。 目指したゴール 今回の設計で目指したゴールは、かなり明確です。 UI を書かずに Debug 項目を追加できる 構造が自然に整理され続ける 無効化・除去が簡単 プロジェクト規模が大きくなっても破綻しない つまり、 「運用しても壊れない設計」 を最優先にしました。 全体構成 全体の流れは、次のようになります。 起動 ↓ RuntimeInitializeOnLoadMethod ↓ DebugManager 自動生成 ↓ DebugOption 自動登録 ↓ Reflection による項目収集 ↓ UI 自動生成 & バインディング ここで重視したのは、 ...

2026年2月18日 · 3 分 · 462 文字 · Wuyukwi

🧠 AndroidビルドでPlayFabのSecretKeyが丸見えだった話と、ビルド時に自動変換する対策

📌 この記事は Zenn に投稿した内容のアーカイブです。 はじめに PlayFab を使ったプロジェクトで、 TitleId や DeveloperSecretKey をどう管理するかは、最初に一度は悩むポイントだと思います。 自分も最初は深く考えずに、 const string TitleId = "XXXX"; const string DeveloperSecretKey = "YYYY"; のようにコードに直接書いていました。 ところが Android ビルド後に apk を確認してみると、 strings コマンドで 平文のままキーが抜ける ことに気づき、 「これはさすがにまずいな……」となったのが今回のきっかけです。 問題点:apk 内に平文で残る C# のコードに直接書いた文字列は、 IL2CPP でも 難読化をしていても 最終的に 文字列リテラルとして apk 内に残ります 。 つまり、 strings app.apk を叩くだけで、TitleId や SecretKey が見えてしまう状態でした。 もちろん「完全に隠す」ことは不可能ですが、 平文で置いておくのはリスクが高すぎる と判断しました。 方針:コードには平文を置かない 今回の方針はシンプルです。 ソースコード内に 平文のキーを一切書かない ビルド時に Editor 側で変換・生成する ランタイムでは最小限の復号処理だけ行う いわゆる「秘匿」というより、 apk を覗かれたときに即バレしない状態を作る のが目的です。 実装概要 実装は以下の流れにしました。 Editor フォルダ内 ...

2026年2月5日 · 1 分 · 157 文字 · Wuyukwi

🐈 UnityのEditor拡張で「設定の保存先」に毎回悩む話

📌 この記事は Zenn に投稿した内容のアーカイブです。 Unity でエディタ拡張を書いていると、 「この設定、どこに保存するのが正解なんだろう?」 と悩む場面がよくあります。 そのときにまず候補に上がるのが EditorPrefs です。 bool isOpen = EditorPrefs.GetBool("MyTool_Foldout", false); とても手軽で便利ですが、使い方を間違えると チーム開発では地味に事故りやすい API でもあります。 この記事では、 EditorPrefs は何のための仕組みなのか どんな用途に向いているのか 逆に使ってはいけないケース を整理してみます。 EditorPrefs とは何か EditorPrefs は、Unity エディタ専用の設定保存機構 です。 プロジェクト単位ではない ユーザー(マシン)単位で保存される バージョン管理の対象外 という特徴があります。 つまり、 「この PC で、この Unity を使っている自分だけの設定」 を保存するためのものです。 保存場所はどこ? EditorPrefs の中身は、OS ごとに以下の場所に保存されます。 Windows:レジストリ macOS:~/Library/Preferences Linux:~/.config この時点で分かる通り、 Git にも SVN にも乗りません 。 向いているユースケース 1. エディタ UI の表示状態 例えば、 ツールウィンドウの開閉状態 折りたたみ(Foldout)の ON / OFF 最後に選択していたタブ こういった「見た目の状態」は、EditorPrefs と非常に相性が良いです。 bool isOpen = EditorPrefs.GetBool("MyTool_Foldout", false); ...

2026年2月2日 · 1 分 · 183 文字 · Wuyukwi