Как избежать виртуальных функций в C при разработке Entity System - PullRequest
0 голосов
/ 12 ноября 2018

Я хочу разработать систему сущностей для моей игры, используя только C и небольшое подмножество C ++. Многие люди делают это, используя наследование, но я наткнулся на теговые союзы и узнал, что таким путем можно добиться аналогичного результата, потому что виртуальные функции медленны для игр (так что я слышал от Кейси Муратори и Джона Блоу, два игровые разработчики, из которых я черпаю много вдохновения).

struct Unit {
   int type;
   int hp;
   union {
      struct {
        int kingID; 
      } soldier_data;

      struct {
        string name;
      } king_data;
   };
}

Джон Блоу избегает виртуальных функций, используя некоторые функции из своего нового языка Jai, который еще не выпущен, поэтому приведенный выше пример - моя единственная идея.

Например, я мог бы написать только одну функцию обновления и использовать тип для различения сущностей. Это была бы очень большая функция, но мы избегаем виртуальных функций.

В моей игре есть, скажем, солдаты и деревья. Деревья статичны и в основном ничего не делают, поэтому я бы написал другую более легкую структуру для сущностей деревьев, чтобы сэкономить память, и использовал объединения для хранения разных типов деревьев:

struct TreeEntity {    
      Texture* texture;    
      union {
        struct {
           int height;
        } pineTree_data;
        struct {
           string name;
        } coconutTree_data;
   }
}

Проблема, с которой я сталкиваюсь, заключается в том, что, если и солдаты, и деревья кликабельны ? Если бы я использовал наследование, я бы просто использовал функцию Entity * selectEntity () и проверил бы тип экземпляра после этого, но с моим подходом я в некотором роде потерян.

Мой подход плох? Должен ли я придерживаться виртуальных функций или есть способ справиться с этим?

1 Ответ

0 голосов
/ 12 ноября 2018

Вы спрашиваете, как создать универсальную функцию Entity* selectEntity(), которая может возвращать либо Unit *, либо Tree * (или, возможно, другие вещи).

Вы можете сделать это, возвращая указатель базового класса. Unit и Tree наследуются от Entity, и Entity может содержать небольшое перечисление, например:

enum class EntityType : uint8_t {
    Unit, Tree, // ...
};

Если вы не хотите использовать наследование, вместо этого вы можете просто иметь общую начальную подпоследовательность переменных-членов в каждом типе сущностей, например:

struct Unit {
    EntityType type;
    // ...
};

Это эквивалентно версии наследования с точки зрения разметки памяти, и вы можете вернуть EntityType * из selectEntity(), который фактически будет указывать на первый член модуля или дерева.

...