事件功能未按预期工作

时间:2018-02-16 00:58:18

标签: c# function unity3d event-handling unity5

首先,我将解释发生的事情,然后是我期待发生的事情,最后是它背后的代码

所以发生的事情就是当我按下输入时,文字的颜色是绿色

我期望发生的是颜色变红

这是基于我是否在字段中输入“Bad”

//Please note I have edited uni9mportant code out

//Event Listener
inputField.onEndEdit.AddListener (delegate {
            VerifyWords();
});

//Clss that handles the dictionary
public abstract class WordDictionary: MonoBehaviour{
    public static Dictionary<string,bool> _wordDictionary = new Dictionary<string,bool> ();

    private void Start(){
        _wordDictionary.Add ("Bad",true);
    }
}

//Function that handles the word verification
private void VerifyWords(){
        if (openChat == false) { //If we done have open chat
            bool hasBadWords = false; //Reset boolean
            string[] stringSplit = inputField.text.Split (' '); //Split text string

            for (int i = 0; i < stringSplit.Length; i++) { // Go through each word in the string array
                if (WordDictionary._wordDictionary.ContainsKey (stringSplit[i])) { //If the word is in the dictionary
                    hasBadWords = true; //Then there is a bad word
                }
            }

            if (hasBadWords == true) { //If a bad word was found
                inputField.textComponent.color = Color.red; //Then the text should be red
            } else {
                inputField.textComponent.color = Color.green; //The text should be green
            }
        }
    }

EDIT 我编写了带有注释的代码,以便将我的想法付诸实践

2 个答案:

答案 0 :(得分:4)

问题是该类被标记为abstract。抽象类无法实例化,因此Unity无法在无法实例化的类上调用Start。最简单的解决方法是从类定义中删除abstract

public class WordDictionary: MonoBehaviour{
    public static Dictionary<string,bool> _wordDictionary = new Dictionary<string,bool> ();

    private void Start(){
        _wordDictionary.Add ("Bad",true);
    }
}

但是你现在遇到了一个新问题。 WordDictionary有一个静态成员,由非静态方法初始化。这意味着每次您创建新的WordDictionary时,都会调用Start(),它会将所有单词添加到字典中再次(或者至少它会尝试,在这种情况下,您将获得重复的密钥异常,以避免您也可以编写_wordDictionary["Bad"] = true来替换现有密钥(如果存在)。

这里更好的选择是使用静态构造函数。这将确保字典仅初始化一次:

public class WordDictionary: MonoBehaviour{
    public static Dictionary<string,bool> _wordDictionary = new Dictionary<string,bool> ();

    static WordDictionary() {
        _wordDictionary.Add ("Bad",true);
    }

    private void Start(){
    }
}

现在,您可以使用WordDictionary,而无需担心每次实例化类时字典都会增长。但是在这一点上真的没有用WordDictionary MonoBehavior,因为它实际上只是一堆词的持有者。所以你的班级现在变成了:

public class WordDictionary: {
    private static Dictionary<string,bool> _wordDictionary = new Dictionary<string,bool> ();

    public static Dictionary<string, bool> Words {
        get { return _wordDictionary; }
    }

    static WordDictionary() {
        _wordDictionary.Add ("Bad",true);
    }
}

我在这里添加了一个属性,因为你应该使用属性,并且使用下划线名称(在我的代码世界中)意味着它是一个私有字段。您可以扩展字典以执行其他操作:

public class WordDictionary: {
    private static List<string> _wordList = new List<string> ();

    static WordDictionary() {
        _wordList.Add ("Bad");
    }

    public static Contains(string word) {
        return _wordList.Contains(word);
    }

    public static ContainsAny(IEnumerable<string> words) {
        return words.Any(w => Contains(w));
    }
}

我认为没有理由在这里使用Dictionary,如果它包含单词那么它就是“坏”,如果它不包含单词那么它就会“好”。因此,更改为列表会使事情变得更简单。如果隐藏“Dictionary”在后台工作的方式,只显示“包含”和“包含任何”方法,您将获得两个优点,使用变得更简单,您可以在不更改接口和下游的情况下更改底层“引擎”代码。

现在您的着色功能变得更加简单:

private void VerifyWords() {
    if (openChat)
        return;

    var stringSplit = inputField.text.Split(' ');

    if (WordDictionary.ContainsAny(stringSplit))                
        inputField.textComponent.color = Color.red;
    else
        inputField.textComponent.color = Color.green;
}

答案 1 :(得分:2)

首先,我建议您不要将MonoBehaviour用于WordDictionary。我认为没有理由这样做。 Insted使用ScriptableObject。

其次它不需要是抽象的,我不认为你需要一个字典就可以了,假设你只存储'坏'字。

e.g。 (我在这里使用了dicitonary,可以列出假设你的要求仅适用于存储的坏词)

[CreateAssetMenu(menuName = "Custom Object/Word Dictionary")]
public class WordDictionary : ScriptableObject
{
    public Dictionary<string, bool> Values = new Dictionary<string, bool>();
}

脚本对象在您的资源中创建,可以在场景中由GameObjects引用。所以在需要使用dicitonary的gameObjects中添加一个

public WordDictionary gameDictionary;

并将其设置为您在资源中创建的字典。一般来说,单声道/静态类和使monoBehaviour像静态对象一样行为的类似方法会导致问题。

可编写脚本的对象是一个很好的解决方法。它们在游戏开始时可以像单身一样没有初始化,它们可以像任何其他类一样包含数据或函数,但与MonoBehaviour不同,它们没有Start,Update等等......并不意味着你可以调用AtStart()但是,你可以在游戏中的某些特定的初始化行为中写入Scriptable对象。

一个重要的注意事项,在编辑器中,脚本化对象中更新的数据仍然存在,在运行时它不会。例如在编辑器中测试你的游戏时,会话之间会保留“坏”字样......在构建中它不会,但我认为你正在准备关于游戏初始化的字典,所以这应该是一个非问题。