見出し画像

【Unity】スクロールビューに表示するテキストの長さがランダムに変わるときの設定

今回は以下の記事の追記です。

「答えろ!!プロ野Q」を開発中!

現在、プロ野球クイズゲーム「答えろ!!プロ野Q」を開発中です。
楽しく開発できてます!

このゲームの解説用テキストを表示するのにスクロールビューを使用したのですが、少し手間取ったので記事に残します。
かなり汎用性もあると思います。
ちなみに解説文はこんなのです。

ワシの現役時代は180kmは出ていた

スクロールビュー(Scroll View)の調整内容

1.Scroll Rect

・RectTransformはセンタリング
・水平(Horizontal)のチェックは外す
・水平スクロールバーは不要
・移動タイプはクランプがおすすめ

2.Viewport

・Rect TransformはStretch
・Maskコンポーネントをアタッチ

3.Content

・Rect Transformのアンカーは左上
・Content Size Fitterをアタッチ、垂直調節をPreferred Sizeに
・Vertical Layout Groupをアタッチ

4.Text(TMP)→Contentの子オブジェクト

・Rect Transformのアンカーは左上
・TextMeshProに実際に文字を入力して、開始位置を整える
・TextMeshProは左寄せ、上寄せ
・Content Size Fitterをアタッチ、垂直調節をPreferred Sizeに

5.Scrollber Vertical

・Rect Transformのアンカーは右寄せのStretch
・レイキャストターゲットが外れているとハンドルをつかめない

6.Handle

・Rect TransformはStretch

実装結果

解説文が短い問題ではスクロールバーは表示されません。

解説文が長い問題ではスクロールバーは表示されます。

スクロールビューが表示される解説文が連続で表示された場合、前の解説文を閉じた際のスクロールビューの位置を引き継いでしまうので、解説文が表示されると同時にスクロールビューの位置をリセットするとよいです。

以下はボタンを押した際にスクロールビューの位置を戻すことを想定して作ったスクリプトです。
ボタンを押した際にSetActiveAndResetScroll()が実行されるとスクロールビューの位置がリセットされます。
今回は「次の問題へ」ボタンが押された際に実行されるようにしました。

ScrollResetterコンポーネント

using UnityEngine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks;

public class ScrollResetter : MonoBehaviour{
    [Header("位置をリセットするスクロールを登録")] public ScrollRect scrollRect;
    //クリックするとスクロールビューが開くボタン等にセット。
    //スクロールビューが開くと同時にSetActiveAndResetScrollを実行。
    private Button button;

    //このスクリプトが有効になったときにボタンを取得
    private void OnEnable() {
        button = GetComponent<Button>();
        // ボタンがあればイベントリスナーを追加
        if (button != null){
            button.onClick.AddListener(SetActiveAndResetScroll);
        }
    }

    private async void ResetScrollToTop() {
        Canvas.ForceUpdateCanvases();  // すべてのキャンバスの更新を強制
        await UniTask.Yield();  // 1フレーム待機してレイアウト更新を待つ
        // ScrollRectのcontentの位置をリセット
        if (scrollRect != null) {
            scrollRect.verticalNormalizedPosition = 1.0f;
        }
    }
    
    public async void SetActiveAndResetScroll() {
        // 親オブジェクトのスケールを変更するアニメーションを開始
        var parentTransform = scrollRect.transform.parent;
        if (parentTransform != null) {
            await ScaleParentObjectAsync(parentTransform);
        }
        
        // スケール変更後にスクロール位置をリセット
        ResetScrollToTop();
    }

    private async UniTask ScaleParentObjectAsync(Transform parentTransform) {
        Vector3 originalScale = parentTransform.localScale;
        Vector3 targetScale = new Vector3(1.0f, 1.0f, 1.0f);  // 目標のスケールを設定

        float duration = 0.1f;  // アニメーションの期間
        float elapsedTime = 0f;

        while (elapsedTime < duration) {
            elapsedTime += Time.deltaTime;
            float t = Mathf.Clamp01(elapsedTime / duration);
            parentTransform.localScale = Vector3.Lerp(originalScale, targetScale, t);
            await UniTask.Yield();  // フレームをまたいで処理
        }

        parentTransform.localScale = targetScale;  // 最終的なスケールを設定
    }
}

いいなと思ったら応援しよう!