Перечисления Unity, на которые ссылается инспектор, выходят из строя при расширении

1

Выпуск:

перечисление, на которое ссылаются скрипты 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 место, так как они будут ссылаться на индекс записи перечисления.

Простым решением было бы наложить правило только добавления к концу и никогда не удалять записи, которые становятся устаревшими. Это становится довольно расточительным, поэтому, очевидно, не очень предпочтительным.

Какие предлагаются решения этой проблемы? Любые примеры того, как другие подходят к этой довольно распространенной ситуации? Мое предпочтение было бы, конечно, тем, что можно было бы отсортировать, а новые записи добавлены в любом месте, но у нас не может быть всего, что мы хотим :)

  • 0
    Внутренне Unity сохраняет только значения перечисления, поэтому, если вы расширяете перечисление где-либо, кроме конца, вы перемещаете числа вокруг, и Unity изменяет выбранное перечисление в соответствии с его сохраненным значением, а не именем перечисления.
Теги:
unity3d
serialization
enums

2 ответа

1
Лучший ответ

Просто укажите явные числовые значения для записей:

public enum StringID 
{
    String_EMPTY = 0,
    String_Inventory = 1,
    String_Recipes = 2,
    String_Tools = 3,
    String_Journal = 4,

    //...
}

Таким образом, порядок не имеет значения для значений. Обратите внимание, что вы можете сделать это ретроспективно или "как раз вовремя", когда вам нужно сделать то, что в противном случае было бы изменением.

(Я лично тоже избавился бы от префикса String_, но это другое дело.)

  • 0
    Спасибо Джон, теперь я применил этот подход для всех реализаций наивного / внутреннего кода, и я реализовал этап в синтаксическом анализаторе для внешних данных, чтобы выполнить сравнение и отслеживать уже существующие записи, чтобы сохранить их индекс. Я должен признать, что это был мой запасной подход, или подход «плана b» - это то, как я обычно подходил к суммированной категоризации перечислений или битовых полей и индексации из-за моего чрезмерного воздействия UE3 в течение последних 8 лет. Я надеялся, что упустил какой-то другой очевидный подход или модель использования, чтобы лучше справляться с этой распространенной ситуацией, но похоже, что это все еще лучший маршрут!
0

Я бы использовал явную карту, а не голый массив; например:

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.

Примечание: вы всегда можете вернуть данные словаря в упорядоченный массив; но наличие явной карты препятствует упорядочению порядка.

  • 0
    Мне нравится структура данных хранения в паре ключ / значение для внутренних данных для локализации, немного более удобная для нескольких систем. Однако, если я что-то упускаю, этот подход не решает ситуацию анализа добавления / удаления записей в поле ссылочного ключа (например, внешне что-то все еще ссылается на StringID of n, который может изменить индекс по позициям, если он столкнется)?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню