前々から「ScriptableObject」なるものが気になっていたが、使い方も用途もわからず放置して数か月たったある日・・・
ふとYou Tube にて、いつも勉強させてもらっている
Unityゲームスタジオ スタジオしまづさんの下記の動画を拝聴
VIDEO youtu.be
この中ではモンスターの特性を設定するためのデータを「ScriptableObject」を活用して管理されている
なるほど、データの基本構造が同じデータで、パラメーターだけが異なるようなデータを量産するのに向いているのか!!
かつ、SerializeFieldとしてパラメーターを定義すると、Unityのエディター上で編集できる
今までだと、Script内で定義しているので、データの編集も管理も不便だなぁと感じていた
データだけ別ファイルにするというのもあるけど、読み込みも微妙に面倒だったり・・・
前置きが長くなったが、とりあえず使ってみようと思い、下記のような数字表示の制御に使ってみたので、やり方を紹介しておく
なお、見た目7セグメントLED的な表示だが、10枚のスプライトを切り替えて順に表示しているだけ
今回はこの辺の解説は省いているので注意を
数字の表示の制御にあたっては下記のような数値を制御するだけだが、途中で数字を更新する速度や、色を変えたりしたいので、構造は単純だが微妙なパラメーターの調整が結構面倒だったりするもの
〇制御に使用するパラメーター
・同じ状態を維持する時間
・数字の更新スピード(スプライトの入れ替えスピード)
・色
上記を一つのScriptableObjectとして定義し、さらに配列化して、時間が経過したら次
ScriptableObjectに移動してという形で動作の変化をつけていくようにしてみる
データ配列イメージ
0 動作開始フェーズのデータ
1 高速更新フェーズのデータ
2 停止フェーズのデータ
で、実際にコーディングしてみる
〇ScriptableObjectの定義
using UnityEngine;
[CreateAssetMenu] ⇒これにより下記のようにHerrarchyのプラスボタンを押して表示されるメニューに表示され、簡単にファイルが作成されるようになる
public class SequenceDataObj : ScriptableObject ⇒専用の定義 { [SerializeField] public int Mode = 0;//0:更新,1:書き換え [SerializeField] public float Duration = 0;//当該データを使用する時間 [SerializeField] public float UpdateSpeed = 0;//数字の更新スピード [SerializeField] public Color color; //数字の色 [SerializeField] public int TeishiNumOffset = 0;//最後に止める数字までの送りコマ数
}
※データのアクセスは制限するほどのものでもないので、すべてpublicで定義
上記のスクリプト の作成でのUnity Editor上の表示は下記の通り
実際に作成したScriptableObject
今回作成したScriptableObjectの配列を作り、Editor上で割り付け
以上のような感じで、時間経過ごとにScriptableObjectのデータを入れ替えつつ作成したのが、上の方の動画のような動作
説明は以上
感想としては、こうした表示制御はデータの作成、調整、並び替えなどにいちばん時間がかかるので、この作業の効率が良くなった点は大きいかも!!
長くなったので、説明はしないが、今回作成したスクリプト は下記の通り
参考になれば幸いです
下記をImageオブジェクトにアタッチして制御しています
---------------------------------------------
using System.Collections; using UnityEngine; using UnityEngine.UI;
public class SegController : MonoBehaviour { SequenceDataObj CurrentSeqData; [SerializeField] Sprite Segsprites; [SerializeField] SequenceDataObj tempdata; [SerializeField] SequenceDataObj sequenceDatas;
bool IsPlaying = false; Coroutine coroutine = null; int counter = 0; Image image; int CurrentPicNum=0; int SeqDataPos = 0; int SeqDatasize = 0; int TeishiPicNum = 0; int TempPicNum = 0;
void Start() { image = GetComponent<Image>();
SegPicChange(7,new Color(255,255,255)); }
private void Update() { if (Input.GetKeyDown(KeyCode.UpArrow)) { HendouStart(sequenceDatas,7);
} }
public void HendouStart(SequenceDataObj[] sequenceDatas,int Teishinum) { //動作データを取得 SeqDataPos = 0; SeqDatasize = sequenceDatas.Length;
SetupSeqdata(sequenceDatas[SeqDataPos]); TeishiPicNum = Teishinum;
//動作コルーチンスタート IsPlaying = true;
coroutine = StartCoroutine(HendorLoop());
}
IEnumerator HendorLoop() { for(; ; ) {
if (counter > 0) { counter--;
UpdatePic(); } else { SeqDataPos++;
if (SeqDataPos == SeqDatasize) {
IsPlaying = false; StopCoroutine(coroutine); } else { SetupSeqdata(sequenceDatas[SeqDataPos]); UpdatePic();
} }
yield return new WaitForSeconds(CurrentSeqData.UpdateSpeed);
} } void SetupSeqdata(SequenceDataObj nextdata) { CurrentSeqData = nextdata; if (CurrentSeqData.Mode == 1) { PicNumAdjust(CurrentSeqData.TeishiNumOffset);
}
counter = (int)(CurrentSeqData.Duration / CurrentSeqData.UpdateSpeed);
}
//イメージの差しかえ void SegPicChange(int number,Color color) {
image.sprite = Segsprites[number]; image.color = color;
}
//図柄番号の更新 void UpdatePic() { CurrentPicNum++; if (CurrentPicNum >= 10) { CurrentPicNum = 0; }
SegPicChange(CurrentPicNum,CurrentSeqData.color);
}
//最終的に停止させたい数字にするための途中書き換えのための調整
void PicNumAdjust(int offset) { CurrentPicNum = TeishiPicNum - offset;
if (CurrentPicNum < 0) CurrentPicNum += Segsprites.Length;
}
}