SFML sprite 在制作多个纹理时是一个白色方块

SFML sprite is a white square when making multiple textures

我正在制作一个 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;
}

}

截图如下:

TL;DR 解决方案,要么:

  • 使用 std::vector<sf::Texture> 以外的容器 - std::list<sf::Texture>std::forward_list<sf::Texture>
  • 存储指向纹理的指针 - std::vector<std::unique_ptr<sf::Texture>>

说明

您存储纹理对象以及引用它们的精灵。这是正确的,因为 spite 只是保留对其纹理的引用(指针)。这也意味着纹理地址必须在精灵生命周期内保持不变。

您似乎没有考虑 std::vector push_back() 的工作原理。 vector 最初分配一些内存,一旦没有地方插入新项目,vector 分配更多内存并将所有插入的项目和新项目复制到那里。所以所有的项目地址都变了。

在你的情况下,一个项目是一个纹理,它的地址在插入另一个纹理时改变,所以一些精灵 "looses" 它的纹理。这通常会导致绘制白色方块。