SFML2 スプライト用の単純なスプライト キャッシュを作成しています。スプライトへのポインターのマップを保持するマネージャー クラスがあります。また、所有者マップへの参照を保持するスプライト クラスもあります。問題はスプライトのデストラクタにあります。次のようになります。
~ActualSprite()
{
if(m_iteratorLocation != m_ownerMap.end())
{
m_ownerMap.erase(m_iteratorLocation);
}
}
m_iteratorLocation は、スプライト マップ内のスプライトの現在の位置であると想定されています。スプライト コンストラクターで初期化されます。ここでは、スプライト マネージャーからのスプライト作成メソッドを示します。
SpritePtr getSprite(SpriteId name)
{
if(!spriteMap[name])
{
spriteMap[name] = std::tr1::make_shared< ActualSprite >(spriteMap, spriteMap.find(name));
clipSprite(name);
return spriteMap[name];
}
else
return spriteMap[name];
}
基本的に、プログラムを終了すると、次のような例外/エラー メッセージが表示されますExpression: map/set iterator outside range
。
spriteMap.find(name)
最初は、名前が見つからず、spriteMap.end()
代わりに返されるためにこれが起こると思っていました。しかし、私はそれを理解していません。キーをマップにspriteMap[name]
追加するという最初の言及ではありませんか? name
とにかく、イテレータが.end()と等しくない場合にのみマップエントリを消去するifステートメントを追加しましたが、それでもポップアップします。
基本的に、イテレータの代わりに、消去に enum という名前を使用して動作しますが、エラー メッセージが表示される理由を知りたいと思っています。
これは、現在の作業バージョンと、エラーをスローするコメント付きイテレータ バージョンを含む完全なコードです。
#include <SFML/Graphics.hpp>
#include <memory>
#include <map>
enum SpriteId
{
ITEM1,
ITEM2,
ITEM3,
ITEM4,
ITEM5
};
const int WIDTH = 100;
const int HEIGHT = 100;
class ActualSprite;
typedef std::tr1::shared_ptr< ActualSprite > SpritePtr;
typedef std::map< SpriteId, SpritePtr > SpriteMap;
class ActualSprite : public sf::Sprite
{
private:
//SpriteMap::iterator m_iteratorLocation;
SpriteMap &m_ownerMap;
SpriteId &m_name;
public:
//ActualSprite(SpriteMap &ownerMap, SpriteMap::iterator iteratorLocation) : m_ownerMap(ownerMap), m_iteratorLocation(iteratorLocation)
//{}
ActualSprite(SpriteMap &ownerMap, SpriteId &name) : m_ownerMap(ownerMap), m_name(name)
{}
~ActualSprite()
{
m_ownerMap.erase(m_name);
}
//~ActualSprite()
//{
// if(m_iteratorLocation != m_ownerMap.end())
// {
// m_ownerMap.erase(m_iteratorLocation);
// }
//}
};
class SpriteManager
{
private:
SpriteMap spriteMap;
sf::Texture& m_texture;
void clipSprite(SpriteId name)
{
spriteMap.at(name)->setTexture(m_texture);
switch(name)
{
case ITEM1: spriteMap.at(name)->setTextureRect(sf::IntRect(0,0,WIDTH,HEIGHT));break;
case ITEM2: spriteMap.at(name)->setTextureRect(sf::IntRect((1*WIDTH),0,WIDTH,HEIGHT));break;
case ITEM3: spriteMap.at(name)->setTextureRect(sf::IntRect((2*WIDTH),0,WIDTH,HEIGHT));break;
case ITEM4: spriteMap.at(name)->setTextureRect(sf::IntRect((3*WIDTH),0,WIDTH,HEIGHT));break;
case ITEM5: spriteMap.at(name)->setTextureRect(sf::IntRect((4*WIDTH),0,WIDTH,HEIGHT));break;
//default: exception or somethin'
}
}
public:
SpriteManager(sf::Texture& texture) : m_texture(texture)
{}
SpritePtr getSprite(SpriteId name)
{
if(!spriteMap[name])
{
spriteMap[name] = std::tr1::make_shared< ActualSprite >(spriteMap, name);
/*spriteMap[name] = std::tr1::make_shared< ActualSprite >(spriteMap, spriteMap.find(name));*/
clipSprite(name);
return spriteMap[name];
}
else
return spriteMap[name];
}
};
int main()
{
sf::RenderWindow window(sf::VideoMode(800,600), "Test", sf::Style::Titlebar | sf::Style::Close);
sf::RectangleShape background(sf::Vector2f(800.0f,600.0f));
window.setFramerateLimit(30);
sf::Texture spriteSheet;
if(!spriteSheet.loadFromFile("SpriteSheet.png"))
{
return 1;
}
SpriteManager sprites(spriteSheet);
SpritePtr sprite = sprites.getSprite(ITEM2);
SpritePtr sprite2 = sprites.getSprite(ITEM4);
sprite->setPosition(100,100);
sprite2->setPosition(200,100);
while(window.isOpen())
{
sf::Event event;
while( window.pollEvent(event))
{
if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sf::Vector2i currentPos = sf::Mouse::getPosition(window);
sprite->setPosition((static_cast<float>(currentPos.x) - (WIDTH/2)), (static_cast<float>(currentPos.y) - (HEIGHT/2)));
}
if(event.type == sf::Event::Closed)
{
window.close();
}
}
window.clear();
window.draw(background);
window.draw(*sprite);
window.draw(*sprite2);
window.display();
}
return 0;
}
注:これは単なるテストであるため、すべてが 1 つの .cpp ファイルにあり、項目名が説明的ではないのはそのためです。