<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Unity on Wuyukwi's Notebook</title><link>https://wuyukwi.duckdns.org/tags/unity/</link><description>Recent content in Unity on Wuyukwi's Notebook</description><generator>Hugo</generator><language>ja</language><lastBuildDate>Mon, 18 May 2026 17:34:45 +0900</lastBuildDate><atom:link href="https://wuyukwi.duckdns.org/tags/unity/index.xml" rel="self" type="application/rss+xml"/><item><title>☝️ 「汎用化したい」という衝動と、開発の現実</title><link>https://wuyukwi.duckdns.org/posts/zenn-010f3a8e5af665/</link><pubDate>Mon, 18 May 2026 17:34:45 +0900</pubDate><guid>https://wuyukwi.duckdns.org/posts/zenn-010f3a8e5af665/</guid><description>&lt;blockquote&gt;
&lt;p&gt;📌 &lt;em&gt;この記事は &lt;a href="https://zenn.dev/wuyukwi/articles/010f3a8e5af665"&gt;Zenn&lt;/a&gt; に投稿した内容のアーカイブです。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;プログラマーを数年やっていると、おそらく全員が一度は同じことを考える。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「これ、他のプロジェクトでも使える形にしたい」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最初はただ動けばよかったコードが、だんだん気持ち悪く見えてくる。&lt;br&gt;
コピペも増える。責務も混ざる。依存も汚くなる。&lt;/p&gt;
&lt;p&gt;すると自然に、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;共通化したい&lt;/li&gt;
&lt;li&gt;抽象化したい&lt;/li&gt;
&lt;li&gt;再利用可能にしたい&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という欲求が出てくる。&lt;/p&gt;
&lt;p&gt;これは悪いことではない。むしろ健全だと思う。&lt;br&gt;
“設計”を意識し始めた証拠だから。&lt;/p&gt;
&lt;p&gt;ただ、この感覚はかなり危ない。&lt;/p&gt;
&lt;p&gt;一歩間違えると、&lt;br&gt;
簡単に「過剰設計」に転がり始める。&lt;/p&gt;
&lt;p&gt;「将来使うかもしれない」&lt;/p&gt;
&lt;p&gt;この一言が、&lt;br&gt;
過剰設計の始まりになることはかなり多い。&lt;/p&gt;
&lt;p&gt;今回は、自分がゲーム開発をやる中で感じた、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;なぜ人は汎用化したくなるのか&lt;/li&gt;
&lt;li&gt;なぜそれが失敗しやすいのか&lt;/li&gt;
&lt;li&gt;実際どう考えるとちょうどいいのか&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;について書いてみる。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="汎用化したくなるのは実はかなり自然なこと"&gt;汎用化したくなるのは、実はかなり自然なこと&lt;/h2&gt;
&lt;p&gt;例えば、最初の頃のコードってかなり局所的になる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (isBoss)
{
hpBar.color = Color.red;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;みたいな、「今必要だから書いたコード」が大量にある。&lt;/p&gt;
&lt;p&gt;でも経験を積むと、&lt;br&gt;
こういうコードを見るだけで“変更コスト”を想像するようになる。&lt;/p&gt;
&lt;p&gt;「これ別のボス出たらどうするんだろう」&lt;br&gt;
「色変えるたびに if 増えるの？」&lt;br&gt;
「そもそも UI が敵情報知ってるのおかしくない？」&lt;/p&gt;
&lt;p&gt;みたいなことを考え始める。&lt;/p&gt;
&lt;p&gt;つまり汎用化欲求の正体って、単なる意識高い設計趣味ではなく、&lt;/p&gt;
&lt;p&gt;“変更に弱いコードへの違和感”&lt;/p&gt;
&lt;p&gt;なんだと思う。&lt;/p&gt;
&lt;p&gt;だからある程度コードを書いた人ほど、自然と抽象化に向かう。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="実際汎用化にはかなり強いメリットがある"&gt;実際、汎用化にはかなり強いメリットがある&lt;/h2&gt;
&lt;p&gt;これは間違いない。&lt;/p&gt;
&lt;h3 id="1-依存に敏感になる"&gt;1. 「依存」に敏感になる&lt;/h3&gt;
&lt;p&gt;再利用を意識すると、まずベタ結合が気になり始める。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;直接参照&lt;/li&gt;
&lt;li&gt;Singleton ベタ依存&lt;/li&gt;
&lt;li&gt;MonoBehaviour 神クラス&lt;/li&gt;
&lt;li&gt;Inspector 配線地獄&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;みたいなものを避けたくなる。&lt;/p&gt;
&lt;p&gt;結果として、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;責務分離&lt;/li&gt;
&lt;li&gt;Interface 化&lt;/li&gt;
&lt;li&gt;データ駆動&lt;/li&gt;
&lt;li&gt;疎結合&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;みたいな方向へ進む。&lt;/p&gt;</description></item><item><title>🧊 【Unity】10万オブジェクトを回転させたらどこがボトルネックになるのか（後編：ISystemで一桁msへ）</title><link>https://wuyukwi.duckdns.org/posts/zenn-8577fbf1074840/</link><pubDate>Wed, 01 Apr 2026 12:47:15 +0900</pubDate><guid>https://wuyukwi.duckdns.org/posts/zenn-8577fbf1074840/</guid><description>&lt;blockquote&gt;
&lt;p&gt;📌 &lt;em&gt;この記事は &lt;a href="https://zenn.dev/wuyukwi/articles/8577fbf1074840"&gt;Zenn&lt;/a&gt; に投稿した内容のアーカイブです。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="はじめに"&gt;はじめに&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://zenn.dev/wuyukwi/articles/88800f31f667f3"&gt;前回&lt;/a&gt;は、Job System + Burst を使って&lt;br&gt;
&lt;strong&gt;10万オブジェクトの回転処理（46ms → 3.5ms）&lt;/strong&gt; まで最適化しました。&lt;/p&gt;
&lt;p&gt;ただしその時点でも、フレーム全体としてはまだ重く、&lt;br&gt;
ボトルネックはレンダリング側に残っていました。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="なぜjob-systemだけでは不十分だったのか"&gt;なぜJob Systemだけでは不十分だったのか&lt;/h2&gt;
&lt;p&gt;前回の時点で回転処理自体はかなり軽くなっていましたが、&lt;br&gt;
それでもフレーム全体としては大きな負荷が残っていました。&lt;/p&gt;
&lt;p&gt;原因は、描画周りの処理です。&lt;/p&gt;
&lt;p&gt;たとえロジック（Job）が高速でも、メインスレッド側では依然として&lt;br&gt;
10万個の &lt;code&gt;MeshRenderer&lt;/code&gt; を個別に処理する必要があります。&lt;/p&gt;
&lt;p&gt;具体的には以下のような処理です：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Culling（可視判定）&lt;/li&gt;
&lt;li&gt;Bounding Volume（バウンディング更新）&lt;/li&gt;
&lt;li&gt;RenderQueue（描画順の整理）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらがすべて「オブジェクト単位」で実行されるため、&lt;br&gt;
結果として大きなCPU負荷になっていました。&lt;/p&gt;
&lt;p&gt;この問題に対するアプローチが、Entities Graphicsです。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;目標：&lt;br&gt;
→ GameObjectベースのオブジェクトをEntityに変換する&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;仕組み：&lt;br&gt;
→ 変換後は、これらの処理を &lt;code&gt;Entities Graphics&lt;/code&gt; が内部的に管理し、&lt;br&gt;
&lt;code&gt;BatchRendererGroup&lt;/code&gt; を利用して描画処理をまとめて実行します。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;その結果：&lt;/p&gt;
&lt;p&gt;数万〜数十万単位のオブジェクトでも、&lt;br&gt;
ごく少数のバッチとして扱えるようになります。&lt;/p&gt;
&lt;h2 id="-結果"&gt;■ 結果&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://static.zenn.studio/user-upload/8eac221c088d-20260401.gif"&gt;&lt;br&gt;
今回は DOTS（Entities + Entities Graphics）に移行した結果：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;フレーム時間：約120ms → 約9ms&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;110FPS前後で安定&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ほぼ別物レベルまで改善しています。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="-比較"&gt;■ 比較&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;指標&lt;/th&gt;
&lt;th&gt;改造前（GameObject）&lt;/th&gt;
&lt;th&gt;改造後（Pure DOTS）&lt;/th&gt;
&lt;th&gt;改善&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Batches&lt;/td&gt;
&lt;td&gt;~120,000&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;74&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;約1486倍削減&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SetPass Calls&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;26&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;約2.1倍改善&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tris / Verts&lt;/td&gt;
&lt;td&gt;不安定&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;安定&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;描画の一貫性向上&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frame Time&lt;/td&gt;
&lt;td&gt;120ms（8FPS）&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;9ms（110FPS）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;約13倍高速化&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="-profilerを見ると何が起きているか"&gt;■ Profilerを見ると何が起きているか&lt;/h2&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://static.zenn.studio/user-upload/561808254336-20260401.png"&gt;&lt;br&gt;
&lt;img loading="lazy" src="https://static.zenn.studio/user-upload/d2021f89924c-20260401.png"&gt;&lt;br&gt;
Profilerを確認すると：&lt;/p&gt;</description></item><item><title>🧊 【Unity】10万オブジェクトを回転させたらどこがボトルネックになるのか（前編：LateUpdateとJob System）</title><link>https://wuyukwi.duckdns.org/posts/zenn-88800f31f667f3/</link><pubDate>Tue, 31 Mar 2026 17:31:45 +0900</pubDate><guid>https://wuyukwi.duckdns.org/posts/zenn-88800f31f667f3/</guid><description>&lt;blockquote&gt;
&lt;p&gt;📌 &lt;em&gt;この記事は &lt;a href="https://zenn.dev/wuyukwi/articles/88800f31f667f3"&gt;Zenn&lt;/a&gt; に投稿した内容のアーカイブです。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最近、DOTS（Data-Oriented Tech Stack）が実際どのくらい効果があるのか気になっていたので、&lt;br&gt;
簡単な検証を兼ねて触ってみることにしました。&lt;/p&gt;
&lt;p&gt;せっかくなので「大量のオブジェクトを動かした場合にどこがボトルネックになるのか？」も含めて、&lt;br&gt;
段階的に確認していこうと思います。&lt;/p&gt;
&lt;p&gt;この記事ではまず、LateUpdateでの回転処理のボトルネックと、&lt;br&gt;
Job Systemによる最適化の効果にフォーカスします。&lt;/p&gt;
&lt;p&gt;レンダリング周り（CullingやDrawCall）については、次回以降で触れる予定です。&lt;/p&gt;
&lt;h2 id="-検証環境"&gt;■ 検証環境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;CPU：i7-12700K&lt;/li&gt;
&lt;li&gt;GPU：RTX 3070&lt;/li&gt;
&lt;li&gt;Unity：URPの新規プロジェクト&lt;/li&gt;
&lt;li&gt;オブジェクト数：10万（Cube）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="-テスト内容"&gt;■ テスト内容&lt;/h2&gt;
&lt;p&gt;シンプルに「10万個のCubeを生成して回転させるだけ」です。&lt;br&gt;
&lt;img loading="lazy" src="https://static.zenn.studio/user-upload/96aecb2d5f9f-20260331.gif"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;BoxColliderは削除&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ランダム位置に配置&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;各オブジェクトにランダムな回転軸&lt;/p&gt;
&lt;p&gt;void Start()
{
var root = new GameObject(&amp;ldquo;CubeRoot&amp;rdquo;).transform;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for (int i = 0; i &amp;lt; spawnCount; i++)
{
var go = Instantiate(prefab, Random.insideUnitSphere * 50f, Quaternion.identity, root);
transforms.Add(go.transform);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;void LateUpdate()
{
float dt = Time.deltaTime;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for (int i = 0; i &amp;lt; transforms.Count; i++)
{
transforms[i].Rotate(rotationAxes[i], 100f * dt);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;</description></item><item><title>🙌 なぜ Unity は C# を選び、Unreal は選ばなかったのかについての個人の考察</title><link>https://wuyukwi.duckdns.org/posts/zenn-97b70df23bd792/</link><pubDate>Wed, 11 Mar 2026 19:31:51 +0900</pubDate><guid>https://wuyukwi.duckdns.org/posts/zenn-97b70df23bd792/</guid><description>&lt;blockquote&gt;
&lt;p&gt;📌 &lt;em&gt;この記事は &lt;a href="https://zenn.dev/wuyukwi/articles/97b70df23bd792"&gt;Zenn&lt;/a&gt; に投稿した内容のアーカイブです。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id="はじめに"&gt;はじめに&lt;/h1&gt;
&lt;p&gt;ゲームエンジンの言語の話になると、よくこんな対比が出てきます。&lt;/p&gt;
&lt;p&gt;Unity は C#。&lt;br&gt;
Unreal は C++ と Blueprint。&lt;/p&gt;
&lt;p&gt;この違い、ただの好みではありません。&lt;br&gt;
エンジンの設計思想そのものに関わっています。&lt;/p&gt;
&lt;p&gt;C# が優れているとか、C++ が古いとか、そういう単純な話ではない。&lt;br&gt;
両者はそもそも目指している開発体験が違うのです。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="unity-が辿った言語統一の歴史"&gt;Unity が辿った言語統一の歴史&lt;/h1&gt;
&lt;p&gt;今でこそ「Unity といえば C#」という印象がありますが、最初からそうだったわけではありません。&lt;br&gt;
初期の Unity では、開発者のバックグラウンドに合わせて複数の言語を選択できるのが特徴でした。&lt;/p&gt;
&lt;p&gt;具体的には次の3つです。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;UnityScript&lt;/strong&gt; （JavaScript 風の独自言語）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Boo&lt;/strong&gt; （Python 風の言語）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当時の Unity は「スクリプト言語の自由度」を売りの一つにしており、Web 開発者は UnityScript、Python 系に慣れている人は Boo、という具合に選べるようになっていました。&lt;/p&gt;
&lt;p&gt;しかし、この方針は長くは続きませんでした。&lt;/p&gt;
&lt;p&gt;Unity 2017 頃から段階的に非推奨となり、&lt;br&gt;
&lt;strong&gt;Unity 2019.1 を最後に UnityScript と Boo は完全に削除&lt;/strong&gt; されます。&lt;/p&gt;
&lt;p&gt;結果として、Unity のスクリプト言語は &lt;strong&gt;C# のみ&lt;/strong&gt; に統一されました。&lt;/p&gt;
&lt;p&gt;参考&lt;br&gt;
&lt;a href="https://discussions.unity.com/t/which-release-removed-support-unityscript-and-boo/1624299"&gt;https://discussions.unity.com/t/which-release-removed-support-unityscript-and-boo/1624299&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;なぜこうなったのか。理由はいくつかあります。&lt;/p&gt;
&lt;p&gt;まず、複数言語の維持コストです。&lt;br&gt;
エンジン側はコンパイラ、ツールチェーン、デバッグ環境などをすべてサポートし続ける必要があります。&lt;/p&gt;
&lt;p&gt;さらに重要なのは、UnityScript と Boo の実態です。&lt;br&gt;
これらは見た目こそ別言語でしたが、内部では Mono 上で動作するスクリプトでした。&lt;/p&gt;</description></item><item><title>☝️ デバッグ UI を書かずに Unity のデバッグ環境を成立させる設計と実装</title><link>https://wuyukwi.duckdns.org/posts/zenn-2d31ee3e52b29e/</link><pubDate>Wed, 18 Feb 2026 13:18:23 +0900</pubDate><guid>https://wuyukwi.duckdns.org/posts/zenn-2d31ee3e52b29e/</guid><description>&lt;blockquote&gt;
&lt;p&gt;📌 &lt;em&gt;この記事は &lt;a href="https://zenn.dev/wuyukwi/articles/2d31ee3e52b29e"&gt;Zenn&lt;/a&gt; に投稿した内容のアーカイブです。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id="はじめに"&gt;はじめに&lt;/h1&gt;
&lt;p&gt;Unity で開発していると、&lt;br&gt;
&lt;strong&gt;実行中にパラメータを触りながら挙動を確認したい&lt;/strong&gt;&lt;br&gt;
という場面は、ほぼ毎日のように出てきます。&lt;/p&gt;
&lt;p&gt;最初のうちは、Unity 標準の仕組みを使って&lt;br&gt;
簡単な Runtime Debug UI を用意すれば十分でした。&lt;/p&gt;
&lt;p&gt;ただ、プロジェクトが進み、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;デバッグ項目が増える&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;調整対象が増える&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;複数人で同時に触る&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という状況になるにつれ、&lt;br&gt;
&lt;strong&gt;「その場しのぎ」で作ったデバッグ UI が、確実に足を引っ張る&lt;/strong&gt;&lt;br&gt;
ようになってきます。&lt;/p&gt;
&lt;p&gt;この段階で欲しくなったのが、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;壊れにくく、拡張しやすく、&lt;br&gt;
プロジェクトと一緒に「育てていける」デバッグ基盤&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;でした。&lt;/p&gt;
&lt;p&gt;この記事では、&lt;br&gt;
そのために設計した &lt;strong&gt;自作 Runtime Debug システム&lt;/strong&gt; について、&lt;br&gt;
&lt;strong&gt;設計意図と実装の要点&lt;/strong&gt; を中心にまとめます。&lt;/p&gt;
&lt;h1 id="何が問題だったのか"&gt;何が問題だったのか&lt;/h1&gt;
&lt;p&gt;問題の本質は、&lt;strong&gt;「UI をどう実装するか」&lt;/strong&gt; ではありませんでした。&lt;/p&gt;
&lt;p&gt;本当に困っていたのは、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Debug 項目の追加・削除が面倒&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;どこに何のデバッグ設定があるのか分からない&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不要になった項目が整理されず、蓄積していく&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という &lt;strong&gt;運用面の破綻&lt;/strong&gt; です。&lt;/p&gt;
&lt;p&gt;特に後半になると、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;「デバッグ環境のせいで、デバッグそのものがやりにくい」&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;という、本末転倒な状態になりがちでした。&lt;/p&gt;
&lt;h1 id="目指したゴール"&gt;目指したゴール&lt;/h1&gt;
&lt;p&gt;今回の設計で目指したゴールは、かなり明確です。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;UI を書かずに Debug 項目を追加できる&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;構造が自然に整理され続ける&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;無効化・除去が簡単&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;プロジェクト規模が大きくなっても破綻しない&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;つまり、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;「運用しても壊れない設計」&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;を最優先にしました。&lt;/p&gt;
&lt;h1 id="全体構成"&gt;全体構成&lt;/h1&gt;
&lt;p&gt;全体の流れは、次のようになります。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;起動
↓
RuntimeInitializeOnLoadMethod
↓
DebugManager 自動生成
↓
DebugOption 自動登録
↓
Reflection による項目収集
↓
UI 自動生成 &amp;amp; バインディング
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ここで重視したのは、&lt;/p&gt;</description></item><item><title>🧠 AndroidビルドでPlayFabのSecretKeyが丸見えだった話と、ビルド時に自動変換する対策</title><link>https://wuyukwi.duckdns.org/posts/zenn-6817fe00d739b4/</link><pubDate>Thu, 05 Feb 2026 14:15:44 +0900</pubDate><guid>https://wuyukwi.duckdns.org/posts/zenn-6817fe00d739b4/</guid><description>&lt;blockquote&gt;
&lt;p&gt;📌 &lt;em&gt;この記事は &lt;a href="https://zenn.dev/wuyukwi/articles/6817fe00d739b4"&gt;Zenn&lt;/a&gt; に投稿した内容のアーカイブです。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="はじめに"&gt;はじめに&lt;/h3&gt;
&lt;p&gt;PlayFab を使ったプロジェクトで、&lt;br&gt;
&lt;code&gt;TitleId&lt;/code&gt; や &lt;code&gt;DeveloperSecretKey&lt;/code&gt; をどう管理するかは、最初に一度は悩むポイントだと思います。&lt;/p&gt;
&lt;p&gt;自分も最初は深く考えずに、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const string TitleId = &amp;quot;XXXX&amp;quot;;
const string DeveloperSecretKey = &amp;quot;YYYY&amp;quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;のようにコードに直接書いていました。&lt;/p&gt;
&lt;p&gt;ところが Android ビルド後に apk を確認してみると、&lt;br&gt;
&lt;code&gt;strings&lt;/code&gt; コマンドで &lt;strong&gt;平文のままキーが抜ける&lt;/strong&gt; ことに気づき、&lt;br&gt;
「これはさすがにまずいな……」となったのが今回のきっかけです。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="問題点apk-内に平文で残る"&gt;問題点：apk 内に平文で残る&lt;/h3&gt;
&lt;p&gt;C# のコードに直接書いた文字列は、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;IL2CPP でも&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;難読化をしていても&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最終的に &lt;strong&gt;文字列リテラルとして apk 内に残ります&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;つまり、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;strings app.apk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;を叩くだけで、TitleId や SecretKey が見えてしまう状態でした。&lt;/p&gt;
&lt;p&gt;もちろん「完全に隠す」ことは不可能ですが、&lt;br&gt;
&lt;strong&gt;平文で置いておくのはリスクが高すぎる&lt;/strong&gt; と判断しました。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="方針コードには平文を置かない"&gt;方針：コードには平文を置かない&lt;/h3&gt;
&lt;p&gt;今回の方針はシンプルです。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ソースコード内に &lt;strong&gt;平文のキーを一切書かない&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ビルド時に Editor 側で変換・生成する&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ランタイムでは最小限の復号処理だけ行う&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;いわゆる「秘匿」というより、&lt;br&gt;
&lt;strong&gt;apk を覗かれたときに即バレしない状態を作る&lt;/strong&gt; のが目的です。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="実装概要"&gt;実装概要&lt;/h3&gt;
&lt;p&gt;実装は以下の流れにしました。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Editor フォルダ内&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>🐈 UnityのEditor拡張で「設定の保存先」に毎回悩む話</title><link>https://wuyukwi.duckdns.org/posts/zenn-b2fdefc2c53908/</link><pubDate>Mon, 02 Feb 2026 17:57:13 +0900</pubDate><guid>https://wuyukwi.duckdns.org/posts/zenn-b2fdefc2c53908/</guid><description>&lt;blockquote&gt;
&lt;p&gt;📌 &lt;em&gt;この記事は &lt;a href="https://zenn.dev/wuyukwi/articles/b2fdefc2c53908"&gt;Zenn&lt;/a&gt; に投稿した内容のアーカイブです。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Unity でエディタ拡張を書いていると、&lt;br&gt;
「この設定、どこに保存するのが正解なんだろう？」&lt;br&gt;
と悩む場面がよくあります。&lt;/p&gt;
&lt;p&gt;そのときにまず候補に上がるのが &lt;code&gt;EditorPrefs&lt;/code&gt; です。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bool isOpen = EditorPrefs.GetBool(&amp;quot;MyTool_Foldout&amp;quot;, false);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;とても手軽で便利ですが、使い方を間違えると&lt;br&gt;
&lt;strong&gt;チーム開発では地味に事故りやすい&lt;/strong&gt; API でもあります。&lt;/p&gt;
&lt;p&gt;この記事では、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;EditorPrefs は何のための仕組みなのか&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;どんな用途に向いているのか&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;逆に使ってはいけないケース&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;を整理してみます。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="editorprefs-とは何か"&gt;EditorPrefs とは何か&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;EditorPrefs&lt;/code&gt; は、&lt;strong&gt;Unity エディタ専用の設定保存機構&lt;/strong&gt; です。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;プロジェクト単位ではない&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ユーザー（マシン）単位で保存される&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;バージョン管理の対象外&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という特徴があります。&lt;/p&gt;
&lt;p&gt;つまり、&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「この PC で、この Unity を使っている自分だけの設定」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;を保存するためのものです。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="保存場所はどこ"&gt;保存場所はどこ？&lt;/h2&gt;
&lt;p&gt;EditorPrefs の中身は、OS ごとに以下の場所に保存されます。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Windows：レジストリ&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;macOS：&lt;code&gt;~/Library/Preferences&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Linux：&lt;code&gt;~/.config&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;この時点で分かる通り、&lt;br&gt;
&lt;strong&gt;Git にも SVN にも乗りません&lt;/strong&gt; 。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="向いているユースケース"&gt;向いているユースケース&lt;/h2&gt;
&lt;h3 id="1-エディタ-ui-の表示状態"&gt;1. エディタ UI の表示状態&lt;/h3&gt;
&lt;p&gt;例えば、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ツールウィンドウの開閉状態&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;折りたたみ（Foldout）の ON / OFF&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最後に選択していたタブ&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;こういった「見た目の状態」は、EditorPrefs と非常に相性が良いです。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;bool isOpen = EditorPrefs.GetBool(&amp;quot;MyTool_Foldout&amp;quot;, false);&lt;/code&gt;&lt;/p&gt;</description></item><item><title>💡 【Unity UGUI】Maskを使わずに実現する「穴あき」ハイライト演出</title><link>https://wuyukwi.duckdns.org/posts/zenn-731d17a8464927/</link><pubDate>Mon, 20 Oct 2025 19:24:18 +0900</pubDate><guid>https://wuyukwi.duckdns.org/posts/zenn-731d17a8464927/</guid><description>&lt;blockquote&gt;
&lt;p&gt;📌 &lt;em&gt;この記事は &lt;a href="https://zenn.dev/wuyukwi/articles/731d17a8464927"&gt;Zenn&lt;/a&gt; に投稿した内容のアーカイブです。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="はじめに"&gt;はじめに&lt;/h2&gt;
&lt;p&gt;UGUIで部分的にハイライトを当てたい場面、特に&lt;strong&gt;チュートリアル中の誘導UI&lt;/strong&gt; では「特定のボタンだけを明るく見せ、他の部分を半透明で覆う」演出がよく使われます。&lt;br&gt;
一般的には &lt;code&gt;Mask&lt;/code&gt; や &lt;code&gt;RectMask2D&lt;/code&gt; を利用しますが、これらにはいくつかの課題があります。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Mask&lt;/code&gt;&lt;/strong&gt; ：Stencilバッファを使うため、描画コストが高い&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;RectMask2D&lt;/code&gt;&lt;/strong&gt; ：矩形領域しか扱えず、&lt;strong&gt;穴あき表現（逆マスク）&lt;/strong&gt; はできない&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;そこで今回は、&lt;code&gt;MaskableGraphic&lt;/code&gt; を継承し、&lt;strong&gt;完全プログラム制御で「逆マスク（穴あきマスク）」を生成する方法&lt;/strong&gt; を紹介します。&lt;br&gt;
最終的には、&lt;strong&gt;ハイライト部分がクリック可能で、他の部分はブロックされる&lt;/strong&gt; 、高性能な &lt;code&gt;HollowOutMask&lt;/code&gt; コンポーネントを実装していきます。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="目標仕様"&gt;目標仕様&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;機能&lt;/th&gt;
&lt;th&gt;説明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;視覚効果&lt;/td&gt;
&lt;td&gt;自身の &lt;code&gt;RectTransform&lt;/code&gt; 領域内に半透明のマスクを描画し、指定の &lt;code&gt;RectTransform&lt;/code&gt; 部分を「くり抜く」&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;射線処理&lt;/td&gt;
&lt;td&gt;穴の部分は&lt;strong&gt;クリックが通過&lt;/strong&gt; し、マスク部分は&lt;strong&gt;クリックをブロック&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;動的追従&lt;/td&gt;
&lt;td&gt;対象オブジェクトが動いたりスケールが変化しても、くり抜き領域が追従&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;これを、&lt;code&gt;Mask&lt;/code&gt; 系コンポーネントを使わずに、&lt;strong&gt;頂点操作&lt;/strong&gt; だけで実現します。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="実装の基本構造"&gt;実装の基本構造&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;HollowOutMask&lt;/code&gt; は &lt;code&gt;MaskableGraphic&lt;/code&gt; を継承し、&lt;code&gt;OnPopulateMesh()&lt;/code&gt; をオーバーライドします。&lt;/p&gt;
&lt;h3 id="頂点生成の考え方"&gt;頂点生成の考え方&lt;/h3&gt;
&lt;p&gt;想像してみてください。&lt;br&gt;
マスク全体を表す「外側の矩形（Outer Rect）」と、くり抜く「内側の矩形（Inner Rect）」があるとします。&lt;/p&gt;
&lt;p&gt;この２つの矩形を組み合わせ、外側を塗りつつ内側を抜くには、&lt;strong&gt;8つの頂点&lt;/strong&gt; と&lt;strong&gt;8枚の三角形&lt;/strong&gt; が必要です。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="コード例onpopulatemesh"&gt;コード例：OnPopulateMesh()&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
if (_isTargetNull)
{
base.OnPopulateMesh(vh);
return;
}
// Outer Rect（自身のRectTransform基準）
float outerLx = rectTransform.rect.xMin;
float outerBy = rectTransform.rect.yMin;
float outerRx = rectTransform.rect.xMax;
float outerTy = rectTransform.rect.yMax;
vh.AddVert(new Vector3(outerLx, outerTy), color, Vector2.zero);
vh.AddVert(new Vector3(outerRx, outerTy), color, Vector2.zero);
vh.AddVert(new Vector3(outerRx, outerBy), color, Vector2.zero);
vh.AddVert(new Vector3(outerLx, outerBy), color, Vector2.zero);
// Inner Rect（穴部分）
float innerLx = _targetMin.x;
float innerBy = _targetMin.y;
float innerRx = _targetMax.x;
float innerTy = _targetMax.y;
vh.AddVert(new Vector3(innerLx, innerTy), color, Vector2.zero);
vh.AddVert(new Vector3(innerRx, innerTy), color, Vector2.zero);
vh.AddVert(new Vector3(innerRx, innerBy), color, Vector2.zero);
vh.AddVert(new Vector3(innerLx, innerBy), color, Vector2.zero);
// Triangles（外側と内側の間を埋める）
vh.AddTriangle(0, 1, 5); vh.AddTriangle(5, 4, 0);
vh.AddTriangle(1, 2, 6); vh.AddTriangle(6, 5, 1);
vh.AddTriangle(2, 3, 7); vh.AddTriangle(7, 6, 2);
vh.AddTriangle(3, 0, 4); vh.AddTriangle(4, 7, 3);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで、&lt;strong&gt;中央が透明な「リング状ポリゴン&lt;/strong&gt; を生成できます。&lt;/p&gt;</description></item><item><title>📚 UI開発を10倍速くするための実戦ポイント</title><link>https://wuyukwi.duckdns.org/posts/zenn-143fe2d003d031/</link><pubDate>Thu, 09 Oct 2025 12:11:28 +0900</pubDate><guid>https://wuyukwi.duckdns.org/posts/zenn-143fe2d003d031/</guid><description>&lt;blockquote&gt;
&lt;p&gt;📌 &lt;em&gt;この記事は &lt;a href="https://zenn.dev/wuyukwi/articles/143fe2d003d031"&gt;Zenn&lt;/a&gt; に投稿した内容のアーカイブです。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="はじめに"&gt;はじめに&lt;/h2&gt;
&lt;p&gt;多くの人は「UI開発＝手の速さ」だと思っています。&lt;br&gt;
でも実際のプロジェクトでは、進行を遅らせる原因は&lt;strong&gt;コードの速さではなく、データフローとUI構造設計の悪さ&lt;/strong&gt; です。&lt;/p&gt;
&lt;p&gt;Unity（UGUI）で時間を食う典型的なポイントを挙げると、以下のようになります。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;データ前処理がバラバラ&lt;/strong&gt; ：ソートやフィルタが各UIに散らばっていると、UI層が処理待ちになる。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;階層構造が深すぎる&lt;/strong&gt; ：1回の更新で大量のTransformを走査、処理も重くバグも出やすい。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;アニメーション・状態管理が未抽象化&lt;/strong&gt; ：新しい状態を追加するたびにコードを壊す。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同じランキングUIでも、ある人は半日で完成、ある人は3日かかる。&lt;br&gt;
その差は、手の速さではなく&lt;strong&gt;設計の差&lt;/strong&gt; です。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="データ層とui層を明確に分離する"&gt;データ層とUI層を明確に分離する&lt;/h2&gt;
&lt;p&gt;ありがちなアンチパターンは、&lt;code&gt;OnClick()&lt;/code&gt; の中で&lt;br&gt;
データ取得 → オブジェクト生成 → UI更新を全部やるケース。&lt;/p&gt;
&lt;p&gt;短期的には動いても、UI改修のたびに全部作り直しになります。&lt;/p&gt;
&lt;p&gt;もっと良い設計はこうです👇&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DataService / Manager&lt;/strong&gt; にデータロジックをまとめる&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UI は &lt;strong&gt;DTO（Data Transfer Object）&lt;/strong&gt; を受け取って表示専念&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;データ前処理は Python や外部ツールで事前に済ませる&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;こうすると要件変更が来ても、UI側はほとんど触らずに済みます。&lt;br&gt;
データ層が変わってもUIは安定、これが真の開発効率化です。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="リスト描画はオブジェクトプールが必須"&gt;リスト描画は「オブジェクトプール」が必須&lt;/h2&gt;
&lt;p&gt;ランキング、インベントリ、スキルリストなど、&lt;br&gt;
毎回 &lt;code&gt;Instantiate&lt;/code&gt; ＋ &lt;code&gt;Destroy&lt;/code&gt; していると、&lt;br&gt;
処理が重くなるだけでなく、開発時間も無駄に増えます。&lt;/p&gt;
&lt;h3 id="対策"&gt;対策：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;オブジェクトプールを構築する&lt;/strong&gt; ：&lt;br&gt;
再利用可能なUI要素をキャッシュして、再描画時はデータだけ差し替え。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;シンプルな PoolManager でOK&lt;/strong&gt; ：&lt;br&gt;
使い終わった要素は &lt;code&gt;SetActive(false)&lt;/code&gt; して再利用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ScrollRect の仮想化レンダリングと併用&lt;/strong&gt; ：&lt;br&gt;
数千件でも軽く動作。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;あるプロジェクトでは、インベントリUIの描画時間が&lt;br&gt;
500セルで200ms → プール導入後は30msに短縮。&lt;br&gt;
体感で「カクつき」が消えました。&lt;/p&gt;</description></item><item><title>🔥 ゲームプログラマーとして成長するために大切な3つの力</title><link>https://wuyukwi.duckdns.org/posts/zenn-f6d20f7d12e8b4/</link><pubDate>Thu, 18 Sep 2025 16:43:12 +0900</pubDate><guid>https://wuyukwi.duckdns.org/posts/zenn-f6d20f7d12e8b4/</guid><description>&lt;blockquote&gt;
&lt;p&gt;📌 &lt;em&gt;この記事は &lt;a href="https://zenn.dev/wuyukwi/articles/f6d20f7d12e8b4"&gt;Zenn&lt;/a&gt; に投稿した内容のアーカイブです。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="はじめに"&gt;はじめに&lt;/h2&gt;
&lt;p&gt;「どうすればプログラミングが上手くなるのか？」&lt;br&gt;
これは、ゲーム業界を目指すエンジニアにとって、常につきまとうテーマです。&lt;/p&gt;
&lt;p&gt;Unity や Unreal Engine などの便利なエンジンやライブラリが整っている時代でも、「本当にゲームを作れる」プログラマーになるためには、&lt;strong&gt;言語やフレームワークの知識以上に重要な根本的スキル&lt;/strong&gt; があります。&lt;/p&gt;
&lt;p&gt;本記事では、ゲームプログラマーとして実務を経験する中で特に大事だと感じる&lt;strong&gt;3つの力&lt;/strong&gt; を紹介します。&lt;/p&gt;
&lt;h2 id="-抽象化の力--巨大なコードを分けて考える"&gt;① 抽象化の力 —— 巨大なコードを「分けて」考える&lt;/h2&gt;
&lt;p&gt;ゲーム開発は、数千〜数百万行にもなるコードの集合です。&lt;br&gt;
その全てを頭に入れることは不可能なので、&lt;strong&gt;必要な部分だけをブラックボックスとして扱う&lt;/strong&gt; 考え方が必須になります。&lt;/p&gt;
&lt;p&gt;例えば、「プレイヤーが持つ全ての武器を取得する」処理を作る場合を考えます。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Repositoryパターンによる例
class WeaponRepository {
public List&amp;lt;Weapon&amp;gt; GetAllWeapons(PlayerId playerId);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;この &lt;code&gt;WeaponRepository&lt;/code&gt; クラスを作るときは、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;DBやセーブデータへのアクセス&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ログやエラーハンドリング&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;フォーマット変換&lt;br&gt;
など、たくさんの下位レイヤのライブラリを呼び出しますが、&lt;strong&gt;上のレイヤからは「GetAllWeapons」だけ見えればよい&lt;/strong&gt; のです。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これが抽象化であり、&lt;strong&gt;モジュールを積み重ねて大規模ゲームを成立させる基本&lt;/strong&gt; です。&lt;/p&gt;
&lt;h3 id="実戦ポイント"&gt;実戦ポイント&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;オブジェクト指向（OOP）、関数型（FP）、手続き型といった &lt;strong&gt;複数のパラダイムを状況に応じて使い分ける&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;トップダウン（設計から実装）とボトムアップ（共通処理の抽出）を行き来しながら開発する&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;抽象化しすぎると開発が重くなり、抽象化しなさすぎるとコピペ地獄になるため、バランスを取る&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="-デバッグの力--ブラックボックスを開ける技術"&gt;② デバッグの力 —— ブラックボックスを「開ける」技術&lt;/h2&gt;
&lt;p&gt;抽象化したコードは便利ですが、&lt;strong&gt;バグが起きたときには中を開ける必要&lt;/strong&gt; があります。&lt;/p&gt;
&lt;p&gt;たとえば「インベントリ画面に武器一覧が表示されない」と報告されたとき、どこから原因を追うべきでしょうか？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;F12（DevTools）や &lt;code&gt;curl&lt;/code&gt; でクライアント→サーバ間通信を確認&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;サーバで &lt;code&gt;WeaponRepository.GetAllWeapons()&lt;/code&gt; の戻り値をログ出力&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DBにクエリを直打ちして期待通りの結果か確認&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;こうして&lt;strong&gt;層を一つずつ下って調査&lt;/strong&gt; するのがデバッグの基本です。&lt;br&gt;
このスキルはバグ修正だけでなく、&lt;strong&gt;新しいプロジェクトやチームに参加したときにコードを理解する力&lt;/strong&gt; にもなります。&lt;/p&gt;
&lt;p&gt;実戦ポイント&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ログやアサートを常に入れておく&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;デバッガでステップ実行できるように設計する&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;バグ報告を「再現可能な条件」に落とし込む&lt;/p&gt;</description></item><item><title>💨 Fusionの[Networked]属性はどう動いている？IL変換と自動同期の仕組みを解剖する</title><link>https://wuyukwi.duckdns.org/posts/zenn-79685434adc2f5/</link><pubDate>Wed, 04 Jun 2025 19:50:30 +0900</pubDate><guid>https://wuyukwi.duckdns.org/posts/zenn-79685434adc2f5/</guid><description>&lt;blockquote&gt;
&lt;p&gt;📌 &lt;em&gt;この記事は &lt;a href="https://zenn.dev/wuyukwi/articles/79685434adc2f5"&gt;Zenn&lt;/a&gt; に投稿した内容のアーカイブです。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="はじめに"&gt;はじめに&lt;/h2&gt;
&lt;p&gt;Photon Fusionは、高性能・高柔軟性なネットワーク同期システムを提供する次世代ネットワークライブラリです。&lt;br&gt;
その中でも特に重要な役割を担っているのが、&lt;code&gt;[Networked]&lt;/code&gt; 属性です。&lt;/p&gt;
&lt;p&gt;この属性を使うことで、&lt;strong&gt;プレイヤーの位置やアニメーション状態、ゲーム内オブジェクトの変化&lt;/strong&gt; などを自動的に同期でき、煩雑な手動のデータ送受信処理を省くことができます。&lt;/p&gt;
&lt;p&gt;本シリーズでは、Fusionの内部同期処理を段階的に掘り下げて解説していきますが、今回は、&lt;code&gt;[Networked]&lt;/code&gt; 属性の裏側で何が起きているのか、どのようにして自動同期が実現されているのかを詳しく見ていきます。&lt;/p&gt;
&lt;h2 id="fusionにおけるnetworked属性の同期処理概要"&gt;Fusionにおける[Networked]属性の同期処理概要&lt;/h2&gt;
&lt;h3 id="networked-属性は"&gt;&lt;code&gt;[Networked]&lt;/code&gt; 属性は？&lt;/h3&gt;
&lt;p&gt;Fusionでは、&lt;code&gt;[Networked]&lt;/code&gt; 属性が付与されたプロパティは&lt;strong&gt;ネットワーク状態の同期対象&lt;/strong&gt; として扱われますが、ユーザーが手動で同期コードを書く必要はありません。&lt;br&gt;
この仕組みは、Unityが提供する &lt;strong&gt;ILPostProcessor API&lt;/strong&gt; を活用しており、C# で書かれたコードをビルド後に&lt;strong&gt;IL（中間言語）レベルで自動変換&lt;/strong&gt; しています。&lt;/p&gt;
&lt;p&gt;IL&lt;/p&gt;
&lt;p&gt;ILは、.NET における中間言語です。&lt;br&gt;
Unity では、C# で書いたスクリプトは必ずこの IL を経由してからネイティブコードに変換されます。&lt;/p&gt;
&lt;p&gt;具体的には、以下のような処理が行われます：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;NetworkedWeaved&lt;/code&gt; という属性を追加して、該当プロパティがネットワーク状態バッファに割り当てられることを明示&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;getter/setter が &lt;code&gt;NetworkBehaviour&lt;/code&gt; の内部バッファ（&lt;code&gt;StateBuffer&lt;/code&gt;）への&lt;strong&gt;メモリアクセスに差し替え&lt;/strong&gt; られる&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;実行時に &lt;code&gt;Spawned()&lt;/code&gt; されていない場合のアクセス制限も挿入される&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="変換前のcコード"&gt;変換前のC#コード：&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt; [Networked] private Vector2 _position { get; set; }
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="il変換後ilspyで逆コンパイルしたコード"&gt;IL変換後（ILSpyで逆コンパイルしたコード）：&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;    [Networked]
    [NetworkedWeaved(0, 2)]
    private unsafe Vector2 _position
    {
        get
        {
            if (base.Ptr == null)
            {
                throw new InvalidOperationException(&amp;quot;Error when accessing PhotonCapybara._position. Networked properties can only be accessed when Spawned() has been called.&amp;quot;);
            }
            return (Vector2)base.Ptr[0];
        }
        set
        {
            if (base.Ptr == null)
            {
                throw new InvalidOperationException(&amp;quot;Error when accessing PhotonCapybara._position. Networked properties can only be accessed when Spawned() has been called.&amp;quot;);
            }
            Unsafe.Write(base.Ptr + 0, value);
        }
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="補足解説"&gt;補足解説：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;base.Ptr&lt;/code&gt; は &lt;code&gt;NetworkBehaviour&lt;/code&gt; に割り当てられた&lt;strong&gt;ネットワーク状態メモリの先頭ポインタ&lt;/strong&gt; です。&lt;/p&gt;</description></item></channel></rss>