Я создаю фреймворк SFML, и когда я использую функцию loadImage один раз, изображение загружается правильно со всеми цветами, но если я использую его два раза для другой текстуры, визуализируется только один спрайт, и он весь белый. Я читал, что вы не хотите удалять текстуру или спрайт, иначе он будет белым. Но в этом коде я храню все текстуры в векторе. Кто-нибудь знает, что не так в этой функции?
FM::Image FM::graphics::loadImage(const char* fileName) {
texturesindex++;
sf::Texture texture;
texture.loadFromFile(fileName);
textures.push_back(texture);
sf::Sprite sprite(textures[texturesindex]);
Image image;
image.sprite = sprite;
return image;
}
Вот весь код:
SFFM.cpp:
#include "SFFM.h"
#include <SFML/Graphics.hpp>
#include <vector>
#include <string>
int backgroundcolor[3] = { 0,0,0};
sf::RenderWindow Window(sf::VideoMode(800, 600), "MyGame");
std::vector<sf::Texture> textures;
int texturesindex = -1;
void FM::window::setWindowOptions(unsigned int Width, unsigned int Height, const char* Title, int FrameLimit) {
Window.setSize(sf::Vector2u(Width, Height));
Window.setFramerateLimit(FrameLimit);
Window.setTitle(Title);
}
void FM::window::setBackgroundColor(int r, int g, int b) {
backgroundcolor[0] = r;
backgroundcolor[1] = g;
backgroundcolor[2] = b;
}
FM::Image FM::graphics::loadImage(const char* fileName) {
texturesindex++;
sf::Texture texture;
texture.loadFromFile(fileName);
textures.push_back(texture);
sf::Sprite sprite(textures[texturesindex]);
Image image;
image.sprite = sprite;
return image;
}
void FM::graphics::drawImage(Image image, int x, int y, int scalex, int scaley, int rotation) {
image.sprite.setPosition(x, -y);
image.sprite.setRotation(rotation);
image.sprite.setScale(sf::Vector2f(scalex, scaley));
Window.draw(image.sprite);
}
void FM::graphics::drawImage(Image image, int x, int y, int scalex, int scaley) {
image.sprite.setPosition(x, -y);
image.sprite.setScale(sf::Vector2f(scalex, scaley));
Window.draw(image.sprite);
}
void FM::graphics::drawImage(Image image, int x, int y) {
image.sprite.setPosition(x, -y);
Window.draw(image.sprite);
}
int main()
{
FM::Start();
while (Window.isOpen())
{
sf::Event event;
while (Window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
Window.close();
else if (event.type == sf::Event::Resized)
{
Window.setView(sf::View(sf::FloatRect(0, 0, event.size.width, event.size.height)));
}
}
Window.clear(sf::Color(backgroundcolor[0], backgroundcolor[1], backgroundcolor[2]));
FM::Update();
Window.display();
}
return 0;
}
SFFM.h:
#pragma once
#include <SFML/Graphics.hpp>
namespace FM
{
void Update();
void Start();
class window {
public:
static void setWindowOptions(unsigned int Width, unsigned int Height, const char * Title, int FrameLimit);
static void setBackgroundColor(int r, int g, int b);
};
class Image {
public:
sf::Sprite sprite;
};
class graphics {
public:
static Image loadImage(const char* fileName);
static void drawImage(Image image, int x, int y, int scalex, int scaley, int rotation);
static void drawImage(Image image, int x, int y, int scalex, int scaley);
static void drawImage(Image image, int x, int y);
};
class Input {
public:
};
};
main.cpp:
#include "SFFM.h"
#include <SFML\Graphics.hpp>
FM::Image Gangster;
FM::Image Block;
int x = 0;
int y = 0;
void FM::Start() {
window::setWindowOptions(1280, 720, "Platformer", 120);
window::setBackgroundColor(0, 127, 255);
Gangster = graphics::loadImage("assets/Gangster.png");
}
void FM::Update() {
graphics::drawImage(Gangster, x, y, 5, 5);
graphics::drawImage(Block, 100, 100, 5, 5);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
y += 1;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
y -= 1;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
x += 1;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
x -= 1;
}
}
Вот скриншот:
Поскольку я хотел упростить ситуацию, я сделал две функции start и update, которые вызываются в основной функции в SFFM.cpp, так что мне не нужно видеть весь беспорядок в основной функции.





TL; DR Solutions, либо:
std::vector<sf::Texture> - std::list<sf::Texture> или std::forward_list<sf::Texture>.std::vector<std::unique_ptr<sf::Texture>>.Объяснение
Вы храните объекты текстуры вместе со ссылками на них. Это правильно, потому что злоба просто сохраняет ссылку (указатель) на свою текстуру. Это также означает, что адрес текстуры должен оставаться неизменным в течение всего времени жизни спрайта.
Похоже, вы не учли, как работает std :: vector push_back (). Вектор изначально выделяет некоторую память, и когда нет места для вставки нового элемента, вектор выделяет больше памяти и копирует туда все вставленные элементы и новый. Таким образом, все адреса пунктов меняются.
В вашем случае элемент является текстурой, его адрес изменяется при использовании другой текстуры, поэтому некоторый спрайт «теряет» свою текстуру. Обычно это приводит к рисованию белых квадратов.
Благодарю за ответ. Но тогда как мне добавить указатель на вектор. С отталкиванием?
@BlockySteve textures.emplace_back (new sf :: Texture (texture)), если вы используете C++ 11, textures.push_back (std :: make_unique <sf :: Texture> (texture)), если вы используете C++ 14 . Или лучше использовать первую альтернативу, в вашем случае достаточно заменить «вектор» на «список».
Почему
mainнет в main.cpp?