- 投稿日:2019-09-29T23:52:44+09:00
OutsystemsでC#を書いてみた
やったこと
- 簡単な2項の足し算をするコードをC#で書いて、それをOutSystemsのロジック内で呼び出して使ってみた
- Structure型のRecordをC#に渡してみることにも挑戦してみた
想定読者
初歩的なOutsystemsの操作は何となくわかるが、C#でExtensionを書いたことはない・どうやって書くか知りたい人
開発環境
- Outsystems11(ServiceStudio, IntegrationStudio)
- Vidual Studio
筆者のスキル
C#の詳しいことは全然わからん outsystemsも初心者
手順
C#のコードを書く(Extension)
- 任意のApplication内に、Extentsionを作成する
- Create Moduleボタンを押すと、勝手にIntegrationStudioが開いて、EnvironmentのPasswordを聞かれるのですなおに入力する
- 以下のような画面が開くので必要ならDescriptionを書く
- 左のツリーのActionsフォルダを右クリックして、Add Actionをクリック
- 以下の図のように、Actionの引数や戻り値を設定できる画面になるので、それぞれ入力する
- 今回は、2つの項目の引数を受け取って計算結果を返却するアクションを作成するので、以下のようなParametersを設定した
- 左上のFileメニューを開いて、Edit Sourcecode .NETを選択する
- 勝手にVisual Studioが開く
- 右側のソリューションエクスプローラーでCaluculation.csを開くと先ほど入力した引数や戻り値などは勝手に補完してくれていることがわかる
// TODO: Write implementation for action
というコメントの下に今回やりたかった足し算のコードを入力する
ssResult = ssFirstTerm + ssSecondTerm;
- コードが入力し終わったら、ファイルを保存してVisual Studioを閉じる
- IntegrationStudioに戻って、1Click Publishボタンを押す(下図)
- Publishが終わってからServiceStudioに戻ると、ちゃんとExtensionが作成されてIntegrationStudioで作ったモジュールが反映されていることが確認できる
ServiceStudio側でExtensionを呼び出す
- 下図のような画面を作って、FirstTermとSecondTermというLocalVariableを用意して、Inputの値が入るように設定する
Additionボタンを押すとC#で書いたアクションを呼び出すためのScreenAction(Addition)を呼び出すように設定する
C#で書いたアクションのDependencyを貼る
- 呼び出して使ってみる
- Publishして計算させてみるとこんな感じで計算結果が正しく表示された
OutsystemsのStructureをC#に渡したい場合はどうするの?
- IntegrationStudioでStructureを定義するとその型でレコードを受け取れるようになる
EditStructure.csで、Nameの値がfooかどうか見てあげる(C#わかんない)
書いたのはこれだけEditStructure.cspublic void MssGetStructureAndValidateValue(RCStructureRecord ssStructure, out bool ssResult) { ssResult = false; String ValueForCompare = "foo"; if (ssStructure.ssSTStructure.ssName.Equals(ValueForCompare)) { ssResult = true; } } // MssGetStructureAndValidateValue
- 投稿日:2019-09-29T22:12:40+09:00
class NestedList<T> : List<NestedList<T>> {}
タイトルなにこれ?
今まで見たことがなかったコードなのですが、実は書いてもエラーが発生しないコードなんです。
(コレクションクラスが継承可能だという事実も同時に知りました……。)ということで、リストの型ネストによって何ができるのかを見ていきましょう。
ネストさせるとどうなる?
辞書の型ネストの方が構造が分かり易かったので、まずそちらから。
class NestedDictionary<T> : Dictionary<T, NestedDictionary<T>> {}と書くと、これは、Tを用いてNestedDictionary<T>を取り出す、というのを無限に繰り返せるデータ構造になります。
実際にこれを使ってみると……var dic = new NestedDictionary<string>() { { "hoge", new NestedDictionary<string>() { { "asdf" , new NestedDictionary<string>() }, { "qwer", new NestedDictionary<string>() { { "abcd", new NestedDictionary<string>() } } } } }, { "fuga", new NestedDictionary<string>() { { "test", new NestedDictionary<string>() }, { "qiita", new NestedDictionary<string>() { { "haha", new NestedDictionary<string>() } } } } } }; foreach(var s in dic["fuga"]["qiita"].Keys) Console.WriteLine(s); //dic変数の中の"fuga"をKeyとしたValueを取り出す //さらにそこから"qiita"をKeyとしたValueを取り出す //結果として"haha"が出力されるというコードが書けます(ネスト深っ)
これを踏まえた上で、Listの型ネストを見てみましょう。
ただし、タイトル通りだと性質が分かりづらいので、少しコードを書き加えます。public class NestedList<T> : List<NestedList<T>> { public T Value { get; set; } public NestedList(T value) => Value = value; }何してるかいまいちピンとこないかもしれません。
実際に使ってみましょう。var list = new NestedList<string>("top") { new NestedList<string>("umum....") { new NestedList<string>("aaa"), new NestedList<string>("bbb") }, new NestedList<string>("fmfm...") { new NestedList<string>("areare?"), new NestedList<string>("oooooo") { new NestedList<string>("naninani?") }, new NestedList<string>("qiita") } }; Console.WriteLine(list[1][2].Value); //listの1番目("fmfm..."を含む)のオブジェクトの中の2番目("qiita"を含む)のオブジェクトを取り出して中身を表示する //"qiita"が出力されるValueプロパティを追加したことによってツリー構造っぽく見えるようになりました。
逆に言えば、コードを少し書き加えたのは、ツリー構造の性質を持っていることを分かりやすくしたかったからでした。上記以外にも色々試したところ、リストの型ネストは、"ツリー構造"または"無限次元リスト"のような感じがしました。
ツリー構造は、リストの一般化だった……?実際に使える?
ツリー構造を取れるので、それが必要なプログラムには使えるかと思います。
実際に、ツリー構造に関係が深いコードをいくつか書いてみました。//名前は違うけど、NestedListと同じです。 public class NTree<T> : List<NTree<T>> { public T Value { get; set; } public NTree(T value) => Value = value; //深さ優先探索(行きがけ順) private IEnumerable<NTree<T>> DFSNodes() { var stack = new Stack<NTree<T>>(); stack.Push(this); while(stack.Any()) { var tree = stack.Pop(); yield return tree; tree.Reverse(); foreach(var part in tree) stack.Push(part); tree.Reverse(); } } //深さ優先探索(行きがけ順)の値を求める public IEnumerable<T> DFSValues() => DFSNodes().Select(t => t.Value); //幅優先探索(レベル順) private IEnumerable<NTree<T>> BFSNodes() { var queue = new Queue<NTree<T>>(); queue.Enqueue(this); while(queue.Any()) { var tree = queue.Dequeue(); yield return tree; foreach(var part in tree) queue.Enqueue(part); } } //幅優先探索(レベル順)の値を求める public IEnumerable<T> BFSValues() => BFSNodes().Select(t => t.Value); //葉の数を調べる public int CountLeaves() => DFSNodes().Count(part => part.IsEmpty()); //葉の値だけを取り出す public IEnumerable<T> Leaves() => DFSNodes().Where(part => part.IsEmpty()).Select(part => part.Value); }幅優先探索、たった7行で作ることができました……!
(実は今まで一回もまともに実装できた試しが無かった)
深さ優先探索もたったの9行。驚きです。
葉の数や値も簡単に出せました。おわりに
コレクションクラスを継承する、という発想にはなかなか至りにくいとは思います。
しかしながら、使い方次第で大きな可能性を秘めていることが今回でわかりました。
頭の片隅に置いておき、状況によって使ってみるのも手かもしれません。ライセンス
- 投稿日:2019-09-29T18:44:19+09:00
【Unity(C#)】OculusIntegrationを使ってVR空間でSliderを操作
目的
VR空間内でスライダーのUIを操作して、ゲームの難易度を設定する
というのが今回の目的です。この記事ではVR空間内でスライダーのUIを操作の部分を記述します。
デモ
実際に作成したものがこちらです。
見た目は置いといて、機能としては完成です。OculusIntegrationの設定
①OVRInputModuleの設定
Create Empty
でGameObjectを生成して、OVRInputModule
をAdd Componentします。設定項目としては3か所だけです。
今回は人差し指のトリガーで操作する設定にしてます。
Cursorの箇所は後述します。
②Cursorの設定
続いて、Cursorの設定です。
Create Empty
でGameObjectを生成して、LaserPointer
をAdd Componentします。
同じオブジェクトにLineRenderer
もAdd Componentします。あと、LineRendererが太すぎるのでWidthを0.03くらいにしました。
お好みでmaterialを設定してレーザーの色を変えたりできます。
今回のデモではカーソルは表示していませんが、
必要な場合はCursorVisual
お好きなカーソル(ゲームオブジェクト)をアタッチすればOKです。
③OVRRaycasterを追加
Canvasに
OVRRaycaster
をAdd Componentします。
これで、そのCanvasの子のUIに対して操作が可能になります。
もともとあるGraphyicRaycaster
は消してしまって構いません。設定完了!
これでもうUIを操作できます。
OculusIntegration神ですね。コード
スライダーの値を取得するメソッド、
GetLevel
を用意します。Sliderにアタッチusing UnityEngine; using UnityEngine.UI; public class LevelGetFromSlider : MonoBehaviour { Slider levelSlider; void Start() { levelSlider = this.gameObject.GetComponent<Slider>(); } public int GetLevel() { return (int)levelSlider.value; } }Textにアタッチusing UnityEngine.UI; using UnityEngine; public class LevelText : MonoBehaviour { [SerializeField] LevelGetFromSlider _levelGetFromSlider; Text levelText; void Start() { levelText = this.gameObject.GetComponent<Text>(); } public void LevelTextChange() { levelText.text = _levelGetFromSlider.GetLevel().ToString(); } }後はテキスト側で
On Value Changed
に登録するメソッド内で先程のGetLevel
を使います。
On Value Changed
というのは、Slider Componentに用意されているイベントハンドラーです。
画像のように登録して使います。これでSliderの値が変更された際に、テキストも変わります。
Editor上でSliderのValueを直接編集しても反映されないので注意です。
- 投稿日:2019-09-29T14:55:00+09:00
UnityでProjectSettingsと共にunitypackageをExportする
雑記
レイヤー設定と共にパッケージを作成したい機会があったので。
問題ないかは不明。http://myoujing.wpblog.jp/2014/03/274/
こちらを参考にしましたが、余計なdll等も含まれてしまったため
以下のようにしてみました。#if UNITY_EDITOR using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; public class ExportSetting : MonoBehaviour { [MenuItem("Assets/ExportWithSettings")] static void Export() { string[] assetPaths = { "Assets/含めたいフォルダー", "ProjectSettings/AudioManager.asset", "ProjectSettings/ClusterInputManager.asset", "ProjectSettings/DynamicsManager.asset", "ProjectSettings/EditorBuildSettings.asset", "ProjectSettings/GraphicsSettings.asset", "ProjectSettings/InputManager.asset", "ProjectSettings/NavMeshAreas.asset", "ProjectSettings/NetworkManager.asset", "ProjectSettings/Physics2DSettings.asset", "ProjectSettings/ProjectSettings.asset", "ProjectSettings/QualitySettings.asset", "ProjectSettings/TagManager.asset", "ProjectSettings/TimeManager.asset", "ProjectSettings/UnityConnectSettings.asset" }; string exportPath = "test.unitypackage"; AssetDatabase.ExportPackage(assetPaths, exportPath, ExportPackageOptions.Interactive | ExportPackageOptions.Recurse); } } #endifProjectSettingsは再帰で読まれなかった。
環境
Unity 2017 4.2.8f1
- 投稿日:2019-09-29T09:55:42+09:00
windows form で 隠れるパネルを作成する
やりたいこと
環境
- Microsoft Visual Studio Community 2019
- Microsoft .NET Framework Ver.4.8
使用するコントロール
使用するのは 3つだけ
* Panel panel1 これが隠れるパネル
* Timer timer1 隠れるアニメーション用タイマー
* Label label1 クリックイベントで閉じたり開いたりさせる作成
コントロールの配置
form にpanel1を配置します。
[プロパティ]
* BackColor = "ActiveCaption"
* Dock = "Left"
panel1上にラベルで閉じたり開いたりするための つまみ を作成します。
[プロパティ]
* AutoSize = "False"
* BackColor = "ControlDarkDark"
* Dock = "Right"
* Font = メイリオ, 12pt, style=Bold
* ForeColor = "White"
* text = "<"
* TextAlign = "MiddleCenter"
timerを設置します。
[プロパティ]
Interval = 10 この数値が小さいほど動きが早くなります。コーディング
使用する 変数、定数 の準備
Form1.cspublic partial class Form1 : Form { const int PITCH = 10; // 閉じる(開く)移動幅 小さくするとなめらかになります。 bool _is_hide = false; // 表示状況 true:非表示状態 false:表示状態 int _hidePanelWidth; // 現在の隠れるパネルの幅Form の Loadイベントで隠れるパネルの現状の幅を取得
Form1.cs-Form1_Load()private void Form1_Load(object sender, EventArgs e) { _hidePanelWidth = this.panel1.Width; // 隠れパネルの幅を取得 }ラベルの Clickイベント を記述します。
クリックされるごとにタイマーをスタートします。Form1.cs-Label1_Click()private void Label1_Click(object sender, EventArgs e) { timer1.Start(); // タイマースタート }タイマーの Tickイベント を記述します。
タイマーがスタートされると、 Interval で設定されている時間(ms)ごとにTickイベントが実行されます。Form1.cs-Timer1_Tick()private void Timer1_Tick(object sender, EventArgs e) { // 表示状況により分岐 if (_is_hide) { // 閉じているとき this.panel1.Width = this.panel1.Width + PITCH; // 幅をピッチ分増やす // 増加後の幅が当初の幅を超えたか if (this.panel1.Width >= _hidePanelWidth) { timer1.Stop(); // タイマーをストップ this.panel1.Width = _hidePanelWidth; // 当初の幅に再設定 label1.Text = "<"; // つまみの方向を反転 _is_hide = false; // 表示状況を反転 } } else { // 開いているとき this.panel1.Width = this.panel1.Width - PITCH; // 幅をピッチ分減らす // 減少後の幅がつまみの幅を下回った場合 if (this.panel1.Width <= label1.Width) { timer1.Stop(); // タイマーをストップ this.panel1.Width = label1.Width; // つまみ分の幅に再設定 label1.Text = ">"; // つまみの方向を反転 _is_hide = true; // 表示状況を反転 } } }ボタンの端が残ってしまっています。
隠しパネル内に配置したコントロールは Anchor を "Top, Right" にすることで解決できます。
ちゃんとボタンも隠れました。
- 投稿日:2019-09-29T06:46:06+09:00
.NETCore3.0がリリースされたのでVisualStudio2019からBlazorを作成してAzureにアップしてみる
はじめに
.NET Core 3.0がリリースされたので、プレビュー版ではないVisual Studio 2019からBlazorをAzureにアップできるか試してみた。
環境
ちなみに、Azure側はまだ.NET Core 3.0をサポートしていない模様。
Blazorで試すテンプレートについて
今回はBlazorサーバーアプリとBlazor WebAssembly Appを試す。
Azure側の環境
BlazorサーバーアプリとBlazor WebAssembly Appともにリソースグループは新規作成で作り、ホスティングプランは日本に変更して作成する。
この辺りは任意で。
Blazorサーバーアプリ編
新規作成でBlazorサーバーアプリを選択し、何もせずそのまま発行まで進むと、警告が出て、無理矢理デプロイするとエラーになってしまった。
回避策
Blazor WebAssembly App編
特にエラーなくアップできたが、こちらはターゲットフレームワークがnetstandard2.0になっている(前から)
これでプレビュー版が削除できる!
- 投稿日:2019-09-29T03:02:16+09:00
【Unity】RPGのレベルシステムの書き方
レベルシステム、RPG作っていれば必ず書くと言っていい処理ですが、自分流の書き方を残しておきます。
累計経験値と累計経験値に応じたレベルのテーブルがあれば、そこから現在Lvと次のLvまでの残り経験値を算出できます。
しかし、Lvを取得する度に都度計算していては流石に重たいので、累計経験値が加算される度に現Lvと残り経験値を更新するようにします。累計経験値に応じたレベルのテーブルを関数の引数にとって外部から参照してますが、これはレベルテーブルは固有な値として
static readonly
で修飾して使うことが多いためです。あるいは、UnityならScriptableObjectから参照する場合もあるでしょう。
いずれにせよ外部またはサブクラス上のstaticな値を汎用的に参照させたいので関数の引数に含めました。
ExpLevelClass.csusing System.Linq; using UnityEngine; [System.Serializable] public class ExpLevelClass { [SerializeField] int _exp; [SerializeField] int _remainExp; [SerializeField] int _minLevel; [SerializeField] int _level = 1; public int Exp => _exp; public int RemainExp => _remainExp; public int MinLevel => _minLevel; public int Level => _level; // Expを加算してLvを初期化する public void AddExp(int exp, int[] expArray) { //カンストを考慮して加算 _exp = Mathf.Clamp(_exp + exp, 0, expArray[expArray.Length - 1]); // 値の更新 UpdateLevel(expArray); UpdateRemainExp(expArray); } void UpdateLevel(int[] expArray) { // 現Exp以下の値の中で最大の値のインデックスを取得 var maxIdx = expArray.Where(x => x <= _exp).Select((val, idx) => new {V = val, I = idx}) .Aggregate((max, working) => (max.V > working.V) ? max : working).I; _level = maxIdx + 1; } void UpdateRemainExp(int[] expArray) { // 現Expより大きい値の中で最小の値のインデックスを取得 var minIdx = expArray.Where(x => x > _exp).Select((val, idx) => new {V = val, I = idx}) .Aggregate((min, working) => (min.V < working.V) ? min : working).I; _remainExp = expArray[minIdx] - _exp; } }Player.cs[System.Serializable] public class Player { public string Name = "主人公"; public ExpLevelClass ExpLevel = new ExpLevelClass(); static readonly int[] TOTAL_EXP_ARRAY = {0,100,300,600,1000}; // 経験値獲得処理 public void AddExp(int exp) { ExpLevel.AddExp(exp, TOTAL_EXP_ARRAY); } }おまけ
関数でLevelとRemainExpの計算結果を返す
ExpLevelClass.csusing System.Linq; using UnityEngine; [System.Serializable] public class ExpLevelClass { [SerializeField] int _exp; [SerializeField] int _remainExp; [SerializeField] int _minLevel; [SerializeField] int _level = 1; public int Exp => _exp; public int RemainExp => _remainExp; public int MinLevel => _minLevel; public int Level => _level; // Expを加算してLvを初期化する public (int afterLevel, int remainExp) AddExp(int exp, int[] expArray) { //カンストを考慮して加算 _exp = Mathf.Clamp(_exp + exp, 0, expArray[expArray.Length - 1]); // 値の更新 UpdateLevel(expArray); UpdateRemainExp(expArray); return (Level, RemainExp); } void UpdateLevel(int[] expArray) { // 現Exp以下の値の中で最大の値のインデックスを取得 var maxIdx = expArray.Where(x => x <= _exp).Select((val, idx) => new {V = val, I = idx}) .Aggregate((max, working) => (max.V > working.V) ? max : working).I; _level = maxIdx + 1; } void UpdateRemainExp(int[] expArray) { // 現Expより大きい値の中で最小の値のインデックスを取得 var minIdx = expArray.Where(x => x > _exp).Select((val, idx) => new {V = val, I = idx}) .Aggregate((min, working) => (min.V < working.V) ? min : working).I; _remainExp = expArray[minIdx] - _exp; } }Player.cs[System.Serializable] public class Player { public string Name = "主人公"; public ExpLevelClass ExpLevel = new ExpLevelClass(); static readonly int[] TOTAL_EXP_ARRAY = {0,100,300,600,1000}; // 経験値獲得処理 public (int afterLevel, int remainExp) AddExp(int exp) { return ExpLevel.AddExp(exp, TOTAL_EXP_ARRAY); } }参考
Linqで快適な生活を
[LINQ][C#] Aggregateの使い方(畳み込み, fold)
C# 7 の Tuple は戻り値が複数の時に便利
- 投稿日:2019-09-29T00:48:12+09:00
レベルに応じてゲームの難易度を変える実装
UNITYでゲーム作るときに難易度調整するためのデータ作りについて
ScriptableObjectを使います。
このような数値調整をUNITY上でやりたい場合のやり方です。
上記の画像にあるデータは、いくつのモノを壊したら、次のレベルに進めるか、そのレベルの難易度はどのぐらいかといったデータを表しています。
どんなゲームを作った際に使ったものか
まず、Garbagersというゲームを作ったのですが、その際の難易度などに関するデータ作りに関して作ったものです。
https://mosq.xyz/Garbagers/まず基本となるデータ
スリーマッチパズルゲームで、多くのゴミを壊すと次のレベルに進み少しづつ難しくなるゲームでした。テトリスのように。
なので、いくつ壊したら次のレベルに進めるか(int)、ゴミが出現するインターバル時間(float)を設定できるようにしました。(GVLevelInfo)
さらに、ゴミがつっかえて溜まってくるとゴミが速く出るようにしました。
横、縦への速度、回転速度、インターバルを指定できるようにしました。(GVPressureInfo)LevelClasses.csusing System; using System.Collections; using System.Collections.Generic; using UnityEngine; [Serializable] public class GVLevelInfo { public int NextBlockCount; public float SpawnInterval = 0f; } [Serializable] public class GVPressureInfo { public float HorizontalSpeed; public float VerticalSpeed; public float AngularSpeed; public float Interval; }[Serializable]アトリビュートをつけておく必要があります。
これらをレベルごとに用意するためリストにします。
それとScriptableObjectにして、UNITY上に置けるデータにします。
(全部publicで書いちゃってますが、UNITYでは[SerializeField]アトリビュートをつけても、シリアライズされます)GVLevelInfoのリスト化したScriptableObjectを作る
class宣言以降、三行だけが重要であとはおまけの関数です。
GVLevelInfoList.csusing System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class GVLevelInfoList : ScriptableObject { public List<GVLevelInfo> List = new List<GVLevelInfo>(); public int GetLevel(int breakCount) { int level = 0; foreach(var v in List) { if (v.NextBlockCount <= breakCount) { ++level; continue; } break; } return level; } public float ToNextRatio(int level,int breakCount) { int prevCount = 0; if (0 <= level-1) { prevCount = List[level-1].NextBlockCount; } if (level < List.Count) { var v = List[level]; return (breakCount - prevCount) / (float)(v.NextBlockCount-prevCount); } return 1f; } }GVPressureInfoのリストも同様に作ります。
GVPressureInfoList.csusing System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class GVPressureInfoList : ScriptableObject { public List<GVPressureInfo> List = new List<GVPressureInfo>(); public GVPressureInfo GetPressure(int pressure) { return List[Mathf.Clamp(pressure,0,List.Count-1)]; } }ということで、データ構造としては用意できました。
あとは、このデータをUNITYプロジェクトの中に追加する方法です。Editorフォルダを作ります
UNITYにおいて、Editorフォルダは特別な名前です。
ここに置かれたスクリプトファイルは、UNITYエディタ上でのみ利用され、ビルドして出力したアプリなどには含まれません。
エディタ上で、データを作ったりする際に使います。LevelInfoMenu.csusing System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; public static class LevelInfoMenu { [MenuItem ("Create/CreateGVLevelInfoList")] static void CreateGVLevelInfoList () { var asset = ScriptableObject.CreateInstance<GVLevelInfoList> (); AssetDatabase.CreateAsset (asset, "Assets/LevelInfoList.asset"); AssetDatabase.Refresh (); } [MenuItem ("Create/CreateGVPressureInfoList")] static void CreatePressureInfoList () { var asset = ScriptableObject.CreateInstance<GVPressureInfoList> (); AssetDatabase.CreateAsset (asset, "Assets/PressureInfoList.asset"); AssetDatabase.Refresh (); } }このスクリプトを書くと、UNITYのトップメニューにCreateが追加されています。
実行すると、指定されたパスの場所にデータが追加されます。
インスペクター上で、データを編集することが可能です。保存場所を選べるようにしたい場合は、下記のような関数を使います。
https://docs.unity3d.com/ja/current/ScriptReference/EditorUtility.SaveFilePanel.html
→プロジェクト内に保存する場合は、こっちでした。
https://docs.unity3d.com/ScriptReference/EditorUtility.SaveFilePanelInProject.htmlこれをゲームで使っていきます。
実際に使う
普通に、MonoBehaviourにインスペクタから設定することができます。
GarbagersSystem.csusing System.Collections; using System.Collections.Generic; using UnityEngine; public class GarbagersSystem : MonoBehaviour { [SerializeField] LevelInfoUI _levelInfo; [SerializeField] GVPressureInfoList _pressureInfo; ...インスペクタに先ほどのメニューから作ったデータをドラッグ&ドロップすればデータが入るので、使いましょう。