So I'm implementing a GUI system to my game.
The problem is, when I go to draw the rectangle shape and text, both contained in one structure, I'm getting a bounds error.
Relevant code:
Draw function found in GUIsystem.cpp
void GUI::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
//if the GUI isn't visible, return
if(visible == false)
return;
states.transform *= getTransform();
//THE PROBLEM***
for(Button* iterate : this->buttons)
{
std::cout << "drawing button" << std::endl;
target.draw(iterate->buttonBackground);
target.draw(iterate->buttonText);
//debugger breaks here, doesn't pass a single iteration but does display the "drawing button" to the console
//claims the problem is buttonText, getting a bounds error
}
//ignore this chunk, same thing as above but not using an iterator
//same exact problem though (bounds error problem with buttonText)
/*for(int i = 0; i < buttonReference-1; i++)
{
target.draw(buttons[i]->buttonBackground);
target.draw(buttons[i]->buttonText);
}
*/
//can't assume this is right, program breaks before this
std::cout << "drawing background" << std::endl;
target.draw(background);
}
Header for GUI class:
class GUI : public sf::Transformable, public sf::Drawable
{
public:
GUI();
//dimensions, position, background color, border color
GUI(sf::Vector2f dimensions, sf::Vector2f position, sf::Color BackgroundColor, sf::Color borderColor);
//returns a number as which refers to the button. Used in game loop to handle the players choice
//dimensions, position, text, button color, border color textcolor, font
int addButton(sf::Vector2f dimensions, sf::Vector2f position, const std::string& text, sf::Color buttonColor, sf::Color borderColor, sf::Color textColor, sf::Font font);
//updates the entire GUI, iterates over all the buttons to check if mouse is hovering or not
int update();
//simply switches visible bool
void show();
void hide();
//should draw the background, the button background and the button's text
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
bool visible;
private:
sf::Vector2f dimensions;
sf::Color backgroundColor;
sf::Color borderColor;
sf::RectangleShape background;
//IMPORTANT - vector of pointers to buttons **this is iterated through in the draw function
std::vector<Button*> buttons;
//a reference used to know which button was clicked on
int buttonReference;
};
The header for the Button class:
class Button
{
public:
Button();
//constructs the button, this is called within the GUI constructor
Button(sf::Vector2f dimensions, sf::Vector2f position, const std::string text, sf::Color buttonColor, sf::Color borderColor, sf::Color textColor, sf::Font font);
//handles when mouse is hovering over a button
void hovering();
//handles when mouse is no longer hovering over a button
void notHovering();
friend GUI;
protected:
//the actual shape drawn
sf::RectangleShape buttonBackground;
//the text drawn
sf::Text buttonText;
sf::Color textColor;
sf::Font* textFont;
};
OUTPUT:
First-chance exception at 0x00007FF6503C035E in The game.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
Unhandled exception at 0x00007FF6503C035E in The game.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
AUTOS:
+ this 0x0000008493f0ed00 {visible=true dimensions={x=0.000000000 y=0.000000000 } backgroundColor={r=0 '\0' ...} ...} GUI *
I'm thinking it might have something to do with the Button class not inheriting "Drawable", yet it's member variables are trying to be drawn but through a class which does inherit "Drawable" (GUI), though I'm not sure.
I can link the entire source for this through github if it's necessary, I know the abstraction makes it harder to find the problem. If there's any specific thing I should also include let me know. Any help would be great.
Thanks!
Actually, the button class stores buttonBackground and buttonText as protected! Reread the header I posted.
I see you friended the GUI class. Using the keyword friend does most of the time indicate a code smell, i.e. bad design, since friended classes break the encapsulation and there are usually better ways to go about things like that.
Your problem might well be, because of:
Button(..., sf::Font font);
You are making a copy of the font object, which gets destroyed as soon as the Button's constructor is left, leaving a reference in the text object to a non-existing font object.
Actually, the button class stores buttonBackground and buttonText as protected! Reread the header I posted.
I see you friended the GUI class. Using the keyword friend does most of the time indicate a code smell, i.e. bad design, since friended classes break the encapsulation and there are usually better ways to go about things like that.
Your problem might well be, because of:
Button(..., sf::Font font);
You are making a copy of the font object, which gets destroyed as soon as the Button's constructor is left, leaving a reference in the text object to a non-existing font object.
Okay, I fixed the encapsulation thing, now they're separate but communicating, however it still won't draw the buttons to the screen.
The GUI background draws fine and works as intended, however the buttons can't be seen for some reason.
Here's the fixed draw function:
In GUIsystem.cpp
void GUI::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
if(visible == false)
return;
states.transform *= getTransform();
target.draw(background);
for(int i = 0; i < buttonReference; i++)
{
std::cout<< "drawing button " << i << std::endl;
target.draw(buttons[i].buttonBackground);
target.draw(buttons[i].buttonText);
}
}
The "drawing button" iterates fine from 0-2 as it should, but the buttons can't be seen.
Here's the fixed header file and the segment where the draw function is called (might be relevant)
GUIsystem.h
class Button;
class GUI : public sf::Transformable, public sf::Drawable
{
public:
GUI();
//dimensions, position, background color, border color
GUI(sf::Vector2f dimensions, sf::Vector2f position, sf::Color BackgroundColor, sf::Color borderColor);
/*returns a number as which refers to the button. Used to handle choice logic
dimensions, position, text, button color, border color textcolor, font name ".txt"
*/
int addButton(sf::Vector2f dimensions, sf::Vector2f position, const std::string& text, sf::Color buttonColor, sf::Color borderColor, sf::Color textColor, sf::Font* font);
int update(sf::Vector2f &);
void show();
void hide();
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
bool visible;
std::vector<Button> buttons;
private:
sf::Vector2f dimensions;
sf::Color backgroundColor;
sf::Color borderColor;
sf::RectangleShape background;
int buttonReference;
};
class Button
{
public:
Button();
Button(sf::Vector2f dimensions, sf::Vector2f position, const std::string& text, sf::Color buttonColor, sf::Color borderColor, sf::Color textColor, sf::Font* font);
bool checkHovering(sf::Vector2i);
void hovering();
void notHovering();
sf::RectangleShape getButtonBackground();
sf::Text getButtonText();
sf::RectangleShape buttonBackground;
sf::Text buttonText;
private:
sf::Color textColor;
sf::Font* textFont;
};
In level1.cpp
gameWindow.setView(view);
gameWindow.clear();
gameWindow.draw(smap);
gameWindow.draw(*player);
gameWindow.draw(*enemy);
gameWindow.draw(*tree);
gameWindow.draw(pauseMenu);
gameWindow.display();
I imagine it's a problem with the draw function, maybe the shape/text objects I'm trying to draw don't exist or something?
**EDIT**
I whipped up a simple version of the GUI system in another application and it works completely fine...
Here's that source
main.cpp
sf::RenderWindow renderWindow(sf::VideoMode(640,480), "Color");
sf::Event event;
GUI menu(sf::Vector2f(50,150), sf::Vector2f(250,50));
menu.addButton(sf::Vector2f(40,15), sf::Vector2f(255, 60));
menu.addButton(sf::Vector2f(40,15), sf::Vector2f(255, 80));
menu.addButton(sf::Vector2f(40,15), sf::Vector2f(255, 100));
renderWindow.setFramerateLimit(30);
while (renderWindow.isOpen())
{
while(renderWindow.pollEvent(event))
{
if(event.type == sf::Event::EventType::Closed)
renderWindow.close();
if(event.type == sf::Event::KeyPressed)
{
if(event.key.code == sf::Keyboard::Escape)
{
if(menu.visible)
menu.hide();
else
menu.show();
}
}
}
renderWindow.clear();
renderWindow.draw(menu);
renderWindow.display();
GUI.h
#include "SFML\Graphics.hpp"
class Button;
class GUI : public sf::Transformable, public sf::Drawable
{
public:
GUI();
//dimensions, position, background color, border color
GUI(sf::Vector2f dimensions, sf::Vector2f position);
//dimensions, position, text, button color, border color textcolor, font name ".txt"
void addButton(sf::Vector2f dimensions, sf::Vector2f position);
void show();
void hide();
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
bool visible;
std::vector<Button> buttons;
private:
sf::RectangleShape background;
};
class Button
{
public:
Button();
Button(sf::Vector2f dimensions, sf::Vector2f position);
sf::RectangleShape buttonBackground;
};
GUI.cpp
#include "GUI.h"
GUI::GUI()
{}
GUI::GUI(sf::Vector2f dimensions, sf::Vector2f position)
{
background.setPosition(position);
background.setSize(dimensions);
background.setFillColor(sf::Color::Green);
visible = false;
}
void GUI::addButton(sf::Vector2f dimensions, sf::Vector2f position)
{
buttons.push_back(Button(dimensions,position));
}
void GUI::show()
{
visible = true;
}
void GUI::hide()
{
visible = false;
}
void GUI::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
if(!visible)
return;
states.transform *= getTransform();
target.draw(background);
for(int i = 0; i < 3; i++)
{
target.draw(buttons[i].buttonBackground);
}
}
Button::Button(sf::Vector2f dimensions, sf::Vector2f position)
{
buttonBackground.setSize(dimensions);
buttonBackground.setPosition(position);
buttonBackground.setFillColor(sf::Color::Blue);
}
Really not sure what the problem is here. Thanks for all the help so far by the way, everything's been cake since. Not sure why this system is messing with me so much.