Явное определение комбинаций флагов в перечислении - PullRequest
0 голосов
/ 20 мая 2018

Я думал о реализации enum, который определяет состояние игрового объекта, и я хотел знать, смогу ли я напрямую использовать флаги в определении enum вместо определения состояния объекта как набора флагов без простого,предварительно определенное глобальное имя для состояний, используемых в автомате состояний.

Например, скажем, есть 5 состояний: PreActivation (создано, но не запущено; т.е. враг в будущей волне), Active (в настоящее время)используется (т. е. враг на экране атакует вас), приостановлен (больше не активен, но может реактивироваться; т. е. противник, если игрок использует замедляющую силу), деактивирован (объект, использование которого завершено, но все еще находится вигровой мир, т.е. враг, чье тело осталось после смерти, как в Doom 1 & 2), и ToRemove (объект, который планируется удалить из игры; т. е. враг после того, как вы очистите уровень и перейдете на следующий).

Что я хочу сделать, так это определить enum, чтобы в состояниях были все применимые флаги;например, Деактивированный враг: 1. Ранее был активирован, 2. В настоящее время не активен.Мое текущее мышление делает что-то вроде этого:

public enum ObjectState
{
    // The first section are the flags
    BeenActivated   = 0b0000001, // Previously activated
    CurrentlyActive = 0b0000010, // Currently activated
    IsSuspended     = 0b0000100, // It may be reactivated
    ShouldRemove    = 0b0001000, // It should be removed
    // These are the states
    PreActivation   = 0b0000100, // Mot currently active, nor has it ever been active, but it will get activated
    Active          = 0b0000011, // Currently active,     and it's been active
    Paused          = 0b0000101, // Not currently active, but it's been active before
    DeActivated     = 0b0000001, // Not currently active, but it's been active before, and it shouldn't get reactivated, but don't remove yet
    ToRemove        = 0b0001001  // Not currently active, but it's been active before, and it shouldn't get reactivated, it should be removed
}

Насколько я знаю, это должно работать правильно, но у меня есть несколько основных проблем:

  1. Есть ли проблемывероятно, это произойдет?
  2. Это плохая практика?
  3. Это плохая практика?И, если это так;
    • A.Что с ним не так?
    • B.Что я должен сделать вместо этого?Я бы просто сделал состояние объекта коллекцией этих флагов, но я бы хотел кратко перечислить для конкретных состояний, так как это учитывает сложность для конкретных случаев и простоту, когда это необходимо.Есть ли более приемлемый способ добиться этого?

Извините, если это повторение, или я нарушил какое-то другое правило, но я только что создал учетную запись сегодня;это мой 1-й пост.Кроме того, я не уверен, как бы вы назвали это при поиске, и я не получил подобных совпадений здесь или в Google.

Ответы [ 3 ]

0 голосов
/ 20 мая 2018

Рассматривали ли вы использование [Flags] -enum ?

[Flags]
public enum ObjectState
{
    BeenActivated   = 1, // Previously activated
    CurrentlyActive = 2, // Currently activated
    IsSuspended     = 4, // It may be reactivated
    ShouldRemove    = 8, // It should be removed
}

// Currently active, and it's been active
var active = ObjectState.BeenActivated | ObjectState.CurrentlyActive;
0 голосов
/ 20 мая 2018

Вы можете сделать это.Это сама точка перечисления флагов.Если enum предназначен для работы в качестве флагов, пометьте его атрибутом [Flags].

Я бы предложил объединить существующие флаги с побитовым или (|) вместо этого.Он более читабелен и менее подвержен ошибкам.

[Flags]
public enum ObjectState
{
    // Flags
    BeenActivated   = 0b0000001, // Previously activated
    CurrentlyActive = 0b0000010, // Currently activated
    IsSuspended     = 0b0000100, // It may be reactivated
    ShouldRemove    = 0b0001000, // It should be removed

    // States as combination of flags.
    PreActivationState   = IsSuspended,                     // Mot currently active, nor has it ever been active, but it will get activated
    ActiveState          = BeenActivated | CurrentlyActive, // Currently active,     and it's been active
    PausedState          = BeenActivated | IsSuspended,     // Not currently active, but it's been active before
    DeActivatedState     = BeenActivated,                   // Not currently active, but it's been active before, and it shouldn't get reactivated, but don't remove yet
    ToRemoveState        = BeenActivated | ShouldRemove     // Not currently active, but it's been active before, and it shouldn't get reactivated, it should be removed
}

Я также добавил суффикс «State» к состояниям, чтобы лучше отличать их от флагов.Или переверните его и добавьте вместо флагов суффикс «Флаги».

0 голосов
/ 20 мая 2018

Сложно понять это без контекста, но вы можете захотеть взглянуть на State Pattern для более расширяемого и оригинального способа ведения дел.

Как это работает, вы делаете игровой объектпустая оболочка, реализующая тот же интерфейс, что и абстрактный класс Game State.Игровой объект будет вызывать состояние, чтобы сделать то, что определяет интерфейс, в то время как состояние имеет ссылку на содержащий его игровой объект.Когда состояние изменяется, экземпляр состояния сообщает игровому объекту.

Так, например, допустим, что ваш игровой объект имеет интерфейс только с одним методом, «Атака».У абстрактного класса состояний есть два конкретных подкласса: Живой и Мертвый.Живой и Мертвый оба реализуют Атаку тоже.Когда что-то атакует ваш игровой объект, object.Attack ();, объект внутренне просто вызывает state.Attack ().Состояние Alive решит, была ли атака успешной, и выполнит parent.State = new DeadState () ;.Когда атака вызывается снова, DeadState ничего не делает.

Таким образом вы избегаете перечислений, переключений, ifs, всего и просто добавляете игровые состояния без дальнейшего программирования.Ваша проверка «была активирована» также будет методом интерфейса.

...