-
Hello, so i'm messing with basic sfml engine about 1 week and i'm tired of it. Can anyone just help me to finish it? I just need one small step to finish it. So here is my problem:
GameObject::GameObject* gameobject = GameObject::getGameObject("player_gameobject");
window.draw(*gameobject->getSprite());
When i draw it texture is white.
-
Did you read The White Square Problem (http://www.sfml-dev.org/tutorials/2.4/graphics-sprite.php#the-white-square-problem) paragraph in the sprite tutorial?
If so, do you understand issue?
-
Okay, so how do i fix this?
-
Don't let the texture go out of scope as long as the sprite exists.
Don't let the texture being moved in memory (e.g. don't use a std::vector as container).
-
Can you please tell me where is my mistake :-\?
GameObject.cpp:
#include "GameObject.h"
#include <unordered_map>
namespace GameObject {
std::unordered_map<std::string, GameObject> gameobjects;
GameObject::GameObject() {
name = "gameobject";
sprite = sf::Sprite();
}
GameObject::GameObject(std::string gameobject_name, sf::Sprite gameobject_sprite, sf::Texture sprite_texture, int gameobject_position_x, int gameobject_position_y) {
name = gameobject_name;
sprite = gameobject_sprite;
sprite.setTexture(sprite_texture);
sprite.setPosition(gameobject_position_x, gameobject_position_y);
}
void GameObject::setName(std::string gameobject_name) {
name = gameobject_name;
}
void GameObject::setSprite(sf::Sprite gameobject_sprite) {
sprite = gameobject_sprite;
}
void GameObject::setTexture(sf::Texture gameobject_texture) {
sprite.setTexture(gameobject_texture);
}
std::string* GameObject::getName() {
return &name;
}
sf::Sprite* GameObject::getSprite() {
return &sprite;
}
void addGameObject(GameObject gameobject) {
gameobjects[*gameobject.getName()] = gameobject;
}
void removeGameObject(std::string gameobject_name) {
gameobjects.erase(gameobject_name);
}
GameObject* getGameObject(std::string gameobject_name) {
return &gameobjects[gameobject_name];
}
//std::vector<GameObject*> getGameObjects() {
// std::vector<GameObject*> gameobjects_c2;
// gameobjects_c2.reserve(gameobjects.size());
// for (auto gameobject : gameobjects) {
// gameobjects_c2.insert(gameobjects_c2.begin(), &gameobject.second);
// }
// return gameobjects_c2;
//}
}
GameObject.h:
#include <SFML\Graphics.hpp>
namespace GameObject {
class GameObject {
private:
std::string name;
sf::Sprite sprite;
public:
GameObject();
GameObject(std::string gameobject_name, sf::Sprite gameobject_sprite, sf::Texture sprite_texture, int gameobject_position_x, int gameobject_position_y);
void setName(std::string gameobject_name);
void setSprite(sf::Sprite gameobject_sprite);
void setTexture(sf::Texture gameobject_texture);
std::string* getName();
sf::Sprite* getSprite();
};
void addGameObject(GameObject gameobject);
void removeGameObject(std::string gameobject_name);
GameObject* getGameObject(std::string gameobject_name);
/*std::vector<GameObject*> getGameObjects();*/
}
Graphics.cpp:
#include <SFML\Graphics.hpp>
#include "Game.h"
#include "GameObject.h"
#include <iostream>
namespace Graphics {
sf::RenderWindow window;
void openWindow() {
window.create(sf::VideoMode(800, 800), Game::getGameName());
window.setVerticalSyncEnabled(true);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
Game::closeGame();
break;
}
}
window.clear();
GameObject::GameObject* gameobject = GameObject::getGameObject("player_gameobject");
window.draw(*gameobject->getSprite());
window.display();
//for (i = 0; i<drawTable.size(); i++)
//{
// m_app->Draw(*drawTable[i]); //Here is the line causing the crash !
//}
//i = 0;
}
}
void closeWindow() {
window.close();
}
}
Graphics.h:
#include <SFML\Graphics.hpp>
namespace Graphics {
void openWindow();
void closeWindow();
}
-
I think the problem is your GameObject::setTexture method. You are passing the sf::Texture by value which means that particular instance will be destroyed as soon as that method returns. You need to pass a reference or pointer and keep that reference or pointer alive somewhere else.
So a quick example:
In GameObject.h
// Rest of Game Object Declaration
void setTexture(const sf::Texture & gameobject_texture);
// Rest of Game Object Declaration
In GameObject.cpp
// Rest of Game Object Definition
// Basically the same as before
void GameObject::setTexture(const sf::Texture & gameobject_texture) {
sprite.setTexture(gameobject_texture);
}
// Rest of Game Object Definition
In file where you set the texture:
// Rest of Code
sf::Texture texture; // IMPORTANT: Make sure texture outlives the GameObject
// Initialize the texture somehow
GameObject::GameObject* gameobject = GameObject::getGameObject("player_gameobject");
gameobject->setTexture(texture);
// Rest of Code
-- OR --
If you have C++11 or better compatibility (At least I think this should work)
// Rest of Code
std::shared_ptr<sf::Texture> texture = std::make_shared(new Texture()); // Now you can store the pointer somewhere else
// Initialize the texture somehow
GameObject::GameObject* gameobject = GameObject::getGameObject("player_gameobject");
gameobject->setTexture(*texture);
// Rest of Code
You could also use std::unique_ptr<sf::Texture>
which enforces stricter ownership rules.
-
Thank you very much!
-
Not working... i tried everything :-\. Here is rest of my code:
Game.cpp:
#include "Game.h"
#include "Graphics.h"
#include <iostream> //to remove
#include "GameObject.h"
namespace Game {
const std::string game_name = "Game";
bool game_opened = false;
bool game_running = false;
sf::Thread updategame_thread(&updateGame);
void openGame() {
if (game_opened) return;
loadResources();
startGame();
game_opened = true;
Graphics::openWindow();
}
void closeGame() {
if (game_opened == false) return;
stopGame();
game_opened = false;
Graphics::closeWindow();
}
void loadResources() {
sf::Texture player_texture;
player_texture.loadFromFile("C:/Users/User/Desktop/RANDOM ITEMS/BI logo.png");
GameObject::GameObject gameobject("test", sf::Sprite(), player_texture); //create go
GameObject::addGameObject(gameobject);
}
GameObject.cpp:
#include <SFML\Graphics.hpp>
#include <string>
#include "GameObject.h"
namespace GameObject {
std::unordered_map<std::string, GameObject> gameobjects;
GameObject::GameObject() {
name = "gameobject";
sprite = sf::Sprite();
texture = sf::Texture();
sprite.setTexture(texture);
}
GameObject::GameObject(std::string gameobject_name, sf::Sprite gameobject_sprite, sf::Texture gameobject_texture) {
name = gameobject_name;
sprite = gameobject_sprite;
texture = gameobject_texture;
sprite.setTexture(texture);
}
void addGameObject(GameObject gameobject) {
gameobjects[*gameobject.getName()] = gameobject;
}
GameObject* getGameObject(std::string gameobject_name) {
return &gameobjects[gameobject_name];
}
std::string* GameObject::getName() {
return &name;
}
sf::Sprite* GameObject::getSprite() {
return &sprite;
}
sf::Texture* GameObject::getTexture() {
return &texture;
}
}
And Graphics.cpp:
#include <SFML\Graphics.hpp>
#include "Game.h"
#include "GameObject.h"
namespace Graphics {
sf::RenderWindow window;
void openWindow() {
window.create(sf::VideoMode(800, 800), *Game::getGameName());
window.setVerticalSyncEnabled(true);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
Game::closeGame();
break;
}
}
window.clear();
GameObject::GameObject* gameobject = GameObject::getGameObject("test");
window.draw(*gameobject->getSprite()); //and i got white box...
window.display();
}
}
Btw i just started with c++, i came from java. So i think that's the reason why i have problem with pointers...
-
What about the corrected Object.h
-
I don't know what you mean?