📚 UI開発を10倍速くするための実戦ポイント

📌 この記事は Zenn に投稿した内容のアーカイブです。 はじめに 多くの人は「UI開発=手の速さ」だと思っています。 でも実際のプロジェクトでは、進行を遅らせる原因はコードの速さではなく、データフローとUI構造設計の悪さ です。 Unity(UGUI)で時間を食う典型的なポイントを挙げると、以下のようになります。 データ前処理がバラバラ :ソートやフィルタが各UIに散らばっていると、UI層が処理待ちになる。 階層構造が深すぎる :1回の更新で大量のTransformを走査、処理も重くバグも出やすい。 アニメーション・状態管理が未抽象化 :新しい状態を追加するたびにコードを壊す。 同じランキングUIでも、ある人は半日で完成、ある人は3日かかる。 その差は、手の速さではなく設計の差 です。 データ層とUI層を明確に分離する ありがちなアンチパターンは、OnClick() の中で データ取得 → オブジェクト生成 → UI更新を全部やるケース。 短期的には動いても、UI改修のたびに全部作り直しになります。 もっと良い設計はこうです👇 DataService / Manager にデータロジックをまとめる UI は DTO(Data Transfer Object) を受け取って表示専念 データ前処理は Python や外部ツールで事前に済ませる こうすると要件変更が来ても、UI側はほとんど触らずに済みます。 データ層が変わってもUIは安定、これが真の開発効率化です。 リスト描画は「オブジェクトプール」が必須 ランキング、インベントリ、スキルリストなど、 毎回 Instantiate + Destroy していると、 処理が重くなるだけでなく、開発時間も無駄に増えます。 対策: オブジェクトプールを構築する : 再利用可能なUI要素をキャッシュして、再描画時はデータだけ差し替え。 シンプルな PoolManager でOK : 使い終わった要素は SetActive(false) して再利用。 ScrollRect の仮想化レンダリングと併用 : 数千件でも軽く動作。 あるプロジェクトでは、インベントリUIの描画時間が 500セルで200ms → プール導入後は30msに短縮。 体感で「カクつき」が消えました。 ...

2025年10月9日 · 1 分 · 133 文字 · Wuyukwi

🔥 ゲームプログラマーとして成長するために大切な3つの力

📌 この記事は Zenn に投稿した内容のアーカイブです。 はじめに 「どうすればプログラミングが上手くなるのか?」 これは、ゲーム業界を目指すエンジニアにとって、常につきまとうテーマです。 Unity や Unreal Engine などの便利なエンジンやライブラリが整っている時代でも、「本当にゲームを作れる」プログラマーになるためには、言語やフレームワークの知識以上に重要な根本的スキル があります。 本記事では、ゲームプログラマーとして実務を経験する中で特に大事だと感じる3つの力 を紹介します。 ① 抽象化の力 —— 巨大なコードを「分けて」考える ゲーム開発は、数千〜数百万行にもなるコードの集合です。 その全てを頭に入れることは不可能なので、必要な部分だけをブラックボックスとして扱う 考え方が必須になります。 例えば、「プレイヤーが持つ全ての武器を取得する」処理を作る場合を考えます。 // Repositoryパターンによる例 class WeaponRepository { public List<Weapon> GetAllWeapons(PlayerId playerId); } この WeaponRepository クラスを作るときは、 DBやセーブデータへのアクセス ログやエラーハンドリング フォーマット変換 など、たくさんの下位レイヤのライブラリを呼び出しますが、上のレイヤからは「GetAllWeapons」だけ見えればよい のです。 これが抽象化であり、モジュールを積み重ねて大規模ゲームを成立させる基本 です。 実戦ポイント オブジェクト指向(OOP)、関数型(FP)、手続き型といった 複数のパラダイムを状況に応じて使い分ける トップダウン(設計から実装)とボトムアップ(共通処理の抽出)を行き来しながら開発する 抽象化しすぎると開発が重くなり、抽象化しなさすぎるとコピペ地獄になるため、バランスを取る ② デバッグの力 —— ブラックボックスを「開ける」技術 抽象化したコードは便利ですが、バグが起きたときには中を開ける必要 があります。 たとえば「インベントリ画面に武器一覧が表示されない」と報告されたとき、どこから原因を追うべきでしょうか? F12(DevTools)や curl でクライアント→サーバ間通信を確認 サーバで WeaponRepository.GetAllWeapons() の戻り値をログ出力 DBにクエリを直打ちして期待通りの結果か確認 こうして層を一つずつ下って調査 するのがデバッグの基本です。 このスキルはバグ修正だけでなく、新しいプロジェクトやチームに参加したときにコードを理解する力 にもなります。 実戦ポイント ログやアサートを常に入れておく デバッガでステップ実行できるように設計する バグ報告を「再現可能な条件」に落とし込む ...

2025年9月18日 · 1 分 · 102 文字 · Wuyukwi

💨 Fusionの[Networked]属性はどう動いている?IL変換と自動同期の仕組みを解剖する

📌 この記事は Zenn に投稿した内容のアーカイブです。 はじめに Photon Fusionは、高性能・高柔軟性なネットワーク同期システムを提供する次世代ネットワークライブラリです。 その中でも特に重要な役割を担っているのが、[Networked] 属性です。 この属性を使うことで、プレイヤーの位置やアニメーション状態、ゲーム内オブジェクトの変化 などを自動的に同期でき、煩雑な手動のデータ送受信処理を省くことができます。 本シリーズでは、Fusionの内部同期処理を段階的に掘り下げて解説していきますが、今回は、[Networked] 属性の裏側で何が起きているのか、どのようにして自動同期が実現されているのかを詳しく見ていきます。 Fusionにおける[Networked]属性の同期処理概要 [Networked] 属性は? Fusionでは、[Networked] 属性が付与されたプロパティはネットワーク状態の同期対象 として扱われますが、ユーザーが手動で同期コードを書く必要はありません。 この仕組みは、Unityが提供する ILPostProcessor API を活用しており、C# で書かれたコードをビルド後にIL(中間言語)レベルで自動変換 しています。 IL ILは、.NET における中間言語です。 Unity では、C# で書いたスクリプトは必ずこの IL を経由してからネイティブコードに変換されます。 具体的には、以下のような処理が行われます: NetworkedWeaved という属性を追加して、該当プロパティがネットワーク状態バッファに割り当てられることを明示 getter/setter が NetworkBehaviour の内部バッファ(StateBuffer)へのメモリアクセスに差し替え られる 実行時に Spawned() されていない場合のアクセス制限も挿入される 変換前のC#コード: [Networked] private Vector2 _position { get; set; } IL変換後(ILSpyで逆コンパイルしたコード): [Networked] [NetworkedWeaved(0, 2)] private unsafe Vector2 _position { get { if (base.Ptr == null) { throw new InvalidOperationException("Error when accessing PhotonCapybara._position. Networked properties can only be accessed when Spawned() has been called."); } return (Vector2)base.Ptr[0]; } set { if (base.Ptr == null) { throw new InvalidOperationException("Error when accessing PhotonCapybara._position. Networked properties can only be accessed when Spawned() has been called."); } Unsafe.Write(base.Ptr + 0, value); } } 補足解説: base.Ptr は NetworkBehaviour に割り当てられたネットワーク状態メモリの先頭ポインタ です。 ...

2025年6月4日 · 1 分 · 187 文字 · Wuyukwi