ルビ設定の実装★【Unity6】

絶対調味ロジック

ルビのインライン設定とオンオフシステムを実装しました。
今回のメッセージ表示(中央からのタイピング)とかなり相性が悪く、
漢字表示時にルビを振ることができなかったため、メッセージ表示後にルビ表示という設定になりました。

ルビシステム

構成ファイル

ファイル種別内容
Sys_RubyRenderer.cs新規ルビ生成・管理
Sys_Messenger.cs追記メッセージ・名前ルビ連携
Sys_TextSettingsManager.cs追記ルビON/OFF設定管理
UI_TextSettingsPanel.cs追記ルビON/OFFボタンUI・プレビュー
Sys_SaveManager.cs修正previewTextのタグ除去

新規スクリプト「Sys_RubyRenderer.cs

テキスト記述形式

Inspector の「conversations[].message」と「charaName」に直接インラインで記述する。

// メッセージ
<r=さとうくん>佐藤君</r><r=じょうほう>情報</r><r=ただ></r>しければ…
// 名前
<r=いとう>伊藤</r>

オブジェクト構成

Msg_Panel(既存メッセージパネル
 ├── Msg_text(既存・TMP本体)
 ├── RubyRoot(Sys_RubyRendererが動的生成)
 │    └── Ruby_xxx(ルビ1つにつき1個・動的生成)
 └── Msg_Panel_Wait_Icon(既存)

Name_Plate(既存ネームプレート
 ├── Name_Text(既存・TMP本体)
 └── RubyRoot(Sys_RubyRendererが動的生成)
     └── Ruby_xxx(動的生成)

PreviewWindowテキスト設定・プレビュー
 ├── PreviewMessage(既存・TMP本体)
 └── RubyRoot(Sys_RubyRendererが動的生成)
      └── Ruby_xxx(動的生成)

Unity上のアサイン設定

コンポーネントフィールドアサイン先
Sys_MessengerrubyRendererMsg_Panel の Sys_RubyRenderer
Sys_MessengernameRubyRendererName_Plate の Sys_RubyRenderer
UI_TextSettingsPanelpreviewRubyRendererPreviewWindow の Sys_RubyRenderer
UI_TextSettingsPanelbtnRubyOnルビONボタン
UI_TextSettingsPanelbtnRubyOffルビOFFボタン

処理フロー

メッセージ

OnEnable
 → rubyRenderer.Initialize(messageText)
 → nameRubyRenderer.Initialize(charaNameText)
 → RubyRootを動的生成(既存なら再利用)
 → SYS_RUBY_VISIBLEからON/OFF状態を復元

ShowNextMessage(次メッセージへ進む前)
 → rubyRenderer.Clear()
 → nameRubyRenderer.Clear()
 → charaNameText.text = StripRubyTags(charaName)
 → nameRubyRenderer.Render(charaName, charaNameText)

DisplayMessage(タイピング処理)
 → plainText = StripRubyTags(text) でタグ除去
 → plainTextでタイピング表示
 → タイピング完了後
 → rubyRenderer.Render(text, messageText)

スキップ時
 → messageText.text = plainText で即時全文表示
 → rubyRenderer.RenderAll(messageText) で一括生成

FinishConversation
 → nameRubyRenderer.Clear()

プレビュー

① UI_TextSettingsPanel.Start()
 → previewRubyRenderer.Initialize(previewMessageText)

② PreviewLoop()
 → plainTextでタイピング表示
 → タイピング完了後
 → previewRubyRenderer.Render(PREVIEW_TEXT, previewMessageText)
 → AutoWait後にpreviewRubyRenderer.Clear()
 → ループ

ON/OFF管理

項目内容
保存キーSYS_RUBY_VISIBLE
保存先global_system.json
デフォルトON(true)
切り替えUI_TextSettingsPanel のボタン2つ
即時反映rubyRoot.SetActive() で現在表示中のルビに反映

現状の制約

制約内容
表示タイミングタイピング完了後に一括表示
同一文字列前方から順に対応
自動改行またぎ非対応
縦書き非対応

未解決の課題(将来対応?)

ルビ表示タイミングの改善
「漢字表示直後にルビを出す」実装を試みたが、
メッセージパネルが中央から広がる演出との座標同期が困難で断念。

解決するには以下のいずれかが必要。

  • パネルの広がり演出を廃止して固定幅にする
  • タイピング中のパネルサイズ変化をルビ座標に毎フレーム反映する

左揃えテキストであればタイピング中の逐次表示が可能。
中央揃えのみ困難。

実機での挙動

やはりメッセージ後に一括表示は違和感があります。
左揃えスタートの場合は、タイミングも位置もうまくいったので、
中央スタートとトレードオフとなっている状況ですね。

現状では、Claudeでも限界難易度になっていたので、今回は妥協するしかないようです。

改善★0515

やはりルビ表示のタイミングが気になったので、漢字表示終了のタイミングでルビ表示するようにしました。
テキスト中央揃え・パネル中央から左右に広がる」条件だと出来なかったので、
テキスト左揃え」に条件を変え、さらにこの塊を「親オブジェクトの中央に表示」という条件をつけたしました。

中央揃えがダメならば、左揃えのテキスト全体を中央に表示させる、という方向にシフトしました。

  • ADVメッセージ進行の正常化(1クリック進行の復旧)※修正中に起こった不具合
  • ルビ表示およびパネル可変演出のパフォーマンス最適化
  • 左揃えを維持した状態でのパネル中央配置の簡略化

Hierarchy構造

Msg (Canvas基準の中央オブジェクト)
└── ImagePanel (背景Image)
    └── Text (TextMeshPro) ※ImagePanelの子に配置

Inspector設定

ImagePanel
Anchor:Middle Center
PivotX=0.5, Y=0.5(中央に変更)
Pos X:0(コードによる座標計算を廃止)

Text (TextMeshPro)
Anchor:Middle Center(または Stretch-Stretch)
Pivot:X=0, Y=0.5
Alignment:Left, Middle
MarginsTMPのExtra Settings (Margin) で左右余白を設定
 これにより preferredWidth に余白が含まれ、パネルサイズに自動反映される。

コード変更点 (Sys_Messenger.cs)

進行バグの修正 (DisplayMessage):ループ終了直後にフラグを正常化し、1クリックで次へ進むように修正。

// ループ終了後
isDisplayingMessage = false; // ★追加:進行不能バグの解消
isMessageCompleted = true;

最適化されたリサイズ処理 (UpdatePanelSize)
ForceMeshUpdate() を廃止し、Pivot 0.5 を活かしたシンプルなサイズ更新のみに限定。

void UpdatePanelSize()
{
    if (resizeMessagePanel && messagePanelRect != null && messageText != null)
    {
        float w = messageText.preferredWidth;

        // サイズに変化がある時だけ適用(負荷軽減)
        if (Mathf.Abs(messagePanelRect.sizeDelta.x - w) > 0.1f)
        {
            messagePanelRect.sizeDelta = new Vector2(w, messagePanelRect.sizeDelta.y);
            // Pivot 0.5 のため座標更新 (anchoredPosition) は不要
        }
    }
}

動作原理

  1. 進行制御:文字表示中のみ isDisplayingMessage を true に保ち、終了時に false へ戻すことで、
    次クリックが「スキップ」ではなく「次行表示」として正しく判定される。
  2. 中央配置:ImagePanel の Pivot を 0.5 に設定。
    これにより、スクリプトで sizeDelta.x を変更するだけで、パネルは座標計算なしで自動的に左右均等に広がり、常に中央を維持する。
  3. 余白 (Padding):スクリプト側での加算処理を廃止。
    TMPコンポーネント側の Margin設定 を参照することで、左揃えを維持したまま、左右に均等なスペースを含んだパネルサイズが計算される。

留意点

  • horizontalPadding フィールドは不要になったため削除済み。
  • パネルの最小幅を固定したい場合は、
    エディタ側で Layout Element の Min Width を使うか、コードで Mathf.Max を使用することを推奨。

コメント