Я пытаюсь создать игрушечную систему компонентов Entity, чтобы улучшить свои навыки C++. Для этого у меня есть класс ECS_Manager, который использует шаблоны, чтобы иметь несколько классов хранения для каждого типа данных, который я хотел бы использовать в качестве компонента.
Каждый компонент представляет собой просто структуру с целым числом и любыми другими данными, которые мне нужны. В примере он содержит объект Vector2D. Ничего особенного.
В качестве отправной точки внутри класс хранения для каждого типа компонентов имеет свой собственный вектор. Я могу отлично хранить новые данные (в конечном итоге они распечатываются, если я это делаю). Однако, когда я пытаюсь сохранить новые данные в элемент вектора с помощью разыменования указателя (см. Physics_System
ниже), новые значения не сохраняются. Я не могу понять, почему.
#include <iostream>
#include <vector>
#include <map>
#include <typeinfo>
#include <memory>
#include <array>
#include "Vector2D.hpp"
#include "./ECS/components/Position_comp.hpp"
class VComponentStorage {
public:
virtual ~VComponentStorage() = default;
};
template <typename T>
class ComponentStorage : public VComponentStorage{
public:
ComponentStorage(){
this->storage_container_index = 0;
}
void add_component(T component){
this->storage_container.push_back(component);
this->storage_container_index++;
}
T *get_component(int entity_id){
T* start_ptr = this->storage_container.data();
return &(start_ptr[entity_id]);
}
size_t get_component_count(){
return 1;
}
private:
std::vector<T> storage_container;
size_t storage_container_index;
};
class ECS_Mananger{
public:
ECS_Mananger(){
}
template<typename T> void register_component(){
const char *type_name = typeid(T).name();
ComponentStorage<T> *comp_storage_ptr = new ComponentStorage<T>;
this->T_to_comp_storage_Map.insert({type_name, comp_storage_ptr});
}
template<typename T>
void add_component(T component){
const char *type_name = typeid(T).name();
std::cout << type_name << std::endl;
ComponentStorage<T>* my_ptr = static_cast<ComponentStorage<T>*>(this->T_to_comp_storage_Map[type_name]);
my_ptr->add_component(component);
}
template<typename T>
T *get_component(int entity_id){
const char *type_name = typeid(T).name();
ComponentStorage<T>* my_ptr = static_cast<ComponentStorage<T>*>(this->T_to_comp_storage_Map[type_name]);
return my_ptr->get_component(entity_id);
}
private:
std::map<std::string, VComponentStorage*> T_to_comp_storage_Map;
};
void Physics_System(ECS_Mananger &world){
Position_Component* my_ptr = world.get_component<Position_Component>(0);
*my_ptr = { 0, Vector2D(5.0, 2.0)};
};
int main() {
//Create Arrays
ECS_Mananger my_world;
my_world.register_component<Position_Component>();
Position_Component init_pos_val = {0, Vector2D(1.0, 2.0)};
my_world.add_component<Position_Component>(init_pos_val);
// Main game loop
while (1) // Detect window close button or ESC key
{
// Update
Physics_System(my_world);
my_world.get_component<Position_Component>(0)->position.print();
}
return 0;
}
В функции Physics_System
я ожидаю, что значение будет обновлено. Любая причина, почему это не так? Мой C++ немного ржавый. Сначала я делал так: 'world.get_component<Position_Component>(0)->position = Vector2D(4.4, 3.3);' чтобы изменить значение. Это тоже не работало, поэтому я подумал, что, возможно, это как-то связано с правыми/левыми проблемами с языком. Я подозреваю, что хоть я и использую указатели, где-то что-то копируется. Я просто не могу сказать, где.
Редактировать:
Position_Component и спецификация Vector2D:
#include "Vector2D.hpp"
struct Position_Component {
int entity_id;
Vector2D position;
};
class Vector2D {
public:
double x;
double y;
Vector2D() {
this->x = 0.0;
this->y = 0.0;
}
Vector2D(double x, double y){
this->x = x;
this->y = y;
}
void print(){ std::cout << "(" << this->x << "," << this->y << ")" << std::endl; };
Vector2D operator+(const Vector2D& vec){
Vector2D result;
result.x = this->x + vec.x;
result.y = this->y + vec.y;
return result;
}
Vector2D operator-(const Vector2D& vec){
Vector2D result;
result.x = this->x - vec.x;
result.y = this->y - vec.y;
return result;
}
Vector2D operator=(const Vector2D& vec){
Vector2D result;
result.x = vec.x;
result.y = vec.y;
return result;
}
};
Vector2D operator*(const double& s, Vector2D vec){
Vector2D result;
result.x = s*vec.x;
result.y = s*vec.y;
return result;
}
Что касается вашей проблемы, вы пытались отладить свою программу? Например, используя отладчик для пошагового выполнения кода, отслеживая переменные и их значения, чтобы увидеть, что происходит на самом деле?
Как выглядит Position_Component?
@Someprogrammerdude У меня есть. Указатель, используемый в ECS_Manager (хранящийся в карте), используемый для ссылки на правильный объект ComponentStorage, содержит тот же адрес, когда компонент впервые регистрируется, добавляется и когда вызывается get_component. Я предполагаю, что когда я «запрашиваю» адрес PositionComponent, я получаю копию вектора (или элемента). Я просто не понимаю «почему».
@kiner_shah Вопрос отредактирован, чтобы включить Position_Component и содержащийся в нем класс Vector2D.
Проблема в вашем операторе присваивания Vector2D
:
Vector2D operator=(const Vector2D& vec){
Vector2D result;
result.x = vec.x;
result.y = vec.y;
return result;
}
Предполагается, что оператор присваивания присваивает объекту this
, а не создает новый объект. Он также должен возвращать ссылку на *this
(чтобы разрешить цепочку присваиваний).
Из-за этой проблемы назначение
*my_ptr = { 0, Vector2D(5.0, 2.0)};
просто выбрасывается, вы никогда не изменяете *my_ptr
.
Чтобы решить эту проблему, измените, например:
Vector2D& operator=(const Vector2D& vec){
x = vec.x;
y = vec.y;
return *this;
}
Я рекомендую потратить некоторое время на чтение этого канонического справочника по реализации для перегрузки операторов.
ОТ: Функцию
ComponentStorage<T>::get_component()
можно было бы сократить доreturn &storage_container[entity_id];