首先,我将解释发生的事情,然后是我期待发生的事情,最后是它背后的代码
所以发生的事情就是当我按下输入时,文字的颜色是绿色
我期望发生的是颜色变红
这是基于我是否在字段中输入“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 我编写了带有注释的代码,以便将我的想法付诸实践
答案 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对象。
一个重要的注意事项,在编辑器中,脚本化对象中更新的数据仍然存在,在运行时它不会。例如在编辑器中测试你的游戏时,会话之间会保留“坏”字样......在构建中它不会,但我认为你正在准备关于游戏初始化的字典,所以这应该是一个非问题。