Войти
ПрограммированиеФорумОбщее

[C++] Строки как замена enum (2 стр)

Страницы: 1 2 3 Следующая »
#15
7:37, 19 дек. 2017

Suslik
> потому что как можно больше проверок нужно по возможности переносить в
> компайлтайм. если ты неправильно написал имя стата, то лучше, чтобы программа
> просто не скомпилировалась, чем когда-нибудь там, возможно, упала.
Это вопрос баланса, на самом деле. В идеале есть больше двух времен связывания: compile time для редактора, compile time для final build, runtime для game-design, runtime для final build
и т.д.
То что набор строк для геймдизайнера - может быть содержимым в регистре (int) в рантайм финального билда.

В мейнстрим системах это видно как dynamic в C#. Или как скриптинг (Lua с C++).
"Well-Typed Programs Can't Be Blamed" по научному плюс частичные вычисления.


#16
(Правка: 7:40) 7:39, 19 дек. 2017

Проверка типов - это формальная проверка на "соблюдаются ли договоренности в cross-functional team".
Идеи спецификаций на древнем gamedev.ru - они и про это тоже.
И данные тоже бы неплохо уметь компилить (из game-design представления (authoring) в final runtime представление (inplace blobs etc) и проверять договоренности.

#17
(Правка: 9:58) 9:58, 19 дек. 2017

loyso
Из-за кучи англицизмов и самих английских слов твои сообщения трудно воспринимаются :(

#18
10:04, 19 дек. 2017

mr.DIMAS
> Из-за кучи англицизмов и самих английских слов твои сообщения трудно
> воспринимаются
Есть такая проблема, да. Каждый термин - это "культурный референс" и колоссальный пласт опыта в computer science.
Если знаешь (или косвенно выяснил) опыт и культуру собеседника - можно общаться более детально.
Когда широкая и разношерстная публика - можно работать крупными мазками. Чтобы не метать бисер понапрасну.

#19
13:00, 19 дек. 2017

Вообще если всё в строках и в данных - то и указание что и зачем использовать тоже должно быть в данных. Игра не должна знать про существование "Healing potion", игра должна знать про эффекты на предметах которые загружаются из данных. Когда игрок нажимает кнопку например "1" - брать предмет с этого слота и применять эффекты с него.

#20
13:22, 19 дек. 2017

zlos
> Игра не должна знать про существование "Healing potion", игра должна знать про эффекты на предметах которые загружаются из данных.
проблема в том, что эти самые эффекты влияют на статы. которых в общем случае может быть очень много. например, банка может давать такой простой стат как current_player_health, а может — какой-нибудь increased_max_resistances_when_on_full_mana

#21
13:23, 19 дек. 2017

Почему бы просто не сделать

class EntityId
{
    ...
};

EntityId HealingPotion("HealingPotion");
EntityId ManaPotion("ManaPotion");
Ну и заполировать макросом при желании.
Entity разных классов можно держать в разных файлах, EntityId может хранить строку, может хранить хеш от строки, может хранить айдишники автоматически вычисляемые при старте,  может хранить айдишники загружаемые из базы при старте, может хранить айдишники выдаваемые кодогенерацией, итд.

#22
14:33, 19 дек. 2017

Suslik
Сделать описание примерно такое:

ItemName = "HealingPotion"
uiIcon = "ui/icons/healingpotion"
model = 'models/items/potion"
materialColor = blue
effects = [
  current_player_health = 10
]
И игре не надо знать про её существование! Только про эффекты. Тебе в любом случае все эти эффекты придётся реализовывать. Там вообще можно прицепить lua и разойтись как следует с условиями и действиями.
#23
(Правка: 14:54) 14:52, 21 дек. 2017
годы идут, а в плюсы все так и не завезли enum здорового человека.

Suslik
> роблема в том, что эти самые эффекты влияют на статы. которых в общем случае
> может быть очень много. например, банка может давать такой простой стат как
> current_player_health, а может — какой-нибудь
> increased_max_resistances_when_on_full_mana
Я эту "проблему" решил просто полем в базе куда записывается скрипт который исполняется при наступлении одного из трех условий.
Изображение


return [](){};
Пользуюсь вариантом  предложенного тобой решения, проблем не испытываю.

#24
(Правка: 21:02) 20:56, 8 июня 2018

В общем после опробования кучи вариантов остановился на таком

#define ENUM_EXPAND_AS_ENUM(a, b) a,
#define ENUM_EXPAND_AS_STRINGS(a, b) b,

#define ENUM_DECLARE(Name, EnumMacro) \
  class Name { \
  public: \
    enum Type { EnumMacro(ENUM_EXPAND_AS_ENUM) }; \
    static constexpr char* Str[] = { EnumMacro(ENUM_EXPAND_AS_STRINGS) }; \
    static constexpr size_t EntryCount = sizeof(Str) / sizeof(Str[0]); \
    Name() { } \
    Name(Type value) : mValue(value) { } \
    Name(const string& str) { \
      size_t i = 0; \
      while(i < EntryCount && str != Str[i]) ++i; \
      if(i < EntryCount) mValue = static_cast<Type>(i); \
      else throw std::runtime_error("Unknown " #Name " enum element: " + str); \
    } \
    operator Type() const { return mValue; } \
    void Serialize(Serializer &sav) { sav &mValue; } \
    string ToString() const { return Str[mValue]; } \
  private: \
    Type mValue = static_cast<Type>(0); \
  }; \
  namespace std { \
    template <> struct hash<Name> { \
    std::size_t operator()(const Name &k) const { \
      return std::hash<int>()(k); \
    } \
  }; \
  }

Используется как-то так

#define ITEM_CLASS_ENUM_ENTRIES(X) \
  X(Unknown,"Unknown") \
  X(Rubbish,"Rubbish") \
  X(Ore,"Ore") \
  X(Metal,"Metal") \
  X(Weapon,"Weapon") \
  X(Projectile,"Projectile") \
  X(Potion,"Potion") \
  X(Crystal,"Crystal") \
  X(Blueprint,"Blueprint") \
  X(Armor,"Armor") \
  X(Helmet,"Helmet") \
  X(Trousers,"Trousers") \
  X(Gloves,"Gloves") \
  X(Ring,"Ring") \
  X(Shield,"Shield") \
  X(Key,"Key") \
  X(Necklace,"Necklace") \
  X(Ingredient,"Ingredient") \
  X(Toolset,"Toolset") \
  X(Book,"Book") \

ENUM_DECLARE(ItemClass, ITEM_CLASS_ENUM_ENTRIES)

#undef ITEM_CLASS_ENUM_ENTRIES

Здесь используется X макрос: http://www.drdobbs.com/cpp/the-x-macro/228700289

Дальше енум используется как обычный scoped-enum.

ItemClass key = ItemClass::Key;

// можно получить элемент енума по строке
key = "Key";

// или сконвертить элемент енума в строку
ItemClass gloves = ItemClass::Gloves;
...
auto str = gloves.ToString();

// Проехаться по всем элементам енума
for(int i = 0; i < ItemClass::EntryCount; ++i) { 
  auto foo = ItemClass::Str[i] ;  
}

#25
21:05, 8 июня 2018

+1 за стрингхеши. можно компайлтайм при желании через макросы.

#26
22:52, 8 июня 2018

я делал компайл тайм строки просто упаковывая char в uint64, помещалось 12 букв.
https://github.com/azhirnov/ModularGraphicsFramework/blob/master/… /StringToID.h

#27
0:27, 9 июня 2018

А почему просто не хранить енумы в базе данных как числа? Можно даже сделать отдельную таблицу перевода этих чисел в строки...

#28
0:50, 9 июня 2018

ardru
Потому что понадобится удалить какой-нибудь енум из середины - и сразу же будет больно и трудно.

#29
7:38, 9 июня 2018

Sbtrn. Devil
> Потому что понадобится удалить какой-нибудь енум из середины - и сразу же будет больно и трудно.
https://pastebin.com/1xwWh3XH

Страницы: 1 2 3 Следующая »
ПрограммированиеФорумОбщее