【Unity】無限スクロール可能なステージセレクトを実装

無限スクロール可能ステージセレクト応用版

ステージ選択やアイテム一覧で使える無限スクロールのコード。
インスペクターから、スクロール可能方向(軸)・開始位置・開始方向(軸)・ライン数(一応)を指定可能。

  • 無限なので、スクロールバーは無し。
  • Scroll Viewで作るよりは多分軽い。
  • エディタ拡張を使ってみたので、ワンボタンで初期設定可能。
    (ジャグ配列がシリアライズ出来ないっぽいので、ボタンの設置は実行時)
  • 無限なので、ライン数固定は主にスクロール不可能な軸へ適用(画面からはみ出る場合は無視)。
  • 無限なので、StageMaxが小さい場合に10 x 10等でやると1画面内で1231231231みたいに複数設置される。

作成中に混乱してきたので、冗長なコード&適当な命名になりましたが、まあバグなく動きます。
気力が出たら清書します(善処)。

サンプル動画

【ベータ】マスク無 Vertical

1画面の表示数+スクロール方向への余分しかボタンを生成しない仕様。

上手い事スクロールに追従されているのが分かると思う。
(実際の使用時はマスクを有効にします)

【基本形】マスク有 Horizontal

基本の完成図。

【応用】マスク有 Horizontal カラー

ステージ番号に応じて文字の色を変えたりすると見易い。

導入方法

  1. StageSelecter、StageSelecterEditor、StageSelecterItemスクリプトを作成し、コードを全文コピペ。
    (StageSelecterEditorのみEditorフォルダを作って入れておく)
  2. StageSelecterItemプレハブを作成し、StageSelecterItemスクリプトをアタッチ。
    1. インスペクター -> 各種コンポーネントを紐付け。
  3. ステージ選択ボタン設置領域となる背景画像を設置し、任意の大きさに調整。
    1. StageSelecterスクリプトをアタッチ。
    2. StageSelecterItemPrefabへ、ステージ選択ボタンを紐付け。
    3. インスペクター -> Createをクリック。

各種変数値の設定

StageSelecterのインスペクターから各種変数値を設定していく。

  • scrollAxis:スクロールしたい方向に設定。
  • startAxis:設置順番の方向に設定。scrollAxisと逆に指定するのを推奨。
  • fixedColumnCount / fixedRowCount:無限なのでscrollAxis方向には意味なし。
    スクロール不可能な方向で画面に収まらない場合も無視。

使用後

ステージ選択は出しっ放しにせずに(StageSelecterを)非アクティブ化しておく。

  • タッチ判定にRectangleContainsScreenPointを使っているので、UIの重なりが無視される。
  • Canvas.enabledの無効化だけではUpdateが走る。

コード

StageSelecter

  • ステージ選択領域となる背景Imageにアタッチ。

長いです。


using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class StageSelecter : MonoBehaviour
{

	[HideInInspector]
	[SerializeField]
	bool isInitialized = false;

	[HideInInspector]
	[SerializeField]
	GameObject contentGo;

	[HideInInspector]
	[SerializeField]
	RectTransform contentRt;

	[HideInInspector]
	[SerializeField]
	RectTransform backgroundRt;

//生成したステージ選択ボタンのジャグ配列
	StageSelecterItem[][] stageSelecterItems;


//ステージセレクトのステージ選択ボタンのプレハブ
	[SerializeField]
	GameObject stageSelecterItemPrefab;    


	[Header("ステージ数の開始値 (表示部分に1番目のステージ選択ボタンが入らない場合に調整)")]
	[Range(1, 1000)]
	[SerializeField]
	int stageMin = 1;

	[Header("ステージ数の最大値")]
	[Range(1, 1000)]
	[SerializeField]
	int stageMax = 100;

//インスペクターでStaticな値は設定出来ないようなので、こっちで。
	public static int StageMax = 100;

//スクロール不可能な方向にハミ出る場合は、この値を使わず。表示領域に収まる最大数に固定します。
	[Header("列(横)数指定")]
	[Range(1, 100)]
	[SerializeField]
	int fixedColumnCount = 5;

	[Header("行(縦)数指定")]
	[Range(1, 100)]
	[SerializeField]
	int fixedRowCount = 5;

	[Header("設置開始方向")]
	[SerializeField]
	Axis startAxis;

	[Header("設置開始コーナー")]
	[SerializeField]
	StartCorner startCorner;

	[Header("ステージ選択ボタン間の距離")]
	[SerializeField]
	float spacing = 50.0f;

	[Header("スクロール可能方向")]
	[SerializeField]
	Axis scrollAxis;

	[Header("1スクロールの長さ(時間)")]
	[Range(0.1f, 3.0f)]
	[SerializeField]
	float scrollDuration = 1.0f;

	[Header("スクロール速度の上限(多分deltaTimeが掛かるので大きめに指定)")]
	[Range(1000.0f, 5000.0f)]
	[SerializeField]
	float scrollSpeedMax = 1500.0f;

	[Header("ドラッグ距離の何倍スクロールするかのレート")]
	[Range(5.0f, 30.0f)]
	[SerializeField]
	float scrollRate = 15.0f;

//軸の定数
	enum Axis {
		Horizontal,
		Vertical,
	}

//設置開始コーナーの定数
	enum StartCorner {
		UpperLeft,
		UpperRight,
		LowerLeft,
		LowerRight,
	}


//ステージボタンを生成する時のカウント
	int stageCount = 0;

//タッチ処理関係
	Vector3 beganTouchPoint;
	Vector3 endedTouchPoint;
	Vector3 touchDelta;
	bool isDragging;

//雑多な物
	Vector2 stageSelecterItemSize;

	int contentItemColumnCount;
	int contentItemRowCount;

	Vector2 contentSize;
	Vector2 backgroundSize;

	Vector2 scrollDelta;
	Vector2 previousAnchoredPosition;
	Vector2 scrollTargetAnchoredPosition;
	Vector2 scrollVelocity;
	float scrollElapsedTime;
	Coroutine scroll;
	Vector2 contentSizeIgnoreUnscrollAxis;
	float scrollThreshold;


	int displayedStageMax;
	int fixedContentItemColumnCount;
	int fixedContentItemRowCount;
	int columnEdgeMargin;
	int rowEdgeMargin;

	Vector2 tempPosition;
	Vector2 positionToAdd;
	Vector2 newLinePositionToAdd;


	int borderLineIndex1;
	int borderLineIndex2;

	int lineIndexToAdd;

	int stageNumberToAdd;



	void Awake()
	{
		StageMax = stageMax;

		if (!isInitialized)
			CreateStageSelecter();

		CreateStageSelecterItems();
	}


	void Update()
	{
		if (Input.GetMouseButtonDown(0)) {
			beganTouchPoint = Input.mousePosition;

			if (RectTransformUtility.RectangleContainsScreenPoint(backgroundRt, beganTouchPoint))
				isDragging = true;

		} else if (Input.GetMouseButtonUp(0) && isDragging) {
			endedTouchPoint = Input.mousePosition;

			isDragging = false;
			touchDelta = endedTouchPoint - beganTouchPoint;

			StartScroll();
		}
	}


	void StartScroll()
	{
		if (scroll != null) {
			StopCoroutine(scroll);
		}

		scroll = StartCoroutine(Scroll());
	}


	IEnumerator Scroll()
	{
		scrollElapsedTime = 0;

		switch (scrollAxis) {
			case Axis.Horizontal:
				scrollTargetAnchoredPosition.Set(contentRt.anchoredPosition.x + touchDelta.x * scrollRate, 0);
				contentSizeIgnoreUnscrollAxis.Set(contentSize.x + spacing, 0);
				scrollThreshold = stageSelecterItemSize.x + spacing;
				break;

			case Axis.Vertical:
				scrollTargetAnchoredPosition.Set(0, contentRt.anchoredPosition.y + touchDelta.y * scrollRate);
				contentSizeIgnoreUnscrollAxis.Set(0, contentSize.y + spacing);
				scrollThreshold = stageSelecterItemSize.y + spacing;
				break;
		}


		while (true) {
			yield return null;
			scrollElapsedTime += Time.deltaTime;

			contentRt.anchoredPosition = Vector2.SmoothDamp(contentRt.anchoredPosition, scrollTargetAnchoredPosition, ref scrollVelocity, scrollDuration, scrollSpeedMax);
			scrollDelta += scrollVelocity * Time.deltaTime;


			switch (scrollAxis) {
				case Axis.Horizontal:
					if (scrollDelta.x <= -scrollThreshold) {
						scrollDelta.x += scrollThreshold;

						switch (startAxis) {
							case Axis.Horizontal:
								for (int i = 0; i < fixedContentItemRowCount; i++) {
									stageSelecterItems[i][borderLineIndex2].rt.anchoredPosition += contentSizeIgnoreUnscrollAxis;
									stageSelecterItems[i][borderLineIndex2].AddStageNumber(stageNumberToAdd);
								}
								AddTargetLineIndex(lineIndexToAdd);

								break;
							case Axis.Vertical:
								for (int i = 0; i < fixedContentItemRowCount; i++) {
									stageSelecterItems[borderLineIndex2][i].rt.anchoredPosition += contentSizeIgnoreUnscrollAxis;
									stageSelecterItems[borderLineIndex2][i].AddStageNumber(stageNumberToAdd);
								}
								AddTargetLineIndex(lineIndexToAdd);

								break;
						}

					} else if (scrollThreshold <= scrollDelta.x) {
						scrollDelta.x -= scrollThreshold;

						switch (startAxis) {
							case Axis.Horizontal:
								for (int i = 0; i < fixedContentItemRowCount; i++) {
									stageSelecterItems[i][borderLineIndex1].rt.anchoredPosition -= contentSizeIgnoreUnscrollAxis;
									stageSelecterItems[i][borderLineIndex1].AddStageNumber(-stageNumberToAdd);
								}
								AddTargetLineIndex(-lineIndexToAdd);

								break;
							case Axis.Vertical:
								for (int i = 0; i < fixedContentItemRowCount; i++) {
									stageSelecterItems[borderLineIndex1][i].rt.anchoredPosition -= contentSizeIgnoreUnscrollAxis;
									stageSelecterItems[borderLineIndex1][i].AddStageNumber(-stageNumberToAdd);
								}
								AddTargetLineIndex(-lineIndexToAdd);

								break;
						}
					}
					break;


				case Axis.Vertical:
					if (scrollDelta.y <= -scrollThreshold) {
						scrollDelta.y += scrollThreshold;

						switch (startAxis) {
							case Axis.Horizontal:
								for (int i = 0; i < fixedContentItemColumnCount; i++) {
									stageSelecterItems[borderLineIndex1][i].rt.anchoredPosition += contentSizeIgnoreUnscrollAxis;
									stageSelecterItems[borderLineIndex1][i].AddStageNumber(-stageNumberToAdd);
								}
								AddTargetLineIndex(-lineIndexToAdd);

								break;
							case Axis.Vertical:
								for (int i = 0; i < fixedContentItemColumnCount; i++) {
									stageSelecterItems[i][borderLineIndex1].rt.anchoredPosition += contentSizeIgnoreUnscrollAxis;
									stageSelecterItems[i][borderLineIndex1].AddStageNumber(-stageNumberToAdd);
								}
								AddTargetLineIndex(-lineIndexToAdd);

								break;
						}

					} else if (scrollThreshold <= scrollDelta.y) {
						scrollDelta.y -= scrollThreshold;

						switch (startAxis) {
							case Axis.Horizontal:
								for (int i = 0; i < fixedContentItemColumnCount; i++) {
									stageSelecterItems[borderLineIndex2][i].rt.anchoredPosition -= contentSizeIgnoreUnscrollAxis;
									stageSelecterItems[borderLineIndex2][i].AddStageNumber(stageNumberToAdd);
								}
								AddTargetLineIndex(lineIndexToAdd);

								break;
							case Axis.Vertical:
								for (int i = 0; i < fixedContentItemColumnCount; i++) {
									stageSelecterItems[i][borderLineIndex2].rt.anchoredPosition -= contentSizeIgnoreUnscrollAxis;
									stageSelecterItems[i][borderLineIndex2].AddStageNumber(stageNumberToAdd);
								}
								AddTargetLineIndex(lineIndexToAdd);

								break;
						}
					}
					break;
			}



			if (scrollDuration <= scrollElapsedTime) {
				scrollVelocity = Vector2.zero;
				scroll = null;
				yield break;
			}
		}
	}


	void AddTargetLineIndex(int indexToAdd)
	{
		borderLineIndex1 += indexToAdd;
		borderLineIndex2 += indexToAdd;

		switch (scrollAxis) {
		   case Axis.Horizontal:

				if (borderLineIndex1 < 0) {
					borderLineIndex1 = fixedContentItemColumnCount - 1;
				} else if (fixedContentItemColumnCount <= borderLineIndex1) {
					borderLineIndex1 = 0;
				}

				if (borderLineIndex2 < 0) {
					borderLineIndex2 = fixedContentItemColumnCount - 1;
				} else if (fixedContentItemColumnCount <= borderLineIndex2) {
					borderLineIndex2 = 0;
				}

				break;

			case Axis.Vertical:

				if (borderLineIndex1 < 0) {
					borderLineIndex1 = fixedContentItemRowCount - 1;
				} else if (fixedContentItemRowCount <= borderLineIndex1) {
					borderLineIndex1 = 0;
				}

				if (borderLineIndex2 < 0) {
					borderLineIndex2 = fixedContentItemRowCount - 1;
				} else if (fixedContentItemRowCount <= borderLineIndex2) {
					borderLineIndex2 = 0;
				}

				break;
		}
	}


	void CreateStageSelecterItems()
	{
		backgroundSize = backgroundRt.sizeDelta;
		stageCount = stageMin;
		stageSelecterItemSize = stageSelecterItemPrefab.GetComponent<RectTransform>().sizeDelta;

		switch (scrollAxis) {
			case Axis.Horizontal:
				columnEdgeMargin = 2;
				rowEdgeMargin = 0;
				break;

			case Axis.Vertical:
				columnEdgeMargin = 0;
				rowEdgeMargin = 2;
				break;
		}


//行と列の大体の個数+端の余裕分。
		contentItemColumnCount = Mathf.FloorToInt(backgroundSize.x / (stageSelecterItemSize.x + spacing)) + columnEdgeMargin;
		contentItemRowCount = Mathf.FloorToInt(backgroundSize.y / (stageSelecterItemSize.y + spacing)) + rowEdgeMargin;

		fixedContentItemColumnCount = Mathf.Min(fixedColumnCount, contentItemColumnCount);
		fixedContentItemRowCount = Mathf.Min(fixedRowCount, contentItemRowCount);

		displayedStageMax = fixedContentItemColumnCount * fixedContentItemRowCount;
		contentSize.Set(stageSelecterItemSize.x * fixedContentItemColumnCount + spacing * (fixedContentItemColumnCount - 1), stageSelecterItemSize.y * fixedContentItemRowCount + spacing * (fixedContentItemRowCount - 1));


		switch (scrollAxis) {
			case Axis.Horizontal:
				switch (startCorner) {

					case StartCorner.UpperLeft:
					case StartCorner.LowerLeft:
						borderLineIndex1 = fixedContentItemColumnCount - 1;
						borderLineIndex2 = 0;
						lineIndexToAdd = 1;

						switch (startAxis) {
							case Axis.Horizontal:
							stageNumberToAdd = fixedContentItemColumnCount;
							break;

							case Axis.Vertical:
							stageNumberToAdd = displayedStageMax;
							break;
						}

						break;

					case StartCorner.UpperRight:
					case StartCorner.LowerRight:
						borderLineIndex1 = 0;
						borderLineIndex2 = fixedContentItemColumnCount - 1;
						lineIndexToAdd = -1;

						switch (startAxis) {
							case Axis.Horizontal:
							stageNumberToAdd = -fixedContentItemColumnCount;
							break;

							case Axis.Vertical:
							stageNumberToAdd = -displayedStageMax;
							break;
						}

						break;
				}

				break;

			case Axis.Vertical:
				switch (startCorner) {
					case StartCorner.UpperLeft:
					case StartCorner.UpperRight:
						borderLineIndex1 = fixedContentItemRowCount - 1;
						borderLineIndex2 = 0;
						lineIndexToAdd = 1;

						switch (startAxis) {
							case Axis.Horizontal:
							stageNumberToAdd = displayedStageMax;
							break;

							case Axis.Vertical:
							stageNumberToAdd = fixedContentItemRowCount;
							break;
						}
						break;
					case StartCorner.LowerLeft:
					case StartCorner.LowerRight:
						borderLineIndex1 = 0;
						borderLineIndex2 = fixedContentItemRowCount - 1;
						lineIndexToAdd = -1;

						switch (startAxis) {
							case Axis.Horizontal:
							stageNumberToAdd = -displayedStageMax;
							break;

							case Axis.Vertical:
							stageNumberToAdd = -fixedContentItemRowCount;
							break;
						}
						break;
				}

				break;
		}



		switch (startCorner) {
			case StartCorner.UpperLeft:
				tempPosition.Set(-contentSize.x / 2 + stageSelecterItemSize.x / 2, contentSize.y / 2 - stageSelecterItemSize.y / 2);

				switch (startAxis) {
					case Axis.Horizontal:
						positionToAdd.Set(stageSelecterItemSize.x + spacing, 0);
						newLinePositionToAdd.Set(0, -stageSelecterItemSize.y - spacing);
						break;
					case Axis.Vertical:
						positionToAdd.Set(0, -stageSelecterItemSize.y - spacing);
						newLinePositionToAdd.Set(stageSelecterItemSize.x + spacing, 0);
						break;
				}

				break;
			case StartCorner.UpperRight:
				tempPosition.Set(contentSize.x / 2 - stageSelecterItemSize.x / 2, contentSize.y / 2 - stageSelecterItemSize.y / 2);

				switch (startAxis) {
					case Axis.Horizontal:
						positionToAdd.Set(-stageSelecterItemSize.x - spacing, 0);
						newLinePositionToAdd.Set(0, -stageSelecterItemSize.y - spacing);
						break;
					case Axis.Vertical:
						positionToAdd.Set(0, -stageSelecterItemSize.y - spacing);
						newLinePositionToAdd.Set(-stageSelecterItemSize.x - spacing, 0);
						break;
				}

				break;
			case StartCorner.LowerLeft:
				tempPosition.Set(-contentSize.x / 2 + stageSelecterItemSize.x / 2, -contentSize.y / 2 + stageSelecterItemSize.y / 2);

				switch (startAxis) {
					case Axis.Horizontal:
						positionToAdd.Set(stageSelecterItemSize.x + spacing, 0);
						newLinePositionToAdd.Set(0, stageSelecterItemSize.y + spacing);
						break;
					case Axis.Vertical:
						positionToAdd.Set(0, stageSelecterItemSize.y + spacing);
						newLinePositionToAdd.Set(stageSelecterItemSize.x + spacing, 0);
						break;
				}

				break;
			case StartCorner.LowerRight:
				tempPosition.Set(contentSize.x / 2 - stageSelecterItemSize.x / 2, -contentSize.y / 2 + stageSelecterItemSize.y / 2);

				switch (startAxis) {
					case Axis.Horizontal:
						positionToAdd.Set(-stageSelecterItemSize.x - spacing, 0);
						newLinePositionToAdd.Set(0, stageSelecterItemSize.y + spacing);
						break;
					case Axis.Vertical:
						positionToAdd.Set(0, stageSelecterItemSize.y + spacing);
						newLinePositionToAdd.Set(-stageSelecterItemSize.x - spacing, 0);
						break;
				}

				break;
		}



		switch (scrollAxis) {
			case Axis.Horizontal:

				switch (startAxis) {
					case Axis.Horizontal:

						stageSelecterItems = new StageSelecterItem[fixedContentItemRowCount][];


						for (int i = 0; i < fixedRowCount; i++) {
							if (i < fixedContentItemRowCount)
								stageSelecterItems[i] = new StageSelecterItem[fixedContentItemColumnCount];


							for (int j = 0; j < fixedColumnCount; j++) {

								if (i < fixedContentItemRowCount && j < fixedContentItemColumnCount) {
									stageSelecterItems[i][j] = Instantiate(stageSelecterItemPrefab, contentRt).GetComponent<StageSelecterItem>();

									stageSelecterItems[i][j].rt.localPosition = tempPosition;
									int count = stageCount;
									stageSelecterItems[i][j].SetStageNumber(count);
									tempPosition += positionToAdd;
								}

								stageCount++;
							}
							
							tempPosition -= positionToAdd * fixedContentItemColumnCount;
							tempPosition += newLinePositionToAdd;
						}

						break;
					case Axis.Vertical:
		
						stageSelecterItems = new StageSelecterItem[fixedContentItemColumnCount][];

						for (int i = 0; i < fixedContentItemColumnCount; i++) {
							stageSelecterItems[i] = new StageSelecterItem[fixedContentItemRowCount];

							for (int j = 0; j < fixedContentItemRowCount; j++) {
								stageSelecterItems[i][j] = Instantiate(stageSelecterItemPrefab, contentRt).GetComponent<StageSelecterItem>();

								stageSelecterItems[i][j].rt.localPosition = tempPosition;
								int count = stageCount;
								stageSelecterItems[i][j].SetStageNumber(count);
								tempPosition += positionToAdd;

								stageCount++;
							}
							
							tempPosition -= positionToAdd * fixedContentItemRowCount;
							tempPosition += newLinePositionToAdd;
						}

						break;
				}

				break;

			case Axis.Vertical:

				switch (startAxis) {
					case Axis.Horizontal:

						stageSelecterItems = new StageSelecterItem[fixedContentItemRowCount][];

		
						for (int i = 0; i < fixedContentItemRowCount; i++) {
							stageSelecterItems[i] = new StageSelecterItem[fixedContentItemColumnCount];

							for (int j = 0; j < fixedContentItemColumnCount; j++) {
								stageSelecterItems[i][j] = Instantiate(stageSelecterItemPrefab, contentRt).GetComponent<StageSelecterItem>();

								stageSelecterItems[i][j].rt.localPosition = tempPosition;
								int count = stageCount;
								stageSelecterItems[i][j].SetStageNumber(count);
								tempPosition += positionToAdd;
								stageCount++;
							}
							
							tempPosition -= positionToAdd * fixedContentItemColumnCount;
							tempPosition += newLinePositionToAdd;
						}
						

						break;
					case Axis.Vertical:

						stageSelecterItems = new StageSelecterItem[fixedContentItemColumnCount][];

						for (int i = 0; i < fixedColumnCount; i++) {
							if (i < fixedContentItemColumnCount)
								stageSelecterItems[i] = new StageSelecterItem[fixedContentItemRowCount];

							for (int j = 0; j < fixedRowCount; j++) {

								if (i < fixedContentItemColumnCount && j < fixedContentItemRowCount) {

									stageSelecterItems[i][j] = Instantiate(stageSelecterItemPrefab, contentRt).GetComponent<StageSelecterItem>();

									stageSelecterItems[i][j].rt.localPosition = tempPosition;
									int count = stageCount;
									stageSelecterItems[i][j].SetStageNumber(count);
									tempPosition += positionToAdd;

								}

								stageCount++;
							}
							
							tempPosition -= positionToAdd * fixedContentItemRowCount;
							tempPosition += newLinePositionToAdd;
						}

						break;
				}

				break;
		}
	}


	public void CreateStageSelecter()
	{
		isInitialized = true;

		gameObject.AddComponent<RectMask2D>();
		backgroundRt = GetComponent<RectTransform>();

		contentGo = new GameObject("Content");
		contentRt = contentGo.AddComponent<RectTransform>();
		contentRt.SetParent(transform);

		contentRt.localScale = Vector3.one;
		contentRt.anchoredPosition = Vector2.zero;
	}


//ステージクリア画面からステージセレクト画面に戻り、戻った瞬間にステージクリアマークを適用したい場合は、こんな感じで番号を変えずに更新出来る(StageSelecterItemのAddStageNumber内に表示切り替え処理を入れておく)。
/*
	void OnEnable()
	{
		for (int i = 0; i < stageSelecterItems.Length; i++) {
			for (int j = 0; j < stageSelecterItems[i].Length; j++) {
				stageSelecterItems[i][j].AddStageNumber(0);
			}
		}
	}
*/

}

StageSelecterItem

  • ステージ選択ボタンのプレハブにアタッチ。
  • プレハブ設定画面のインスペクターから、各コンポーネントを紐付けしておく。

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class StageSelecterItem : MonoBehaviour
{
//プレハブ設定画面で、各コンポーネントをインスペクターから紐付けしておく。
//onClickのリスナーをインスペクターから設定しておくならbtnのみ消しても大丈夫です。
	public GameObject go;
	public Transform tf;
	public TextMeshProUGUI tmp;
	public RectTransform rt;
	public Button btn;
//画像差し替え使用時のみ。
//    public Image img;

//ステージ番号
	public int stageNumber = 0;

//ステージ番号の色を変更する時のみ。
/*
	Color32 defaultTmpColor = new Color32(255, 255, 255, 255);
	Color32 specialTmpColor5 = new Color32(255, 223, 0, 255);
	Color32 specialTmpColor10 = new Color32(255, 32, 32, 255);
*/

//インスペクターから設定しておくなら消しても大丈夫です。
	void Awake()
	{
		btn.onClick.AddListener(() => ButtonListenerStageSelect());
	}

	public void ButtonListenerStageSelect()
	{

//ここでGameManager等にstageNumberを渡してステージ開始。

	}

//ステージ番号を変更する際に、有効範囲を超えたら反対側からループさせる。
	public void AddStageNumber(int numberToAdd)
	{
		stageNumber += numberToAdd;
		stageNumber = stageNumber % StageSelecter.StageMax;

		if (stageNumber < 1) {
			stageNumber = StageSelecter.StageMax - Mathf.Abs(stageNumber);
		}


//TextMeshProで番号を振るなら、ここで実行。
		tmp.SetText("{0}", stageNumber);

//Imageを差し替える場合も、ここで実行(stageSelecterItemImagesにステージ番号順にステージ画像を登録しておく)。
//        img.sprite = UIManager.Instance.stageSelecterItemImages[stageNumber];   


//区切りの良いステージは番号の色を変えたりしても良い。
/*
		if (stageNumber % 10 == 0) {
			tmp.color = specialTmpColor10;
		} else if (stageNumber % 5 == 0) {
			tmp.color = specialTmpColor5;
		} else if (tmp.color != defaultTmpColor) {
			tmp.color = defaultTmpColor;
		}
*/
	}

//初期配置時
	public void SetStageNumber(int number)
	{
		stageNumber = number % StageSelecter.StageMax;

		if (stageNumber < 1) {
			stageNumber = StageSelecter.StageMax - Mathf.Abs(stageNumber);
		}


//TextMeshProで番号を振る or Imageの差し替えはここで実行。
		tmp.SetText("{0}", stageNumber);


//番号の色振り。
/*
		if (stageNumber % 10 == 0) {
			tmp.color = specialTmpColor10;
		} else if (stageNumber % 5 == 0) {
			tmp.color = specialTmpColor5;
		}
*/
	}

}

StageSelecterEditor

  • エディタ拡張なので、アタッチしなくても適用される。
  • Editorフォルダを作成して、それに入れておく。
    (その他のフォルダに置くとビルド時にエラーが出る)

エディタ拡張を導入する為のスクリプト。
StageSelecterのCreateボタンで初期設定をしていない場合は、実行時に初期化。
(実行時にAddComponent等するので負荷が増える)


using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(StageSelecter))]
public class StageSelecterEditor : Editor
{
	StageSelecter stageSelecter;

	public override void OnInspectorGUI()
	{
		base.OnInspectorGUI();

		if (stageSelecter == null)
			stageSelecter = target as StageSelecter;


		if (GUILayout.Button("Create")){
			stageSelecter.CreateStageSelecter();
		}
	}

}

タイトルとURLをコピーしました