共有・サイズ固定・追従型ネームプレートの実装【Unity6】

絶対調味ロジック

ふと、キャラクターネーム表示を「MMO」っぽくしてみようと思いたちました。
所属部活を「クラン」のようにも表示してみようかなと。
Aiには「ADVでそれやると視線が定まらなくなる」と怒られつつも強行突破です。

単純にUI画面で「名前プレート」を設置だと、
カメラ位置(引き寄り)によってキャラクターとの距離が定まらなくて位置の違和感があります。

キャラクターの子オブジェクトに名前プレートを設置もやってみましたが、
こちらは追従はできるものの、やはりカメラ位置によっては、今度はサイズがバラバラになります。

これは想定よりも意外に難しそうです。
UIオブジェクトと通常オブジェクトの連携になるので、それなりのシステムが必要と判断し本腰を入れます。

ChtatGPTにて勧められた「World Space UI方式(MMO型)」というのを実装してみました。
これでもまぁ良かったのですが、カメラ位置でのズレが若干気になっていたので、
Claudeにて変更案の「Screen Space UI + WorldToScreenPoint方式」というので再実装しました。

追従型ネームプレートの設計図

目的

  • 2.5D ADVにてキャラクターの頭上にネームプレートを正確に表示する
  • 同キャラクター・複数ポーズに共通のネームプレートを表示させる

採用方式・採用理由

Screen Space UI + WorldToScreenPoint方式

  • WorldSpace UI方式 → Perspectiveカメラの歪みでズレが発生するため却下
  • WorldToScreenPoint → ワールド座標をスクリーン座標に変換するためズレが原理的に発生しない

全体構成

Scene
 ├ ito_normal(ポーズPrefab
 │ ├ Ma_ito_normal_eye
 │ ├ Ma_ito_normal_mo
 │ ├ Ma_ito_normal_main
 │ ├ ito_N_Anchor(空Object・頭上に配置)
 │ └ Sys_AnchorSync
 │     myAnchor → ito_N_Anchor
 │     characterID → “ito
 │
 ├ ito_End(ポーズPrefab
 │ └ 同上構成・characterID → “ito“(共通)
 │
 ├ ito_battle(ポーズPrefab
 │ └ 同上構成・characterID → “ito“(共通)
 │
 └ UICanvas(Screen Space Overlay・Scene共通1枚)
  └ Ito_Plate(非アクティブ初期状態)
  └ Sys_NamePlateScreen ← characterID → “ito

新規スクリプト

Sys_AnchorSync

ポーズPrefabのルートにアタッチ。
OnEnableのタイミングで対応するPlateにアンカーを登録する。

Sys_NamePlateScreen

UICanvas内のPlateにアタッチ。
毎フレームアンカーのワールド座標をスクリーン座標に変換して位置を更新する。

キャラクター追加時の手順

Anchor(空Object)を追加

ポーズ PrefabAnchor(空Object)を追加し、頭上(任意)に配置します。

Sys_AnchorSync をアタッチ

ポーズ Prefab(親オブジェクト)に Sys_AnchorSync をアタッチし、
自身の基準アンカーと共通させる characterID を設定します。

Sys_NamePlateScreen をアタッチ

UICanvasの名前プレートSys_NamePlateScreen をアタッチし、
Sys_AnchorSync で設定した同じ characterID を設定します。

実機での見た目

ビルド後のアプリで実際に確認してみます。

カメラ位置によって、多少のズレはありますが、追従かつサイズ固定は成功しています。
実際のMMOでもキャラクターとの位置はカメラによって変わるので、こんなものでしょうか。

本格MMO式を取り入れようとすると、より複雑になりそうだったので今回は我慢です。
ちょっとした思い付きでしたが、なかなかに時間をとられたのが想定外でした。

同じキャラクター・ポーズ差分での共有という条件もあったので、
そこもちょっと時間がかかった要因になりました。

表示されている部活マークが気に入っています(*´ω`*)

改善★0411

問題

解像度変更(960×540 / 1280×720 / 1600×900)でPlateの位置がずれる

原因

WorldToScreenPoint はピクセル座標を返すため解像度に依存する。
解像度が下がるほどPlateが頭上から離れる挙動が発生。

解決

WorldToViewportPoint で0〜1の正規化座標に変換し、Canvas解像度を掛けて配置。
解像度変化の影響を受けなくなった。

WorldToScreenPoint  → ピクセル座標(解像度依存)→ ズレる
WorldToViewportPoint → 0〜1正規化座標(解像度非依存)→ ズレない

変更箇所

Sys_NamePlateScreen のLateUpdateのみ

コメント