Я пытаюсь создать базовый игровой движок на C++, и я хочу, чтобы объект Engine
мог перебирать все дочерние элементы GameObject
для запуска их методов обновления, для этого я хочу использовать вектор всех дочерних элементов в классе Engine
.
Это похоже на то, что я пытался сделать:
Класс основного двигателя
class Engine {
public:
Engine() {};
std::vector<GameObject> GameObjects; //Vector to store all GameObjects
void AddNewObject(GameObject& obj) {
GameObjects.push_back(obj); //Add new object to the vector array
}
void Run() {
for (int i = 0; i < GameObjects.size(); i++) {
GameObjects[i].Update(); //Run the update method of each GameObject
}
}
}
Дочерний класс GameObject
class GameObject : public Engine {
public:
GameObject() {}
void Update() {
//Do stuff
}
}
Цикл основного кода
int main(void) {
Engine engine;
GameObject object;
engine.AddNewObject(object); //Add object
engine.run();
}
Любая помощь будет принята с благодарностью, спасибо.
будьте очень осторожны при хранении объектов в контейнерах. это работает, но убедитесь, что вы не создаете копии. Я видел много кода, который имеет несколько копий «одного и того же» объекта, которые обновляются в разных запусках. Лучше поставить смарт птр в векто
У вас есть план. (На самом деле я вижу два плана — один включает «вектор всех дочерних элементов», а другой — вектор адресов всех дочерних элементов.) Так что действуйте. Какой вопрос? Вы столкнулись с проблемой? Каковы симптомы?
@SilvioMayolo Спасибо за совет, я попробовал, и количество ошибок сократилось вдвое, а совет Брэда решил проблему.
Здесь есть несколько проблем. Во-первых, ваш вектор должен быть вектором ссылок или указателей, иначе GameObjects.push_back(obj);
создаст копию obj
для помещения в вектор (если вы не переместите его) и полиморфизм не будет работать (вы не можете удерживать подклассы GameObject
).
То, как вы подходите к этому, зависит от того, какой объект вы хотите владеть памятью, связанной с каждым GameObject
. Тривиальное исправление заключается в использовании вектора указателей:
class Engine {
public:
Engine() {};
std::vector<GameObject*> GameObjects; //Vector to store all GameObjects
void AddNewObject(GameObject& obj) {
GameObjects.push_back(&obj); //Add new object to the vector array
}
void Run() {
for (int i = 0; i < GameObjects.size(); i++) {
GameObjects[i]->Update(); //Run the update method of each GameObject
}
}
}
Однако с современным C++ вы, вероятно, захотите использовать интеллектуальный указатель, такой как unique_ptr:
class Engine {
public:
Engine() {};
std::vector<std::unique_ptr<GameObject>> GameObjects; //Vector to store all GameObjects
void AddNewObject(std::unique_ptr<GameObject> obj) {
GameObjects.push_back(std::move(obj)); //Add new object to the vector array
}
void Run() {
for (int i = 0; i < GameObjects.size(); i++) {
GameObjects[i]->Update(); //Run the update method of each GameObject
}
}
}
Используя уникальный указатель, вам придется изменить другой код:
int main(void) {
Engine engine;
std::unique_ptr<GameObject> object = std::make_unique<GameObject>();
// Transfers memory ownership of `object` into `engine`
engine.AddNewObject(std::move(object)); //Add object
engine.run();
}
Наконец, ваша иерархия классов выглядит недействительной. Вероятно, вам не нужно или вы не хотите, чтобы GameObject
был подклассом Engine, поскольку они не имеют ничего общего. GameObject
, вероятно, сам по себе является хорошим базовым классом, и другие игровые объекты могут его наследовать.
Я последовал вашему совету и удалил GameObject
как дочерний элемент Engine
, а также исправил свою проблему, связанную с тем, что вектор не стал указателем. Кажется, проблема исправлена.
GameObject
, вероятно, не должен быть ребенкомEngine
. Это означает, что каждый отдельный объект в вашей игре на самом деле является собственным игровым движком, что менее чем разумно. Кроме этого и некоторого возможного нарезки объектов, если вы планируете создавать подклассыGameObject
(что можно исправить старым добрымunique_ptr
), я не вижу здесь никаких проблем.