В качестве небольшого упражнения я пытаюсь написать очень маленький, простой игровой движок, который просто обрабатывает сущности (перемещение, базовый ИИ и т.д.).
Как таковой, я пытаюсь думать о том, как игра обрабатывает обновления для всех сущностей, и я немного запутался (возможно, потому, что я собираюсь сделать это не так)
Поэтому я решил опубликовать этот вопрос здесь, чтобы показать вам мой нынешний способ думать об этом, и посмотреть, может ли кто-нибудь предложить мне лучший способ сделать это.
В настоящее время у меня есть класс CEngine, который принимает указатели на другие классы, которые ему нужны (например, класс CWindow, класс CEntityManager и т.д.)
У меня есть игровой цикл, который в псевдокоде будет идти так (внутри класса CEngine)
while(isRunning) {
Window->clear_screen();
EntityManager->draw();
Window->flip_screen();
// Cap FPS
}
Мой класс CEntityManager выглядел следующим образом:
enum {
PLAYER,
ENEMY,
ALLY
};
class CEntityManager {
public:
void create_entity(int entityType); // PLAYER, ENEMY, ALLY etc.
void delete_entity(int entityID);
private:
std::vector<CEntity*> entityVector;
std::vector<CEntity*> entityVectorIter;
};
И мой класс CEntity выглядел так:
class CEntity() {
public:
virtual void draw() = 0;
void set_id(int nextEntityID);
int get_id();
int get_type();
private:
static nextEntityID;
int entityID;
int entityType;
};
После этого я бы создал классы, например, для врага, и дал ему лист спрайтов, свои собственные функции и т.д.
Например:
class CEnemy : public CEntity {
public:
void draw(); // Implement draw();
void do_ai_stuff();
};
class CPlayer : public CEntity {
public:
void draw(); // Implement draw();
void handle_input();
};
Все это отлично работало для простого рисования спрайтов на экране.
Но потом я пришел к проблеме использования функций, которые существуют в одном объекте, но не в другом.
В приведенном выше примере псевдокода do_ai_stuff(); и handle_input();
Как вы можете видеть из моего игрового цикла, есть вызов EntityManager- > draw(); Это просто повторяется через entityVector и называется draw(); функция для каждого объекта - что прекрасно работало, поскольку все объекты имеют draw(); функция.
Но потом я подумал, что, если это субъект игрока, который должен обрабатывать ввод? Как это работает?
Я не пробовал, но я предполагаю, что я не могу просто пропустить цикл, как и с функцией draw(), потому что сущности, подобные врагам, не будут иметь функцию handle_input().
Я мог бы использовать оператор if для проверки типа entityType, например:
for(entityVectorIter = entityVector.begin(); entityVectorIter != entityVector.end(); entityVectorIter++) {
if((*entityVectorIter)->get_type() == PLAYER) {
(*entityVectorIter)->handle_input();
}
}
Но я не знаю, как люди обычно начинают писать этот материал, поэтому я не уверен в том, как это сделать.
Я написал много здесь, и я не задавал никаких конкретных вопросов, поэтому я уточню, что я здесь ищу:
- Я так хорошо сформулировал свой код, и он практичен?
- Есть ли более эффективный способ обновления моих объектов и функций вызова, которые могут не иметь другие объекты?
- Использует ли перечисление для отслеживания типов объектов хороший способ идентифицировать объекты?