【问题标题】:SFML sprite is a white square when making multiple textures制作多个纹理时,SFML 精灵是一个白色方块
【发布时间】:2018-03-17 12:47:06
【问题描述】:

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

}

截图如下:

【问题讨论】:

  • 为什么main不在main.cpp中?
  • 因为我想简化事情,所以我在 SFFM.cpp 的主函数中调用了两个函数启动和更新女巫,这样我就不需要看到主函数中的所有混乱。

标签: c++ sfml


【解决方案1】:

TL;DR 解决方案,或者:

  • 使用std::vector&lt;sf::Texture&gt; - std::list&lt;sf::Texture&gt;std::forward_list&lt;sf::Texture&gt; 以外的容器。
  • 存储指向纹理的指针 - std::vector&lt;std::unique_ptr&lt;sf::Texture&gt;&gt;

解释

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

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

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

【讨论】:

  • 感谢您的回答。但是然后我如何将指针添加到向量。反推?
  • @BlockySteve textures.emplace_back(new sf::Texture(texture)) 如果您使用的是 C++11,textures.push_back(std::make_unique<:texture>(texture))如果您使用的是 C++14。或者更好地使用第一个替代方案,在您的情况下,将“vector”替换为“list”就足够了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-13
  • 1970-01-01
  • 1970-01-01
  • 2021-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多