Unityに関連する記事です

 この記事は、LayoutGroup を利用した自動調整機能において
Slider を持つコンポーネントが LayoutGroup 内に含まれている場合に、各UI 用ゲームオブジェクトの位置を動的に自動調整する方法の実装例です。
同様に ScrollView を持つコンポーネントにも応用可能です。





 ポイントとしては Slider のサイズを Scale ではなく Width で調整することにより、UI 画像の 9 Slice にも対応している部分です。
(実装するとわかりますが、Scale を変更してサイズを変えると 9 Slice が有効になりません。)



 なお。LayoutGroup 内に Slider や ScrollView などの子オブジェクトを複数持つ UI が含まれていない場合には、下記の記事を参考にすることで機能実装できます。
【ハルシオンブログ】様
Layoutグループの中で、ほかのオブジェクトのサイズが変わったときに自動で他のオブジェクトの位置を調整する方法
http://halcyonsystemblog.jp/blog-entry-1045.html



設計


 Unity では UI の自動整列機能として LayoutGroup があります。
例えば、Image と Text を横一列に表示させ、その後、Text や Image の横サイズの変更に応じて
各オブジェクトの位置を自動調整する、というような使い方です。

 これは LayoutGroup をアタッチしただけでは実装が行えません。
LayoutGroup の設定のほか、制御下となる各子オブジェクトにも設定が必要となります。

 ここでは参考用に UI を作成し、かつ、それを動的に変化させるサンプルのスクリプトを用意して動作検証を行います。

 特に重要な点が Slider を持つコンポーネントが LayoutGroup 内に含まれている場合の挙動です。
Slider には子オブジェクトがあり、それらの各サイズの調整も必要になります。
これは ScrollView も同様です。


UI 制作 参考例


 ここではサンプルを提示します。

 LayoutGroup を利用して、Slider を子オブジェクトに含めてもられば、サイズや構成については、自由に作成してもらって構いません。
サンプルでは HorizontalLayoutGroup で実装していますが、VerticalLayoutGroup でも問題ありません。


全体構成


 2D 用の敵役のゲームオブジェクトの構成例です。
白い画像部分には Body ゲームオブジェクトで指定した画像が配置されます。

 敵のオブジェクトに追従して表示するため、ワールドスペース内に Canvas を配置し、Hp 用のゲージを Slider で、アイコンを Image で作成しています。








Canvas


 Render Mode はワールドスペースでの利用を目的としていますが、従来の Overlay でも応用可能です。

 CanvasGroup コンポーネントをアタッチし、子オブジェクトをまとめて管理できるようにしています。





LayoutGroup 用オブジェクト


 Canvas 内で Create Empty して作成し、HorizontalLayoutGroup をアタッチして設定しています。
Spacing のサイズについては適宜調整してください。子オブジェクト同士の間が空きます。
また Use Child Size の Width にのみチェックを入れて、子オブジェクトの Width を操作できるようにしています。

 またこのゲームオブジェクト自体の Width と Height の値が HorizontalLayoutGroup が自動調整可能な範囲になります。
今回であれば、Slider 最大の伸縮幅を見越して大きさを設定してください。

 このオブジェクトが UI の親オブジェクトとなりますので、このオブジェクトの Scale が子オブジェクトにも適用されます。
よって、Scale の値はいじらず、必ず、すべて 1 に設定してください








Image


 LayoutGroup 内に配置する Image です。ほかの UI でも問題ありません(ただし、子オブジェクトを持たない UI にしてください)。

 今回、このオブジェクトのサイズは変更しない前提です。
そのため、次に作成する Slider のサイズに合わせて、位置だけが自動調整される形での実装になります。

 タップ感知は行いませんので、Raycast Target はオフにしてください。

 ContentSizeFitter コンポーネント、LayoutElement コンポーネントをアタッチして設定を行っています。

 ContentSizeFitter では横方向の位置のみ可変できるように HorizontalFit のみ Min Size として、サイズは一定に保つようにします。

 LayoutElement では、サイズの最小値を設定しています。








Slider


 今回の実装のメインとなる目的のオブジェクトです。
こちらのサイズがゲーム内で変更されるため、それを自動調整できるようにします。
Slider と同様に、子オブジェクトを持つ UI であれば、ScrollView などにも応用が可能です。

 LayoutElement コンポーネントをアタッチし、Min Width には最小時の Slider サイズを設定しておきます。









 参考用に Slider の子オブジェクトについても掲載します。
フレーム、およびゲージ内に利用する画像には 9 Slice を設定してください。

























手動で機能確認を行う


 Scene ビュー内で手動で Slider の Width を変更してサイズを変えます。
この際、LayoutGroup の機能により、横一列に並んでいる Image と Slider が一緒に動き、位置が変更されれば成功です。

 常に Image が左側に来るようになっているか、Slider のサイズが中央から変更されている
UI 画像の 9 Slice が対応していることを確認してください。





 この時点で正常に動作していない場合には、次のスクリプトを利用して動的に変更した場合にも正常に動作しません
しっかりとチェックし、問題点がないか、見直してください。


サンプルスクリプト

1.SliderViewBase


 初期設定として、Slider のサイズを変更する機能に加えて、
ワールドスペース用にカメラを取得する機能、
DOTween を利用し、Hp のゲージが変化する機能も記載しています。


SliderViewBase.cs

<= クリックすると開きます。



2.HpSlider


 【1】で作成した SliderViewBase クラスを継承して Hp 用の Slider の管理専用のクラスを作成します。


HpSlider.cs

<= クリックすると開きます。



3.EnemyBase


 上記の HpSlider を利用するスクリプトです。


EnemyBase.cs

<= クリックすると開きます。




EnemyBase スクリプトと HpSlider スクリプトをアタッチして設定を行う


 ここでは敵役のゲームオブジェクトに EnemyBase スクリプトと HpSlider スクリプトをアタッチし、アサイン先の設定を行っています。

 ただし、アサインにて制御先を設定しますので、いずれのゲームオブジェクトにアタッチしても問題はありません。






ゲームを実行して動作確認を行う


 ゲームを実行し、Slider のサイズが EnemyBase の SliderWidthSize で設定した値に変更となり、
かつ、HorizontalLayoutGroup 内の位置が自動で更新されて、手動で設定した場合と同じ挙動になっていれば制御成功です。

 処理のポイントは HpSlider 内の SetSliderSize メソッドの内容です。


    /// <summary>
    /// Slider のサイズを設定
    /// HorizontalLayoutGroup 内に Slider を利用しているとサイズを変えただけでは画面に反映されない
    /// そのため override して更新方法を変えている
    /// </summary>
    /// <param name="guageLength"></param>
    public override void SetSliderSize(float guageLength) {

        // Canvas 内の表示更新
        Canvas.ForceUpdateCanvases();

        // SizeDelta 取得し、Size 用の値を設定
        RectTransform sliderRect = slider.transform as RectTransform;
        Vector2 size = new(sliderRect.sizeDelta.x * guageLength, sliderRect.sizeDelta.y);

        // SizeDelta 更新(Scale でサイズ変えると 9 slice が利かない)
        (slider.transform as RectTransform).sizeDelta = size;
        //Debug.Log($"Size {(slider.transform as RectTransform).sizeDelta.x} : {(slider.transform as RectTransform).sizeDelta.y}");

        // レイアウト内の入力値を再計算
        horizontalLayoutGroup.CalculateLayoutInputHorizontal();

        // レイアウト再設定(表示更新)
        horizontalLayoutGroup.SetLayoutHorizontal();
    }

 ,泙査能蕕 Canvas.ForceUpdateCanvases()が呼び出され、キャンバスとその子要素が更新されます。
通常 Canvas 内のオブジェクトの表示更新は 1フレームまたぐ必要がありますが、このメソッドを実行することで即座に更新されます。

 Slider の SizeDelta を取得し、計算した結果を代入することでスライダーのサイズが変更されます。
RectTransfrom コンポーネントは GetComponent メソッドを利用せずとも、transform に対して as RectTransfrom を実行することで取得可能です。
Scale ではなく SizeDelta の Width に対してサイズの変更を行う部分が重要です。そうすることで 9 Slice 機能が有効に働きます。

 horizontalLayoutGroup?.CalculateLayoutInputHorizontal()が呼び出され、水平方向のレイアウトの入力が再計算されます。
これにより、HorizontalLayoutGroup 内の Slider のサイズと、その子オブジェクトのサイズが再計算されます。

 ず埜紊 horizontalLayoutGroup?.SetLayoutHorizontal()が呼び出され、水平方向のレイアウトが再設定され、UI要素が描画される更新が行われます。

 以上の処理の内容により、この順序で処理を行うことで、UI要素のサイズ変更が正常に画面に反映されるようになります。

 特に LayoutGroup 利用時の Slider のサイズ動的な更新においては、´↓い僚萢と、その実行する順番が重要です。
Slider には子オブジェクトがあるため、この処理を適切な順番で実行することにより、LayoutGroup 内の各オブジェクトの位置を動的に自動調整することが可能です。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3Dレールガンシューティング(応用編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



このサイト内の作品はユニティちゃんライセンス条項の元に提供されています。

管理人/副管理人のみ編集できます