перечисление, на которое ссылаются скрипты gameobject с помощью переменных-инспекторов, выходят из строя, когда перечисление содержит новые записи, добавленные до указанного индекса.
Поэтому у меня есть несколько систем, таких как списки элементов, строки локализации и т.д., Которые динамически создаются путем разбора внешних файлов. Этот синтаксический анализ создает перечисление, которое используется для ссылки на элементы с помощью игрового объекта через переменные инспекторов скрипта. Здесь проанализирован вывод моей системы локализации в качестве примера:
public enum LocaleID
{
LocalisedStrings_ENGB,
LocalisedStrings_ENUS,
//...
MAX,
}
public enum StringID
{
String_EMPTY,
String_Inventory,
String_Recipes,
String_Tools,
String_Journal,
//...
}
public static class LocalisedStrings
{
private static string[] SCLocalisedStrings_ENGB =
{
"",
"Inventory",
"Recipes",
"Tools",
"Journal",
//...
}
private static LocaleID currentLocale = (LocaleID)0;
private static string[] activeSC = SCLocalisedStrings_ENGB;
public static void SetLocale(LocaleID newLocale)
{
currentLocale = newLocale;
switch(newLocale)
{
case LocaleID.LocalisedStrings_ENGB:
activeSC = SCLocalisedStrings_ENGB;
break;
case LocaleID.LocalisedStrings_ENUS:
activeSC = SCLocalisedStrings_ENUS;
break;
}
}
//entry interface:
public static string Get(StringID stringID)
{
return activeSC[(int)stringID];
}
}
Это просто возвращает строку через индекс перечисления, основанный на заданной локали. Поэтому у меня было бы что-то вроде имени NPC, выставленного на персонаже, как:
[SerializeField]
public StringID SpeakerTitle;
и установить это через инспектора.
Проблема является довольно очевидной и ожидаемой: если перечисление анализируется по-разному, например, добавляется дополнительная запись вверх (например, для сортировки) или удаляется (для очистки устаревших записей), тогда все ссылочные перечисления станут не по порядку на 1 место, так как они будут ссылаться на индекс записи перечисления.
Простым решением было бы наложить правило только добавления к концу и никогда не удалять записи, которые становятся устаревшими. Это становится довольно расточительным, поэтому, очевидно, не очень предпочтительным.
Какие предлагаются решения этой проблемы? Любые примеры того, как другие подходят к этой довольно распространенной ситуации? Мое предпочтение было бы, конечно, тем, что можно было бы отсортировать, а новые записи добавлены в любом месте, но у нас не может быть всего, что мы хотим :)
Просто укажите явные числовые значения для записей:
public enum StringID
{
String_EMPTY = 0,
String_Inventory = 1,
String_Recipes = 2,
String_Tools = 3,
String_Journal = 4,
//...
}
Таким образом, порядок не имеет значения для значений. Обратите внимание, что вы можете сделать это ретроспективно или "как раз вовремя", когда вам нужно сделать то, что в противном случае было бы изменением.
(Я лично тоже избавился бы от префикса String_
, но это другое дело.)
Я бы использовал явную карту, а не голый массив; например:
private static Dictionary<StringID,string> SCLocalisedStrings_ENGB =
new Dictionary<StringID,string>
{
{StringID.String_EMPTY, ""},
{StringID.String_Inventory, "Inventory"},
//...
};
и получить значение через что-то вроде:
string val;
return LocaleStrings.TryGetValue(key, out val) ? val : DefaultStrings[key];
Ну... на самом деле, я бы, вероятно, имел переводы во внешних файлах как пары ключ/значение, но... meh.
Примечание: вы всегда можете вернуть данные словаря в упорядоченный массив; но наличие явной карты препятствует упорядочению порядка.