Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / [C++] Строки как замена enum (2 стр)

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

Страницы: 1 2 3 Следующая »
loysoПостоялецwww19 дек. 20177:37#15
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" по научному плюс частичные вычисления.

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

Правка: 19 дек. 2017 7:40

mr.DIMASПостоялецwww19 дек. 20179:58#17
loyso
Из-за кучи англицизмов и самих английских слов твои сообщения трудно воспринимаются :(

Правка: 19 дек. 2017 9:58

loysoПостоялецwww19 дек. 201710:04#18
mr.DIMAS
> Из-за кучи англицизмов и самих английских слов твои сообщения трудно
> воспринимаются
Есть такая проблема, да. Каждый термин - это "культурный референс" и колоссальный пласт опыта в computer science.
Если знаешь (или косвенно выяснил) опыт и культуру собеседника - можно общаться более детально.
Когда широкая и разношерстная публика - можно работать крупными мазками. Чтобы не метать бисер понапрасну.
zlosУдалёнwww19 дек. 201713:00#19
Вообще если всё в строках и в данных - то и указание что и зачем использовать тоже должно быть в данных. Игра не должна знать про существование "Healing potion", игра должна знать про эффекты на предметах которые загружаются из данных. Когда игрок нажимает кнопку например "1" - брать предмет с этого слота и применять эффекты с него.
SuslikМодераторwww19 дек. 201713:22#20
zlos
> Игра не должна знать про существование "Healing potion", игра должна знать про эффекты на предметах которые загружаются из данных.
проблема в том, что эти самые эффекты влияют на статы. которых в общем случае может быть очень много. например, банка может давать такой простой стат как current_player_health, а может — какой-нибудь increased_max_resistances_when_on_full_mana
return [](){};Участникwww19 дек. 201713:23#21
Почему бы просто не сделать
class EntityId
{
    ...
};

EntityId HealingPotion("HealingPotion");
EntityId ManaPotion("ManaPotion");
Ну и заполировать макросом при желании.
Entity разных классов можно держать в разных файлах, EntityId может хранить строку, может хранить хеш от строки, может хранить айдишники автоматически вычисляемые при старте,  может хранить айдишники загружаемые из базы при старте, может хранить айдишники выдаваемые кодогенерацией, итд.
zlosУдалёнwww19 дек. 201714:33#22
Suslik
Сделать описание примерно такое:
ItemName = "HealingPotion"
uiIcon = "ui/icons/healingpotion"
model = 'models/items/potion"
materialColor = blue
effects = [
  current_player_health = 10
]
И игре не надо знать про её существование! Только про эффекты. Тебе в любом случае все эти эффекты придётся реализовывать. Там вообще можно прицепить lua и разойтись как следует с условиями и действиями.
MephistophelesПостоялецwww21 дек. 201714:52#23
годы идут, а в плюсы все так и не завезли enum здорового человека.

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


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

Правка: 21 дек. 2017 14:54

mr.DIMASПостоялецwww8 июня 201820:56#24
В общем после опробования кучи вариантов остановился на таком
#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] ;  
}

Правка: 8 июня 2018 21:02

DampireУчастникwww8 июня 201821:05#25
+1 за стрингхеши. можно компайлтайм при желании через макросы.
/A\Постоялецwww8 июня 201822:52#26
я делал компайл тайм строки просто упаковывая char в uint64, помещалось 12 букв.
https://github.com/azhirnov/ModularGraphicsFramework/blob/master/… /StringToID.h
ardruПостоялецwww9 июня 20180:27#27
А почему просто не хранить енумы в базе данных как числа? Можно даже сделать отдельную таблицу перевода этих чисел в строки...
Sbtrn. DevilПостоялецwww9 июня 20180:50#28
ardru
Потому что понадобится удалить какой-нибудь енум из середины - и сразу же будет больно и трудно.
DampireУчастникwww9 июня 20187:38#29
Sbtrn. Devil
> Потому что понадобится удалить какой-нибудь енум из середины - и сразу же будет больно и трудно.
https://pastebin.com/1xwWh3XH
Страницы: 1 2 3 Следующая »

/ Форум / Программирование игр / Общее

2001—2018 © GameDev.ru — Разработка игр