質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

2605閲覧

【Unity,C#】値が変更した時に変更前の値と変更後の値を持ったeventを発行したい

Y0241-N

総合スコア1066

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

1クリップ

投稿2021/11/05 05:10

編集2021/11/08 07:22

前提・実現したいこと

現在、ドロップリストにEnumを登録し、ドロップリストからEnumの値を選択して変更できるようにしました。
これを、例えばEnum1からEnum2に変更されたときのみに通知を出し、Enumが定義されているスクリプトを直接参照せずに
通知を受け取った側でなんらかの処理を実行する仕組みを作りたいと考えています。

色々調べてみて一件だけやりたいことに近いことをしている記事はあったのですが、delegateとeventの使い方が
よくわからず困っています。どのようにすれば通知の発行、受け取りを行えますでしょうか?

該当のソースコード

cs

1using System; 2using System.Collections; 3using System.Collections.Generic; 4using UnityEngine; 5using TMPro; 6 7public class PCB_LM_StateMgr : MonoBehaviour 8{ 9 public enum LearningMode 10 { 11 Show_Only_MouseOver = 0, 12 Allways_Show = 1, 13 Allways_Hide = 2, 14 } 15 16 public static LearningMode _State = LearningMode.Show_Only_MouseOver; 17 public delegate void EnumPropertyChangedDelegate(object sender, Enum newValue); 18 public event EnumPropertyChangedDelegate EnumPropertyChanged; 19 public LearningMode EnumProperty 20 { 21 get{return _State;} 22 23 set 24 { 25 if(value != _State) 26 { 27 _State = value; 28 EnumPropertyChanged?.Invoke(this, _State); 29 } 30 } 31 } 32 33 private TMP_Dropdown DropdownList; 34 35 void Start() 36 { 37 DropdownList = GetComponent<TMP_Dropdown>(); 38 39 string[] StateName = new string[] {"マウスオーバー時のみ表示","常に表示","常に非表示"}; 40 41 //Stringの配列をリストに変換 42 List<string> names = new List<string>(StateName); 43 44 DropdownList.ClearOptions(); 45 //DropDownの要素にリストを追加 46 DropdownList.AddOptions(names); 47 } 48 49 public void Change_PCBox_State() //DropdownList の OnValueChange に登録する 50 { 51 _State = (LearningMode)DropdownList.value; 52 } 53}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Y0241-N

2021/11/08 02:16

アドバイスありがとうございます。 記事の方拝見させていただきましたが、難しいですね... 目的としてる動作は、ドロップリストから値を変更、変更時に変更された値をイベントとして発行し、受け取り側が発行された値に基づいた処理を実行する。という流れを目指しています。
YAmaGNZ

2021/11/08 07:34

DropdownListで値が変更された時にChange_PCBox_Stateが呼ばれるんですかね? それであればEnumPropertyのsetterを介さずに_Stateへ代入するとイベントが発生しないのでは?
Y0241-N

2021/11/08 08:20

>DropdownListで値が変更された時にChange_PCBox_Stateが呼ばれるんですかね? はい、その通りです。現状は見ての通り_Stateに変更された値を代入して別スクリプトで_Stateを取得しています。 EnumPropertyなどは質問文中の記事を参考に見よう見まねで実装したため、具体的な使い方が分からないという状態です。_StateをEnumPropertyに変更したとして、別スクリプトからEnumPropertyを参照してどのようにすればよろしいでしょうか?
YAmaGNZ

2021/11/08 08:29

Unityに関しては私も詳しくないのでさっと検索しただけですが 「UnityAction」や「UnityEvent」について検索してみるといいかと思います。
guest

回答2

0

ベストアンサー

UnityEventを使ってやってみました。
(11/10 古い値、新しい値を渡していなかったのでソース変更)

Dropdownにアタッチしたスクリプト

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.UI; 5using UnityEngine.Events; 6 7public class PCB_LM_StateMgr : MonoBehaviour 8{ 9 public enum LearningMode 10 { 11 Show_Only_MouseOver = 0, 12 Allways_Show = 1, 13 Allways_Hide = 2, 14 } 15 16 [SerializeField] public UnityEvent<(LearningMode oldvalue, LearningMode newvalue)> OnPropertyChanged = new UnityEvent<(LearningMode oldvalue, LearningMode newvalue)>(); 17 18 19 public static LearningMode _State = LearningMode.Show_Only_MouseOver; 20 public LearningMode EnumProperty 21 { 22 get{return _State;} 23 24 set 25 { 26 if(value != _State) 27 { 28 var oldvalue = _State; 29 var newvalue = value; 30 31 _State = value; 32 OnPropertyChanged.Invoke((oldvalue, newvalue)); 33 } 34 } 35 } 36 37 private Dropdown DropdownList; 38 39 void Start() 40 { 41 DropdownList = GetComponent<Dropdown>(); 42 43 string[] StateName = new string[] {"マウスオーバー時のみ表示","常に表示","常に非表示"}; 44 45 //Stringの配列をリストに変換 46 List<string> names = new List<string>(StateName); 47 48 DropdownList.ClearOptions(); 49 //DropDownの要素にリストを追加 50 DropdownList.AddOptions(names); 51 } 52 53 public void Change_PCBox_State(int value) //DropdownList の OnValueChange に登録する 54 { 55 EnumProperty = (LearningMode)DropdownList.value; 56 } 57 58} 59

Textにアタッチしたスクリプト

C#

1using UnityEngine; 2using UnityEngine.UI; 3 4public class TextChanger : MonoBehaviour 5{ 6 Text textbox; 7 8 void Start() 9 { 10 textbox = GetComponent<Text>(); 11 } 12 13 public void PropertyChangedHandler((PCB_LM_StateMgr.LearningMode oldvalue, PCB_LM_StateMgr.LearningMode newvalue) values) 14 { 15 textbox.text = $"{values.oldvalue}→{values.newvalue}"; 16 } 17 18} 19

イメージ説明
こんな感じでインスペクタでプロパティが変化したときに実行するメソッドを設定

これでプロパティが変化したときにOnPropertyChangedが発生し、そのイベントでTextが変化します。

インスペクタ上での設定ではなく

C#

1var drop = GameObject.Find("TestDropdown"); 2var script = drop.GetComponent<PCB_LM_StateMgr>(); 3script.OnPropertyChanged.AddListener(PropertyChangedHandler);

みたいな感じでスクリプトでリスナーを追加することもできます。

今回はイベントリスナーの引数としてタプルを使いましたが、下記のようなイベント情報格納用のクラスを用意して受け渡すほうがいいかもしれません。

C#

1 public class PropertyChangedEventArgs 2 { 3 public LearningMode oldvalue { get; } 4 public LearningMode newvalue { get; } 5 6 public PropertyChangedEventArgs(LearningMode oldvalue, LearningMode newvalue) 7 { 8 this.oldvalue = oldvalue; 9 this.newvalue = newvalue; 10 } 11 }

投稿2021/11/08 11:58

編集2021/11/09 23:01
YAmaGNZ

総合スコア10294

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Y0241-N

2021/11/10 03:54

回答ありがとうございます。 現在別件で多忙な為、時間が確保出来次第試させていただきます。
guest

0

これじゃダメですか

C#

1using System; 2using System.Collections; 3using System.Collections.Generic; 4using UnityEngine; 5using TMPro; 6using UnityEngine.Events; //追加 7 8public class PCB_LM_StateMgr : MonoBehaviour 9{ 10 public enum LearningMode 11 { 12 Show_Only_MouseOver = 0, 13 Allways_Show = 1, 14 Allways_Hide = 2, 15 } 16 17 public static LearningMode _State = LearningMode.Show_Only_MouseOver; 18 public delegate void EnumPropertyChangedDelegate(object sender, Enum newValue); 19 public event EnumPropertyChangedDelegate EnumPropertyChanged; 20 public LearningMode EnumProperty 21 { 22 get{return _State;} 23 24 set 25 { 26 if(value != _State) 27 { 28 _State = value; 29 EnumPropertyChanged?.Invoke(this, _State); 30 } 31 } 32 } 33 34 private TMP_Dropdown DropdownList; 35 36 void Start() 37 { 38 DropdownList = GetComponent<TMP_Dropdown>(); 39 40 string[] StateName = new string[] {"マウスオーバー時のみ表示","常に表示","常に非表示"}; 41 42 //Stringの配列をリストに変換 43 List<string> names = new List<string>(StateName); 44 45 DropdownList.ClearOptions(); 46 //DropDownの要素にリストを追加 47 DropdownList.AddOptions(names); 48 DropdownList.onValueChanged.AddListener(new UnityAction<int>(Change_PCBox_State)); //追加 49 } 50 51//引数追加 52 public void Change_PCBox_State(int num) //DropdownList の OnValueChange に登録する 53 { 54 _State = (LearningMode)num; // numに変更 55 Debug.Log(_State); //ログ追加 56 } 57} 58 59

投稿2021/11/08 08:51

U_U_Jenkins

総合スコア110

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Y0241-N

2021/11/08 08:56

回答ありがとうございます。 これは単にDropdownListへの登録をスクリプトから行うように変更されただけだと思うのですが、 であれば残念ながら私の意図する内容とは異なります。
U_U_Jenkins

2021/11/08 09:05

>>DropdownListで値が変更された時にChange_PCBox_Stateが呼ばれるんですかね? >はい、その通りです。現状は見ての通り_Stateに変更された値を代入して別スクリプトで_Stateを取得しています。 大変失礼いたしました。 これだけ見てこれを目的だと勘違いしていました。 >ドロップリストから値を変更、変更時に変更された値をイベントとして発行し、受け取り側が発行された値に基づいた処理を実行する。という流れを目指しています。 こちらですね... もう少し考えてみますので時間をください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問