2017-03-14 18 views
2

Buttonコンポーネントに欠落しているメソッドがある場合、何らかの情報や警告を得る方法がありますか?Buttonに不足があると警告が表示されないOnClick

私が言っていることは、ボタンのメソッドを実装するときに、そのメソッドをシーンに割り当ててから、次にそのメソッドを割り当てることです。メソッドの名前を変更すると、名前の変更によってシーン内のメソッド呼び出しが更新されず、 "< Missing ScriptName.OldMethodName>"と表示されます。

これが発生したとき、少なくとも再生を押すとき、または少なくともアプリケーションを配備するときは通知を受けたいと思います。

+0

これは、デザイナーではなくコードで 'onClick'イベントを設定することで回避できます。 – Smartis

答えて

4

スコットのanswerは、あなたがやっていることに非常に近いエラーを発射し、この答えにつながったことができます。それは非常に多くのものが欠けていますが。このスクリプトを動作させるには、もっと多くの作業が必要です。

Resources.FindObjectsOfTypeAllでシーン内のすべてのボタン(非アクティブ/無効のボタンを含む)を取得する必要があります。

ボタンを押して、その機能を保持するクラス/スクリプトがリフレクションで存在するかどうかを確認します。これは、スクリプトの名前を変更することがあるためです。これは問題を引き起こす可能性があります。スクリプトのShowメッセージが存在しません。

これは、Type.GetType(className);nullであるかどうかを単に確認することで可能です。

の場合は、ButtononClickの機能を保持するコンポーネントの名前が変更されているため、以下の両方のテストも行わないでください。このスクリプトが削除または再命名されたことを示すエラーメッセージを表示します。クラス.IF

機能はボタンのonClickイベントに登録されていることclassに反射して存在するかどうかを確認今、存在しています。

これは、type.GetMethod(functionName);nullであるかどうかを単にチェックすることによって行うことができます。

この関数が存在する場合、そのボタンは正常です。関数が存在する場合、メッセージを表示する必要はありません。ここで止​​まって。

nullを返す場合は、#4に進みます。

.Check機能の場合は存在しますが、機能がprivateアクセス修飾子で宣言されている場合、この時間は、確認してください。

これは一般的な間違いです。彼らはpublicとして機能を宣言し、それをエディタで割り当ててから間違ってpublicからprivateに変更します。これはうまくいくはずですが、将来問題を引き起こす可能性があります。

これは、type.GetMethod(functionName, BindingFlags.Instance | BindingFlags.NonPublic);nullであるかどうかを単にチェックすることによって行うことができます。

関数が存在する場合

は、この関数のアクセス修飾子が privatepublicから変更されたと publicに戻すべきであることを警告するメッセージが表示されます。

この機能が存在しない場合は、この機能が存在しないか、または名前が変更されたことを警告するメッセージを表示します。

以下は、上記のすべてを実行するスクリプトです。それを空のGameObjectに貼り付け、エディタでゲームを実行するときはいつでもその仕事をします。

using System; 
using System.Reflection; 
using UnityEngine; 
using UnityEngine.UI; 

public class MissingOnClickDetector : MonoBehaviour 
{ 
    void Awake() 
    { 
     //Debug.Log("Class exist? " + classExist("ok.ButtonCallBackTest")); 
     searchForMissingOnClickFunctions(); 
    } 

    void searchForMissingOnClickFunctions() 
    { 
     //Find all Buttons in the scene including hiding ones 
     Button[] allButtonScriptsInScene = Resources.FindObjectsOfTypeAll<Button>() as Button[]; 
     for (int i = 0; i < allButtonScriptsInScene.Length; i++) 
     { 
      detectButtonError(allButtonScriptsInScene[i]); 
     } 
    } 

    //Searches each registered onClick function in each class 
    void detectButtonError(Button button) 
    { 
     for (int i = 0; i < button.onClick.GetPersistentEventCount(); i++) 
     { 
      //Get the target class name 
      UnityEngine.Object objectName = button.onClick.GetPersistentTarget(i); 

      //Get the function name 
      string methodName = button.onClick.GetPersistentMethodName(i); ; 

      //////////////////////////////////////////////////////CHECK CLASS/SCRIPT EXISTANCE///////////////////////////////////////// 

      //Check if the class that holds the function is null then exit if it is 
      if (objectName == null) 
      { 
       Debug.Log("<color=blue>Button \"" + button.gameObject.name + 
        "\" is missing the script that has the supposed button callback function. " + 
        "Please check if this script still exist or has been renamed</color>", button.gameObject); 
       continue; //Don't run code below 
      } 

      //Get full target class name(including namespace) 
      string objectFullNameWithNamespace = objectName.GetType().FullName; 

      //Check if the class that holds the function exist then exit if it does not 
      if (!classExist(objectFullNameWithNamespace)) 
      { 
       Debug.Log("<color=blue>Button \"" + button.gameObject.name + 
        "\" is missing the script that has the supposed button callback function. " + 
        "Please check if this script still exist or has been renamed</color>", button.gameObject); 
       continue; //Don't run code below 
      } 

      //////////////////////////////////////////////////////CHECK FUNCTION EXISTANCE///////////////////////////////////////// 

      //Check if function Exist as public (the registered onClick function is ok if this returns true) 
      if (functionExistAsPublicInTarget(objectName, methodName)) 
      { 
       //No Need to Log if function exist 
       //Debug.Log("<color=green>Function Exist</color>"); 
      } 

      //Check if function Exist as private 
      else if (functionExistAsPrivateInTarget(objectName, methodName)) 
      { 
       Debug.Log("<color=yellow>The registered Function \"" + methodName + "\" Exist as a private function. Please change \"" + methodName + 
        "\" function from the \"" + objectFullNameWithNamespace + "\" script to a public Access Modifier</color>", button.gameObject); 
      } 

      //Function does not even exist at-all 
      else 
      { 
       Debug.Log("<color=red>The \"" + methodName + "\" function Does NOT Exist in the \"" + objectFullNameWithNamespace + "\" script</color>", button.gameObject); 
      } 
     } 
    } 

    //Checks if class exit or has been renamed 
    bool classExist(string className) 
    { 
     Type myType = Type.GetType(className); 
     return myType != null; 
    } 

    //Checks if functions exist as public function 
    bool functionExistAsPublicInTarget(UnityEngine.Object target, string functionName) 
    { 
     Type type = target.GetType(); 
     MethodInfo targetinfo = type.GetMethod(functionName); 
     return targetinfo != null; 
    } 

    //Checks if functions exist as private function 
    bool functionExistAsPrivateInTarget(UnityEngine.Object target, string functionName) 
    { 
     Type type = target.GetType(); 
     MethodInfo targetinfo = type.GetMethod(functionName, BindingFlags.Instance | BindingFlags.NonPublic); 
     return targetinfo != null; 
    } 
} 
+0

広範な応答、プログラマーとスコットありがとう。 私はこのことをもっとよく見ていきます。 – Tavados

+0

小さなバグを見つけて修正しました。名前空間のサポートが追加されました。 'classExist(objectName.name)'を '!classExist(objectFullNameWithNamespace)'に置き換えました。更新されたコードを確認してください。最初のコードでもうまく動作するはずです。この更新されたコードはうまくいくはずです。問題がある場合は教えてください。 – Programmer

2

あなたはボタンクラスを拡張し、名前が欠落している含まれている場合は、イベントカウント+メソッド名をチェックし、

using UnityEngine.UI; 

public class SafeButton : Button 
{ 
    override protected void Awake() 
    { 
     for (int i = 0; i < onClick.GetPersistentEventCount(); i++) 
     { 
      var methodName = onClick.GetPersistentMethodName(i); 
      // if method name contains "missing" 
       // -> Log Error 
     } 
    } 
} 
+0

いいえ、動作しません。 'GetPersistentMethodName(index)'は登録時の元のメソッド名を返します(ドロップダウンメニューから追加したとき)、その名前がスクリプト内で変更されても変更されません。 – Galandil

+0

@Galandilこの回答は正しいです。 OPはエディタからイベントを割り当てることを話していました。 ** "私が言っていることは、ボタンのメソッドを実装し、そのメソッドをシーンに割り当てた後、メソッドの名前を変更すると、その名前がシーンのメソッド呼び出しを更新しないことと" ** .. .. – Programmer

+0

@Programmer、自分で試してみてください。https://www.dropbox.com/s/nuucvxzbp49tad4/PersistentEvent.zip?dl=0 - 一度実行すると、コンソールに 'Test'メソッドが表示されます名。スクリプト内で 'Test1'に変更してプロジェクトをもう一度実行すると、コンソールのメソッド名は変更されていませんが、インスペクタでは' '。 – Galandil

関連する問題