当Button失踪时,Unity缺少警告OnClick

时间:2017-03-14 11:08:18

标签: c# unity3d

当任何Button组件缺少方法时,有没有办法获得某种信息或警告?

我的意思是当你为Button实现一个方法时,在场景中分配该方法然后,例如重命名方法,重命名不会更新场景中的方法调用,因此它显示“< Missing ScriptName.OldMethodName>”。

当发生这种情况时,我希望得到通知 - 至少在按下播放时,或者至少在部署应用程序时。

2 个答案:

答案 0 :(得分:4)

斯科特的answer非常接近你正在做的事情,并得出了这个答案。虽然缺少这么多东西。您需要做更多工作才能使该脚本正常工作。

1 。您需要使用Resources.FindObjectsOfTypeAll获取场景中的所有按钮(包括非活动/禁用的按钮)。

2 。点击按钮,检查包含该功能的类/脚本是否存在反射。你这样做是因为有时我们重命名脚本。这可能会导致问题。显示脚本的消息不存在。

您只需检查Type.GetType(className);是否为null

即可

如果是null,那么请不要同时进行下面的测试,因为包含Button onClick功能的组件已被重新命名。显示一条错误消息,指出此脚本已被删除或重命名。

3 。如果该类存在,现在检查该函数是否存在于class注册到Button的onClick事件中的反射。< / p>

只需检查type.GetMethod(functionName);是否为null即可完成。

如果函数存在,那么Button就可以了。如果函数存在,您不必显示消息。停在这里。

如果返回null,则继续#4

4 。检查函数是否存在,但这一次,检查函数是否使用private 访问修饰符声明

这是人们犯的典型错误。他们将函数声明为public,通过编辑器进行分配,然后将其从public错误地更改为private。这应该有效,但将来会引起问题。

只需检查type.GetMethod(functionName, BindingFlags.Instance | BindingFlags.NonPublic);是否为null即可完成。

如果该功能存在,请显示一条消息,警告您此功能的访问修饰符已从public更改为private,应更改回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;
    }
}

答案 1 :(得分: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
        }
    }
}