🔟

あんさんぶるスターズ!!10周年UIアップデートで導入したコード自動生成とプレビュー機能

に公開

はじめに

あんさんぶるスターズ!!(以下、あんスタ)では、10周年を機に大規模なUIアップデートを実施しました。
Bright me up!! 10周年記念特設サイト|あんさんぶるスターズ!!

この記事では、このUIアップデートで導入したコード自動生成とプレビュー機能をご紹介します。デザイナーがプレハブ作成後にコード生成することで動作確認まで完結でき、エンジニアを待たずに先行して開発できるワークフローを実現しました。

従来の問題点

あんスタのUIアップデート前は、以下のような課題がありました。

1. 複数アプリへのUIの組み込みの課題

あんスタでは複数のアプリ(あんさんぶるスターズ!!Basic・あんさんぶるスターズ!!Music、以下Basic・Music)で共通UIを使用していますが、従来は以下のようなワークフローで開発していました。

共通UIの更新のたびに各アプリへ更新されたUIを同期し、さらに同期後も各アプリ専用のコンポーネントをアタッチする作業が発生していました。
また、UIの同期後は各アプリ側で実装することになっていたので、同じ見た目のUIでも細かい部分で動作が違っていたりして、QA後にどちらかのアプリの動作に寄せるみたいなことが頻繁におきていました。

参考: Nested Prefabを活用した、あんスタ!!MusicのUI実装

2. UIの動作確認までの課題

デザイナーがプレハブを作成した後、実際の動作を確認するにはエンジニアによる以下の作業が必要でした。

  • 専用コンポーネント(スクリプト)の作成
  • UI要素の参照を手動で専用コンポーネントにアサイン
  • アプリへの組み込み

これらが完了しないと実際の動作確認ができず、デザイナーはプレハブで見た目だけ作成、以降のUI調整はエンジニアが行うようなワークフローになっていました。

10周年UIアップデートでのワークフロー

上記のような課題があったため、10周年UIアップデートでは次のようなワークフローにしてデザイナーとエンジニアがそれぞれ作業しやすいようなワークフローにしました。

ステップ1: デザイナーがプレハブを作成

  1. ルートになるプレハブを作成し、EsText、EsImage、EsButtonなどのUI要素を配置します
  2. 各UI要素にインスペクターからコード生成に必要な項目を入力します
  3. アニメーションはTimelineで専用のトラックとクリップを使って設定します
EsPlayerInfoView
  ├─ CharacterImage (EsImage)
  ├─ PlayerNameText (EsText) ※string型で出力
  ├─ LevelText (EsText) ※int型で出力
  └─ CloseButton (EsButton)

ステップ2: コード生成

UI Component Generator

専用のエディター拡張ウィンドウや右クリックからコード生成を実行することで、以下のような2つのファイルが生成されます。

EsPlayerInfoView.Generated.cs
// EsPlayerInfoView.Generated.cs(自動生成・常に上書き)
public partial class EsPlayerInfoView : EsView<EsPlayerInfoView.ViewState>
{
    [SerializeField] private EsImage _characterImage = null!;
    [SerializeField] private EsText _playerNameText = null!;
    [SerializeField] private EsText _levelText = null!;
    [SerializeField] private EsButton _closeButton = null!;

    // ボタンクリックイベントの購読/解除、イベント発行など

    [Serializable]
    public partial class ViewState : EsViewState
    {
        public Sprite CharacterSprite;
        public string PlayerName;
        public int Level;
    }

    protected override void RefreshGenerated()
    {
        _characterImage.SetSprite(State.CharacterSprite);
        _playerNameText.SetText(State.PlayerName);
        _levelText.SetText(State.FormattedLevel)
    }
}
EsPlayerInfoView.cs
// EsPlayerInfoView.cs(手動編集・初回のみ生成)
public partial class EsPlayerInfoView
{
    // [SerializeField]など手動で追加してもOK

    public partial class ViewState
    {
        public long PlayerId; // 必要なフィールドは手動で追加してOK
        public string FormattedLevel => NumberFormatter.WithDelimiter(Level); // 表示用に変換が必要なものも手動で書く
    }

    protected override void OnRefresh()
    {
        // カスタムロジック
    }

    protected override void OnPreview(ViewState previewState)
    {
        // プレビュー用のデータ構築(必要に応じて実装)
    }
}

自動生成コード(.Generated.cs)は各UI要素に設定した項目から自動的に生成され、基本的に編集を行わないファイルです。
また、コード生成と同時に対象プレハブのルートオブジェクトに生成されたコンポーネントが自動でアタッチされ、SerializeFieldへの参照も自動でアサインされるようになっているので、手動でのドラッグ&ドロップ操作は一切不要としました。
Timelineで設定したアニメーションも同様の機能によりDoTweenのコードに変換されたものが自動で生成されます。

ステップ3: デザイナーの動作確認

対象プレハブを選択しインスペクターからプレビュー用のデータを設定することで、エンジニアを待たずにUIの動作確認ができます。
(ViewStateに[Serializable]属性を付けているため、インスペクターから直接編集が可能)

プレビュー用のシーンではプレハブ単体で再生モードに入ることができ、入力イベント、SE設定、アニメーションなどの動作確認が行えます。
また、プレビュー用データに「通常」「エラー」「空データ」など、複数の状態パターンを設定して再生中に切り替えて確認することもできます。

プレビュー機能

ステップ4: エンジニアがロジックを実装

必要に応じてエンジニアが手動編集ファイル(.cs)にロジックを実装します。

EsPlayerInfoView.cs
public partial class EsPlayerInfoView
{
    protected override void OnRefresh()
    {
        // カスタムロジック(アニメーション、複雑な表示制御など)
    }

    protected override void OnPreview(ViewState previewState)
    {
        // リスト画面など動的に要素を生成する場合はエンジニアがコードを記述
        State = previewState;
        Refresh();
    }
}

自動生成コード(.Generated.cs)と手動編集コード(.cs)は分離されているためコード再生成時も手動コードは変更されず、エンジニアが実装したコードはそのまま残ります。
また、各アプリではViewStateに表示したいデータを詰めてRefresh()を呼ぶような作りにしているので、各アプリのエンジニアは「何を表示するか」だけに、UI側は「どう表示するか」だけに集中できます。

ステップ5: 各アプリへの同期

共通UIリポジトリで実装したプレハブとスクリプトを各アプリリポジトリに同期します。

BasicとMusicでは一部の機能やUI要素が異なるため、共通UIリポジトリではタグとフォルダでアプリ専用要素を管理しています。

フォルダ構成とタグによる管理

Assets/EsUI/Features/
  └─ PlayerInfo/
      ├─ EsPlayerInfoView.prefab  (共通プレハブ)
      ├─ ForBasic/                (Basic専用要素)
      └─ ForMusic/                (Music専用要素)

同期後、各アプリで不要な要素が自動的に削除されます。

  • タグによる削除: プレハブ内の EsBasic / EsMusic タグが付いたGameObjectを削除
    • Basicへの同期時 → EsMusic タグのオブジェクトを削除
    • Musicへの同期時 → EsBasic タグのオブジェクトを削除
  • フォルダによる削除: ForBasic/ / ForMusic/ フォルダを削除
    • Basicへの同期時 → ForMusic/ フォルダごと削除
    • Musicへの同期時 → ForBasic/ フォルダごと削除

この仕組みにより、同期するだけで各アプリに最適化されたUIが自動的に構築されます。

まとめ

あんスタ10周年UIアップデートでこの仕組みを導入した結果、以下のような改善を実現しました。

デザイナー

  • エンジニアを待たずに独立して作業可能
  • プレビュー用のデータを使い再生モードでの動作確認(ボタンクリック、SE、アニメーション)
  • 動作確認までの時間を大幅に短縮

エンジニア

  • partial classによる自動生成コードと手動コードの分離
  • コード自動生成により参照のアサイン作業などを削減
  • 複数アプリへの自動最適化

おわりに

いかがでしたでしょうか。

あんスタ10周年UIアップデートで導入したコード自動生成とプレビュー機能についてご紹介しました。

Unity の UI 開発で似たような課題を抱えている方の参考になれば幸いです。

GitHubで編集を提案
Happy Elements

Discussion