2017-03-03 10 views
1

私は、必要なときにUI要素を設定するのに役立つ静的関数をたくさん作成しました。ビルドユニットメニューやリソースグラフ(これは戦略ゲームのためのものです)。私はデリゲートとアクションを使用して、ボタンの初期化ボタンにボタンのonClickイベントを登録する関数を渡すことができました。これまでのところ、これはうまくいきました。(Unity)ボタンを作成してデリゲート(またはアクション)を与え、そのデリゲートに参照パラメータを与える

しかし、テキスト値を変更できるテキストフィールド(たとえば、プレーヤーが購入したいアイテムの数など)を変更すると、代理人は参照を取得しません。したがって、メニューを開くと、メニューの入力フィールドは0.0になり、関数Buy(0.0f)が呼び出されます。しかし、入力フィールドの値を3.0に変更しても、ボタンは依然としてBuy(0.0f)を呼び出します。これは、その値が作成されたときの値であるためです。

奇妙なことですが、私は最近までこの問題を抱えていませんでした。参照してください、私の通常のボタン付き入力フィールドプレハブにはボタンがあり、そのボタンには入力フィールドがありません。これは、入力フィールドの位置を常に知っているため、ボタンがFieldのテキストを参照として扱うことができることを意味します。 FieldButtonを作成する関数は次のとおりです。

// Function to quickly set up a numeric field button. 
// This accomodates a function with a single float parameter. 
public delegate void floatDel(float f); 
public static GameObject InitFieldButton(Transform parent, Vector3 position, string text, floatDel function) 
{ 
    GameObject newElement = GameObject.Instantiate(fieldButton); 
    // Establish UI transform data. 
    newElement.transform.SetParent(parent); 
    newElement.transform.localPosition = position; 
    newElement.transform.GetChild(0).GetComponent<Text>().text = text; 

    // Assign the argued function to the button, with the input text as a parameter to that function. 
    newElement.GetComponent<Button>().onClick.AddListener(delegate { function(float.Parse(newElement.GetComponentInChildren<InputField>().text)); }); 
    return newElement; 
} 

これは機能します。入力フィールドの値を変更すると、ボタンは更新された値で関数を呼び出します。

しかし、私はまた、プレイヤーに多くの異なるものを購入させたいが、ある量を指定する必要があるために、1つの入力フィールドを参照するボタンをたくさん使用しています。これは明らかにボタンと入力フィールドの2つのプレハブです。私はInitButton()関数で全く同じことをやっています:

このオーバーロードは、2つのパラメータ、つまり取引の良い、および取引される数量を持つ関数に対応しています。

public delegate void purchaseDel(Good g, float f); 
public static GameObject InitButton(Transform parent, Vector3 position, string text, purchaseDel function, Good good, GameObject inputField) 
{ 
    GameObject newElement = GameObject.Instantiate(button); 
    // Establish UI transform data. 
    newElement.transform.SetParent(parent); 
    newElement.transform.localPosition = position; 
    newElement.GetComponentInChildren<Text>().text = text; 

    // Assign the function delegated to this button. 
    newElement.GetComponent<Button>().onClick.AddListener(delegate { function(good, float.Parse(inputField.GetComponent<InputField>().text)); }); 
    return newElement; 
} 

私は多くのことを試しました。私がonClickに渡しているような匿名関数はrefを取ることができないので、 'ref'の使用はオプションではないようです。私は現在、ボタンに必要なすべてのデータを保存するためのカスタムスクリプトを提供することを目指していますが、これは面倒で本当に非ジェネリックなものになると思います。

これは非常に一般的なことです。より良い方法がありますか?

答えて

1

自分で解決しました。私は非常にばかげていました。

問題は、実際にはMenuクラスであり、ボタンでどのように投入されたかです。

// Create a buy button for every type of good that can be bought. 
for (int g = 0; g < SGoods.Instance.goodsList.Count - 1; g++) 
     { 
      // Get the text input for how much the player wants to buy. 
      GameObject buyQuantity = MenuElements.InitField(transform, 
       new Vector3(205.0f, -40.0f)); 

      // Call the Button initialiser. 
      GameObject buyButton = MenuElements.TestInitButton(transform, 
       new Vector3(205.0f, -60.0f - 30.0f * g), 
       "Buy", 
       market.BuyFrom, 
       SGoods.Instance.goodsList[g], 
       buyQuantity.GetComponent<InputField>()); 
     } 

私はそれだけのものを作りたかったのにもかかわらず、のためのループ内buyQuantity入力フィールドの変数を置きます。それから私はfor-loopのすべてのループで上書きしていました。この理由から、最後のものを除いて、無視されたすべてのボタンは入力フィールドに変更されます...

不思議なことに、このコードを再入力した後、私は今これについて正確に警告するエラーを受け取ります。私はこれが以前にどのようにしていたのか、間違いはないと確信しています。

とにかく、Unityがオブジェクトのリファレンスを一度持っていれば、リファレンスタイプとして保持することができます。

GameObject buyQuantity = MenuElements.InitField(transform, 
      new Vector3(205.0f, -40.0f)); 

for (int g = 0; g < SGoods.Instance.goodsList.Count - 1; g++) 
{ 
    // Call the Button initialiser. 
    GameObject buyButton = MenuElements.TestInitButton(transform, 
     new Vector3(205.0f, -60.0f - 30.0f * g), 
     "Buy", 
     market.BuyFrom, 
     SGoods.Instance.goodsList[g], 
     buyQuantity.GetComponent<InputField>()); 
} 

は最終的に、これは空想何を必要としない:私はちょうどループの外の参照を宣言しました。 refキーワードなし、クレイジーラムダ関数なし。ちょうど通常の匿名の代理人がうまく動作します。 Menuクラスに保持されているInputFieldで十分です。

public static GameObject TestInitButton(Transform parent, Vector3 position, string text, purchaseDel function, Good good, InputField inputField) 
{ 
    GameObject newElement = GameObject.Instantiate(button); 
    newElement.transform.SetParent(parent); 
    newElement.transform.localPosition = position; 
    newElement.GetComponentInChildren<Text>().text = text; 

    // Assign the function delegated to this button. 
    newElement.GetComponent<Button>().onClick.AddListener(() => function.Invoke(good, float.Parse(inputField.text))); 
    return newElement; 
} 
関連する問題