GameObject class doesn't draw a image but a white box instead

Started by
13 comments, last by Rattenhirn 7 years, 7 months ago

I'm having a problem where my GameObject doesn't display the image I've assigned it to display.

I gave it a valid image path to a file of a format which is supported by the library I'm using.

However creating a object of only my Sprite class seems to work (the image that should be displayed, gets displayed).

GameObject.h


#pragma once

#include "Sprite.h"

class GameObject
{

public:

	GameObject();
	GameObject(std::string m_texturePath, float m_x, float m_y);
	~GameObject();

	void Update();
	void Draw(sf::RenderWindow &m_window);
	void HandleEvents(float m_deltaTime);

private:
	
	Sprite _sprite;

};

GameObject.cpp


#include "GameObject.h"



GameObject::GameObject()
{
}

GameObject::GameObject(std::string m_texturePath, float m_x, float m_y)
{

	_sprite = Sprite(m_texturePath, m_x, m_y);

}

void GameObject::Draw(sf::RenderWindow &m_window)
{
	_sprite.Draw(m_window);
}

Sprite.h


#pragma once

#include <SFML\Graphics.hpp>
#include <string>
#include <iostream>

class Sprite
{

public:
	
	Sprite();
	Sprite(std::string m_texturePath, float m_x, float m_y);
	~Sprite();

	void Draw(sf::RenderWindow &m_window);
	void SetPosition(float m_x, float m_y);

	void SetVisible(bool m_visible);

private:

	sf::Sprite _sprite;
	sf::Texture _texture;

	bool _visible = true;
	bool _created = false;

};


Sprite.cpp


#include "Sprite.h"

Sprite::Sprite()
{

}

Sprite::Sprite(std::string m_texturePath, float m_x, float m_y)
{

	if (_created == false)
	{

		if (_texture.loadFromFile(m_texturePath) == false)
		{
			std::cout << "Failed to load texture : " << m_texturePath << std::endl;
			_created = false;
			return;
		}

		_sprite.setTexture(_texture);
		_sprite.setPosition(m_x, m_y);

		_created = true;

	}

}

void Sprite::Draw(sf::RenderWindow &m_window)
{
	if (_visible == true)
	{
		m_window.draw(_sprite);
	}
}

void Sprite::SetVisible(bool m_visible)
{
	_visible = m_visible;
}

void Sprite::SetPosition(float m_x, float m_y)
{
	_sprite.setPosition(m_x, m_y);
}

MainMenuState.h


#pragma once

#include "GameState.h"
#include "Sprite.h"
#include "GameObject.h"

class MainMenuState : public GameState
{

public:

	MainMenuState();
	~MainMenuState();

	void Update();
	void HandleEvents(float m_deltaTime);
	void Draw(sf::RenderWindow &m_window);

private:

	GameObject gameObject;

};


MainMenuState.cpp


#include "MainMenuState.h"



MainMenuState::MainMenuState()
{

	gameObject = GameObject("src/Textures/test.png", 10, 10);

}

void MainMenuState::Update()
{
	gameObject.Update();
}

void MainMenuState::Draw(sf::RenderWindow &m_window)
{
	gameObject.Draw(m_window);
}

I removed some of the functions which didn't do anything yet and also removed functions which were never gonna be called to reduce the amount of code.

I'm not sure if this still fits in the general-programming section since it has parts of the SFML library in it.

Advertisement

I'm trying to create a GameObject class, which inherits from my Sprite class.


I am tempted to stop reading there. Is it the case that a game object IS A sprite? Inheritance should be used sparingly. You probably meant that a game object HAS A sprite, in which case GameObject should have a member of type Sprite.

I did read the rest of your post. I suspect _created ends up true in some way. I don't see all the code, so I can't be sure. But this should be easy to figure out with a debugger.

I'm trying to create a GameObject class, which inherits from my Sprite class.


I am tempted to stop reading there. Is it the case that a game object IS A sprite? Inheritance should be used sparingly. You probably meant that a game object HAS A sprite, in which case GameObject should have a member of type Sprite.

I did read the rest of your post. I suspect _created ends up true in some way. I don't see all the code, so I can't be sure. But this should be easy to figure out with a debugger.

The game object is partially a sprite, I guess?

The sprite class has a x and y position, move function and such which the GameObject class should also have, do you recommend just giving it a sprite object instead of inheriting?

and _created is working as it should, false until the Create function or Sprite constructor gets called.

Generally, object oriented programming is less useful in practice than in theory, particularly the classical, school-example type of inheritance. Nobody really does that kind of stuff, and it's generally a code smell if you've got inheritance trees that are more than two levels deep, with the first level being an abstract base class.

I would say that your game object should HAVE a sprite, rather than BE a sprite. I would also probably separate the coordinates of the game object, which would be in your game world frame of reference, whereas the sprite position would be in graphics device coordinates

Eric Richards

SlimDX tutorials - http://www.richardssoftware.net/

Twitter - @EricRichards22

Generally, object oriented programming is less useful in practice than in theory, particularly the classical, school-example type of inheritance. Nobody really does that kind of stuff, and it's generally a code smell if you've got inheritance trees that are more than two levels deep, with the first level being an abstract base class.

I would say that your game object should HAVE a sprite, rather than BE a sprite. I would also probably separate the coordinates of the game object, which would be in your game world frame of reference, whereas the sprite position would be in graphics device coordinates

Not sure what you mean by "school-example type of inheritance", what's the difference between that and "good" inheritance?

For the other part, that does make a lot more sense, I'll go ahead and do that instead.

Not sure what you mean by "school-example type of inheritance", what's the difference between that and "good" inheritance?

In school they teach you things like "a triangle is-a shape" and a "car is-a vehicle." They are examples that are simple to grasp, but in practice they are problematic. A game object should almost certainly not be a sprite, in whole or in part. That implies a lot of things that are extremely inflexible: all game objects are visible sprites with position, no game object can have more than one associated sprite, et cetera.

As for your actual problem, you're not providing enough information to say. You should most more of the code. In particular it's unclear where all of your members are initialized and to what, and as another poster commented above, that's likely the culprit.

Let my start of by concurring with the previous posters about your apparent architectural choices.

Now on to the thing you actually asked about. Unfortunately, the code you provided is incomplete and misses details needed to accurately diagnose the problem.

A stab in the dark:

The constructor sets the position of the sprite, the Create method does not. I can't determine what the default position is, but it might just be off screen...

Some questions that might help with the diagnosis (if you don't want to post all the relevant source code):

Where is "_created" initialized?

How is the GameObject you call Create on created?

Does GameObject have a default constructor?

What does it do?

Some general hints:

Pass non trivial objects like std::string by const reference and not by value.

Checking m_x and m_y for NULL seems confusing. It's will just check if their value is equal to 0.0f.

I hope that helps!

Not sure what you mean by "school-example type of inheritance", what's the difference between that and "good" inheritance?

In school they teach you things like "a triangle is-a shape" and a "car is-a vehicle." They are examples that are simple to grasp, but in practice they are problematic. A game object should almost certainly not be a sprite, in whole or in part. That implies a lot of things that are extremely inflexible: all game objects are visible sprites with position, no game object can have more than one associated sprite, et cetera.

As for your actual problem, you're not providing enough information to say. You should most more of the code. In particular it's unclear where all of your members are initialized and to what, and as another poster commented above, that's likely the culprit.

Oh, I understand. I'm not sure why I didn't edit my code and added more in, I was thinking about it but for some reason never did it. I'll do that right away.


Let my start of by concurring with the previous posters about your apparent architectural choices.

Now on to the thing you actually asked about. Unfortunately, the code you provided is incomplete and misses details needed to accurately diagnose the problem.

A stab in the dark:

The constructor sets the position of the sprite, the Create method does not. I can't determine what the default position is, but it might just be off screen...

Some questions that might help with the diagnosis (if you don't want to post all the relevant source code):

Where is "_created" initialized?

How is the GameObject you call Create on created?

Does GameObject have a default constructor?

What does it do?

Some general hints:

Pass non trivial objects like std::string by const reference and not by value.

Checking m_x and m_y for NULL seems confusing. It's will just check if their value is equal to 0.0f.

I hope that helps!

The position code is now commented out, I forgot to edit the new code in, and the check was just for debugging use. :P

The questions you have will be in my updated post. :)

The code looks complete now and you replaced inheritance with composition, great!

What struck me when reading it is, that you copy the Sprite once in the GameObject constructor. Here you should really use initialization lists when initializing members in a constructor, and that might also be the cause of the issue.

Here's how to initialize a member without making an extra copy:


GameObject::GameObject(std::string m_texturePath, float m_x, float m_y)
	: _sprite(m_texturePath, m_x, m_y);
{
}

I don't know much about SFML, so I took a quick peek at the documentation. Google took me here: http://www.sfml-dev.org/tutorials/2.0/graphics-sprite.php

Curiously it has a section talking about the "white rectangle problem", which tells you that you have to manage the lifetime of sf::Texture instances very carefully. That's not very beginner friendly, but I'm sure they had their reasons. Unfortunately it seems that they didn't put any measures in place to stop people from committing this mistake.

So, given the fact that you (probably unintentional) copy both the sprite and the texture around, it is unlikely that their internal state is still consistent. The above code snippet should fix that.

Bonus info: If you have a class that can't be copied safely, like your Sprite class, you can emply the non copyable idiom to get the compiler to tell you if you do it by mistake:

https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-copyable_Mixin

I hope that helps!

The code looks complete now and you replaced inheritance with composition, great!

What struck me when reading it is, that you copy the Sprite once in the GameObject constructor. Here you should really use initialization lists when initializing members in a constructor, and that might also be the cause of the issue.

Here's how to initialize a member without making an extra copy:


GameObject::GameObject(std::string m_texturePath, float m_x, float m_y)
	: _sprite(m_texturePath, m_x, m_y);
{
}

I don't know much about SFML, so I took a quick peek at the documentation. Google took me here: http://www.sfml-dev.org/tutorials/2.0/graphics-sprite.php

Curiously it has a section talking about the "white rectangle problem", which tells you that you have to manage the lifetime of sf::Texture instances very carefully. That's not very beginner friendly, but I'm sure they had their reasons. Unfortunately it seems that they didn't put any measures in place to stop people from committing this mistake.

So, given the fact that you (probably unintentional) copy both the sprite and the texture around, it is unlikely that their internal state is still consistent. The above code snippet should fix that.

Bonus info: If you have a class that can't be copied safely, like your Sprite class, you can emply the non copyable idiom to get the compiler to tell you if you do it by mistake:

https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-copyable_Mixin

I hope that helps!

Didn't know initialization lists did that, however it didn't seem to solve my problem. :/

And I don't think I'm doing this same mistake anywhere else in my application.

And for the bonus, I'll go ahead and read up on that :)

This topic is closed to new replies.

Advertisement