【问题标题】:SFML texture displaying as a white boxSFML 纹理显示为白框
【发布时间】:2015-03-13 03:55:45
【问题描述】:

我在一个基类中有一个纹理和精灵,它正在由另一个类扩展,但是在绘制时,精灵显示为一个白色框。我知道这与精灵丢失了它与纹理对象的链接有关,但我对 C++ 有点陌生,所以我不太确定它是怎么发生的。

这是代码(我已经删除了一些不相关的部分以减小尺寸):

皮卡.h:

#ifndef PICKUPS_PICKUP_H
#define PICKUPS_PICKUP_H

#include <SFML\Graphics.hpp>
#include "..\Player.h"

namespace Pickups
{
    class Pickup
    {
    private:
        sf::Vector2f position;
        sf::Texture texture;
        sf::Sprite sprite;
    public:
        Pickup();

        bool drop(float dt);
        void draw(sf::RenderWindow* window);

        void setTexture(sf::String name);

        void setPos(sf::Vector2f position);
        sf::Vector2f getPos();

        void isColliding(Player* player);

        virtual void onCollect(Player* player) = 0;
    };
}

#endif

pickup.cpp:

#include "Pickup.h"

namespace Pickups
{
    Pickup::Pickup()
    {
    }

    void Pickup::draw(sf::RenderWindow* window)
    {
        window->draw(sprite);
    }

    void Pickup::setTexture(sf::String name)
    {
        if (!texture.loadFromFile("images/pickups/" + name + ".png"))
            std::cout << "Error loading image: images/pickups/" + name.toAnsiString() + ".png" << std::endl;
        else
            sprite.setTexture(texture);
    }
}

健康.h:

#ifndef PICKUPS_HEALTH_H
#define PICKUPS_HEALTH_H

#include "Pickup.h"

namespace Pickups
{
    class Health : public Pickup
    {
    private:
        int worth;
    public:
        Health(sf::Vector2f position, int worth);
        void onCollect(Player* player);
    };
}

#endif

健康.cpp:

#include "Health.h"

namespace Pickups
{
    Health::Health(sf::Vector2f position, int worth)
    {
        setTexture("health");
        setPos(position);
        this->worth = worth;
    }

    void Health::onCollect(Player* player)
    {
        player->addLives(worth);
    }
}

(我不知道这是否是问题的一部分,但我也不妨发布它) 我将拾音器存储在一个向量中,如下所示:

std::vector<Pickups::Health> pickups;

【问题讨论】:

  • 你应该检查texture.loadFromFile是否成功
  • 你是在调用 setTexture 之前尝试绘制吗?
  • 似乎问题的原因是由于某种原因将拾音器存储在向量中......

标签: c++ sfml


【解决方案1】:

为了避免此类问题,我总是将Texture 声明为指针并在类的析构函数中将其删除。像这样,只要您的对象没有被破坏,您的 Texture 就会一直存在。

验证图片的加载总是好的:

    if (!texture.loadFromFile("images/pickups/health.png")){
      //some error code
    }

但这不是这里的问题。

【讨论】:

  • 我实际上并没有使用 setTexture 函数,而是使用了基类中的纹理。我已经验证纹理的加载也成功了。
  • 我为 setTexture 编辑了我的代码并开始使用它,但是它仍然不起作用:/
【解决方案2】:

A std::vector 复制或移动插入的元素,所以只要您有默认的复制构造函数或只要您不更改这种脏的每个元素的纹理-样式,(元素只需要有一个共同的纹理对象来实际指向,所以你浪费了很多内存)sf::Sprite 对象持有的纹理指针变得无效。要了解为什么我们需要考虑插入时会发生什么:

您设置了一个不错的 Pickupish 对象并将其添加到调用复制构造函数的向量中。假设您想要添加的好对象是对象A,而现在添加/复制的对象是B。两者都有一个精灵S 和一个纹理T。两种纹理都有效,但问题是这样的:AS 指向AT,所以复制到B 之后BS 也指向@ 987654337@的T!我认为A 只是暂时的,所以它连同它的纹理一起被破坏了,你就得到了一个漂亮的白色盒子。

您可以通过其他一些肮脏的方式解决此问题,例如在Pickup 中创建自己的复制构造函数,如下所示:

Pickup::Pickup(const Pickup& other)
: position(other.position), texture(other.texture), sprite(other.sprite)
{ sprite.setTexture(texture); }

或通过存储std::unique_ptr&lt;Pickups::Health&gt; 而不仅仅是Pickups::Health

但是,您应该使用一种更好的方法是某种Resourcemanager,它只存储所有相关的纹理,最好是一个大图块集,因为加载一次但大的比加载多个但小的纹理更快。您可以编写自己的非常简单的管理器或使用其他一些例如来自伟大的Thor 图书馆的那个。要将特定图块设置为 Sprite 的纹理,只需调用 sf::Sprite::setTextureRect


我想提一下对您的设计的一些额外改进。让Pickup 派生自sf::Drawable 并定义其纯虚拟draw 函数,您可以将其设为私有。因此,您的来自Pickup 的派生对象不需要知道来自任何sf::RenderTarget 的信息,您只需执行target.draw(myPickupObject)

不需要存储位置,让Pickup也从sf::Transformable派生。您不必实现任何功能,您唯一需要做的就是将矩阵应用于传递给drawsf::RenderStates 对象。

你的draw 函数可能看起来像这样:

void Pickup::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
    //'applying' transformation-matrix
    states.transform *= getTransform();

    target.draw(sprite, states);
}

所以你的Pickup 现在只有sf::Sprite 作为成员,总体而言你的标题只需要包含SFML/Graphics/Sprite.hpp

【讨论】:

  • 哇,这是一个很棒的答案。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2021-02-01
  • 2018-11-17
  • 1970-01-01
  • 2020-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-13
相关资源
最近更新 更多