class Entity {
public:
Entity(){
mySprite = Assets::instance()->spriteManager->request(spriteID); //If I debug fE texture size of mySprite, it outputs "good" results.
}
void render(){
somewindow.draw(*mySprite); //ACCESS VIOLATION: Pointer is null
}
private:
sf::Sprite * mySprite;
}
I know that Singletons are bad but no idea how to do it otherwiseThis is exactly why singletons/globals are bad: They let you "get away" with not figuring out the real solution to your problem.
class Assets {
public:
static Assets& instance();
static const unsigned short int
SPRITE__BALL = 0;
ResourceManager<sf::Sprite> * spriteManager;
protected:
Assets();
static Assets * _instance;
};
Assets.cppAssets* Assets::_instance = NULL;
Assets::Assets(){
spriteManager = new ResourceManager<sf::Sprite>(new Loader<sf::Sprite>());
}
Assets& Assets::instance(){
if (_instance == NULL) _instance = new Assets();
return *_instance;
}
ResourceManager.htemplate<class Res> class ResourceManager {
protected:
std::map<int, Res*> resourceList;
Loader<Res> * loader;
public:
~ResourceManager();
ResourceManager(Loader<Res> * loader);
void load(int key, std::string filePath);
Res* request(int key);
void unload(int key);
void dispose();
};
template<class Res> inline ResourceManager<Res>::~ResourceManager(){
this->dispose();
}
template<class Res> inline ResourceManager<Res>::ResourceManager(Loader<Res> * loader){
this->loader = loader;
}
template<class Res> inline void ResourceManager<Res>::load(int key, std::string filePath){
unload(key);
this->resourceList[key] = this->loader->loadFromFile(filePath);
}
template<class Res> inline Res* ResourceManager<Res>::request(int key){
assert(resourceList.find(key) != resourceList.end() && "Resource could not be found. Make sure to load it before requesting it.");
return this->resourceList[key];
}
template<class Res> inline void ResourceManager<Res>::unload(int key){
if (this->resourceList.find(key) != this->resourceList.end()){
delete this->resourceList[key];
this->resourceList.erase(key);
}
}
template<class Res> inline void ResourceManager<Res>::dispose(){
delete loader;
for (std::pair<int, Res*> kv : resourceList){
delete kv.second;
}
resourceList.clear();
}
Loader.h & Loader.cpptemplate<class T> class Loader {
public:
T* loadFromFile(const std::string& filePath);
~Loader() {}
};
template<>
sf::Texture* Loader<sf::Texture>::loadFromFile(const std::string& path) {
sf::Texture* texture = new sf::Texture();
texture->loadFromFile(path);
return texture;
}
template<>
sf::Sprite* Loader<sf::Sprite>::loadFromFile(const std::string& path){
sf::Texture* texture = new sf::Texture;
texture->loadFromFile(path);
return new sf::Sprite(*texture);
}
class BallEntity : public Entity {
public:
BallEntity(World * world, sf::RenderTarget* target, int radius);
... //Unnecessary functions omitted, fE getType(), update(),
void render();
private:
int radius;
sf::Sprite * ballSprite;
};
BallEntity::BallEntity(World * world, sf::RenderTarget* target, int radius) : Entity(world, target) {
this->radius = radius;
this->ballSprite = Assets::instance().spriteManager->request(Assets::SPRITE__BALL);
}
void BallEntity::render(){
ballSprite->setPosition(...);
ballSprite->setRotation(...);
target->draw(*ballSprite); // ACCESS VIOLATION!!!
}
Sorry, I thought it would be easier to understand the problem if only some simple pseudo-code was posted
Besides...May I ask where do I copy it? I mean, I thought that what I was doing was exactly the contrary, not copying it, since I work with pointers instead of the object itself?
class Entity{
public:
Entity(sf::RenderTarget*target);
virtual ~Entity() = 0;
virtual void render()=0;
protected:
sf::RenderTarget*target;
};
Entity::Entity(sf::RenderTarget*target){
this->target = target;
}
inline Entity::~Entity() { }
class BEntity : public Entity {
public:
BEntity(sf::RenderTarget* target);
~BEntity();
void render();
private:
sf::Sprite * ballSprite;
};
BEntity::BEntity(sf::RenderTarget* target) : Entity(target) {
this->ballSprite = Assets::instance().spriteManager->request(Assets::SPRITE__BALL);
this->target = target;
}
BEntity::~BEntity(){}
void BEntity::render(){
ballSprite->setPosition(200, 200);
ballSprite->setRotation(40);
target->draw(*ballSprite);
}
class World{
private:
std::vector<BEntity*> entities;
sf::RenderTarget * target;
public:
World(sf::RenderTarget * target);
void createBall();
void render();
};
World::World(sf::RenderTarget * target){
this->target = target;
}
void World::render(){
for (BEntity* e : entities){
e->render();
}
}
void World::createBall(){
entities.push_back(new BEntity(this->target));
}
int main()
{
Assets::instance().spriteManager->load(Assets::SPRITE__BALL, "ball.png");
World world(&window);
world.createBall();
sf::Clock clock;
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
if (event.type == sf::Event::Closed)
window.close();
}
sf::Time delta = clock.restart();
window.clear();
world.render();
window.display();
}
return 0;
}
class World;
class Entity {
public:
Entity(World * world, sf::RenderTarget* target);
virtual ~Entity() = 0;
Body* getPhysicsBody();
World* getWorld();
virtual Body* createBody() = 0;
virtual void render() = 0;
virtual void update(float delta) = 0;
virtual unsigned short int getType() = 0;
protected:
sf::RenderTarget* target;
Body * body;
World * parent;
};
inline Entity::~Entity() { }
Entity::Entity(World * world, sf::RenderTarget* target){
this->target = target;
this->parent = world;
}
Body * Entity::getPhysicsBody(){
return body;
}
World * Entity::getWorld(){
return parent;
}
class BallEntity : public Entity {
public:
BallEntity(World * world, sf::RenderTarget* target, int radius);
~BallEntity();
Body* createBody();
void render();
void update(float delta);
unsigned short int getType();
private:
int radius;
sf::Sprite * ballSprite;
};
BallEntity::BallEntity(World * world, sf::RenderTarget* target, int radius) : Entity(world, target) {
this->radius = radius;
this->ballSprite = Assets::instance().spriteManager->request(Assets::SPRITE__BALL);
this->body = createBody();
}
BallEntity::~BallEntity(){}
void BallEntity::update(float delta){}
void BallEntity::render(){
ballSprite->setPosition(200, 200);
ballSprite->setRotation(40);
target->draw(*ballSprite); //VIOLATION ERROR
}
Body * BallEntity::createBody(){
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(0, 0);
b2Body* b2Body = getWorld()->physicsWorld.CreateBody(&bodyDef);
b2CircleShape dynamicBox;
dynamicBox.m_radius = 0.5f;
dynamicBox.m_p.Set(0, 0);
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
b2Body->CreateFixture(&fixtureDef);
Body * body = new Body_Box2d(this, b2Body, &getWorld()->physicsWorld);
return body;
}
unsigned short int BallEntity::getType(){
return 0;
}
class Entity;
class World : public b2ContactListener {
private:
std::vector<Entity*> entities;
sf::RenderTarget * target;
public:
b2World physicsWorld;
World();
void deleteEntity(Entity * entityToRemove);
void createBall();
void moveEntity(float delta, sf::Vector2f velocity, Entity * entity);
void update(sf::Time delta);
void render();
void BeginContact(b2Contact* contact);
void EndContact(b2Contact* contact);
};
World::World() : physicsWorld(b2Vec2(0, 10)){
physicsWorld.SetContactListener(this);
this->entities.push_back(new WallEntity(this, 2, Assets::RESOLUTION_H*Assets::PIXELS_TO_METERS, 0, 0));
this->entities.push_back(new WallEntity(this, 2, Assets::RESOLUTION_H*Assets::PIXELS_TO_METERS, Assets::RESOLUTION_W*Assets::PIXELS_TO_METERS, 0));
}
void World::deleteEntity(Entity * entityToRemove){
entityToRemove->getPhysicsBody()->remove();
this->entities.erase(std::remove(entities.begin(), entities.end(), entityToRemove));
}
void World::createBall(){
BallEntity * be = new BallEntity(this, this->target, 0.5f);
this->entities.push_back(be);
be->getPhysicsBody()->setPositionY(0)->setPositionX(fmod(rand(), Assets::RESOLUTION_W*Assets::PIXELS_TO_METERS));
//TODO: APPLY FORCE
}
void World::moveEntity(float delta, sf::Vector2f velocity, Entity * entity){}
void World::render(){
for(Entity* e : entities){
e->render();
}
}
void World::update(sf::Time delta){
this->physicsWorld.Step(delta.asSeconds(), 8, 6);
std::vector<Entity*>::iterator iterator = entities.begin();
while (iterator != entities.end()){
if ((*iterator)->getPhysicsBody()->getPositionY() < Assets::RESOLUTION_H*Assets::PIXELS_TO_METERS){
delete *iterator;
iterator = entities.erase(iterator);
//TODO: SEND ENTITY DESTROY EVENT
(*iterator)->getPhysicsBody()->remove();
}else{
++iterator;
}
}
}
void World::BeginContact(b2Contact * contact){
Entity* e1 = (Entity*)contact->GetFixtureA()->GetBody()->GetUserData();
Entity* e2 = (Entity*)contact->GetFixtureB()->GetBody()->GetUserData();
if(e1->getType() == 0 && e2->getType() == 0){
//TODO: SEND BALL COLLIDE EVENT
}
if((e1->getType() == 0 && e2->getType() == 2) || e1->getType() == 2 && e2->getType() == 0){
//TODO:: SEND BALL COLLIDE PLATFORM EVENT
}
}
void World::EndContact(b2Contact * contact){
}
World gameWorld;
int main()
{
Assets::instance().spriteManager->load(Assets::SPRITE__BALL, "ball.png");
gameWorld.createBall();
sf::Clock clock;
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
if (event.type == sf::Event::Closed)
window.close();
}
sf::Time delta = clock.restart();
gameWorld.update(delta);
window.clear();
gameWorld.render();
window.display();
}
return 0;
}