#c #sfml
#c #sfml
Вопрос:
Я пытаюсь создать спрайтовый вектор, но первые несколько элементов всегда показывают белый квадрат. Переменные содержатся в классе TileRPG, чтобы затем использоваться в main.cpp tile.cpp
void TileRPG::draw(int id, float x, float y, sf::RenderWindowamp; window) {
m_sprite[id].setPosition(sf::Vector2f(x, y));
window.draw(m_sprite[id]);
}
TileRPG::TileRPG() {
std::ifstream file { "data/tileRPGList.rf" };
std::string line{ "" }, access { "" };
sf::Texture texture;
sf::Sprite sprite;
unsigned int i = 0;
while (std::getline(file, line)) {
m_texture.push_back(texture);
m_sprite.push_back(sprite);
access = "data/" line;
m_texture[i].loadFromFile(access);
m_sprite[i].setTexture(m_texture[i]);
i ;
}
}
tile.hpp
class Tile {
protected:
std::vector<sf::Texture> m_texture;
std::vector<sf::Sprite> m_sprite;
};
class TileRPG : public Tile {
public:
TileRPG();
void draw(int id, float x, float y, sf::RenderWindowamp; window);
};
Ответ №1:
Проблема
Из sf::Sprite::setTexture()
документации:
спрайт не сохраняет свою собственную копию текстуры, а скорее сохраняет указатель на ту, которую вы передали этой функции.
Итак, sf::Sprite
объект не хранит копию sf::Texture
объекта. Кстати, это связано с шаблоном Flyweight, как это можно сделать из sf::Sprite
документации:
Разделение
sf::Sprite
иsf::Texture
обеспечивает большую гибкость и лучшую производительность: действительно,sf::Texture
это тяжелый ресурс, и любая операция с ним выполняется медленно (часто слишком медленно для приложений реального времени). С другой стороны, asf::Sprite
— это облегченный объект, который может использовать пиксельные данные asf::Texture
и рисовать его со своими собственными атрибутами преобразования / цвета / смешивания.
m_texture
Элемент данных в вашем коде является вектором sf::Texture
объектов, т.Е. std::vector<sf::Texture>
. Вызов push_back()
этого вектора перераспределит внутренний буфер вектора, если в нем недостаточно места для хранения sf::Texture
объекта для вставки. Следовательно, sf::Texture
объекты, хранящиеся в std::vector<sf::Texture>
, могут оказаться расположенными в другой позиции в памяти после вызова push_back()
. Поскольку sf::Sprite
объекты просто хранят указатели на sf::Texture
объекты, эти указатели в конечном итоге будут указывать на неправильное местоположение в памяти, если sf::Texture
объекты были перераспределены где-то еще в памяти.
Возможные решения
Вы могли бы просто вызвать, std::vector::reserve()
чтобы заранее зарезервировать достаточно памяти для внутреннего буфера вектора. Недостатком этого подхода является то, что в идеале вам нужно заранее знать количество sf::Texture
объектов, которые ваш вектор будет хранить, чтобы избежать пустой траты памяти.
Другим подходом было бы вызывать sf::Sprite::setTexture()
только после того, как вы правильно заполнили std::vector<sf::Texture>
контейнер. Таким образом, поскольку вы не собираетесь дополнительно вставлять sf::Texture
объекты в вектор, он не будет перераспределять свой внутренний буфер.
Наконец, альтернативным подходом к контейнеру было бы вместо этого определить m_texture
как std::vector<std::unique_ptr<sf::Texture>>
. Таким образом, если происходит перераспределение внутреннего буфера вектора, затрагиваются только адреса std::unique_ptr<sf::Texture>
объектов, не адреса указательных объектов (т. Е. не адреса sf::Texture
объектов). Вы также могли бы использовать boost::stable_vector
для той же цели. В этом случае вместо этого вы бы просто определили m_texture
as boost::stable_vector<sf::Texture>
.
Ответ №2:
Sprite::setTexture
не создает копию текстуры, но сохраняет указатель на нее. Затем этот указатель становится недействительным, как только вектор текстур перераспределяет свое хранилище в одном из последующих push_back
файлов.