Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Vector of custom class, how to populate?  (Read 2379 times)

0 Members and 1 Guest are viewing this topic.

Canvas

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Vector of custom class, how to populate?
« on: October 09, 2014, 09:26:47 pm »
Hello there

I have myself a custom TextObject class and I have myself a GameState class which has a vector of TextObjects, so basically this is how I am populating my vector

TextObject textObject;
        TextObjects.push_back(textObject);
        TextObjects.push_back(textObject);
        TextObjects.at(0).Setup(200, 350, "Score : " + std::to_string(Score), 24, fontLoader.Fonts[FontNames::Main_Font]);
        TextObjects.at(0).CentreText();
        TextObjects.at(1).Setup(200, 100, "Game Over", 48, fontLoader.Fonts[FontNames::Main_Font]);
        TextObjects.at(1).SetRotationAnimation(-12, 12, 0.1);
       

To me this doesn't look quite right but it does work, but I have myself in a pickle, sometimes the player may get a new highscore and if they do I want to show some more text, so I have my code like so

TextObject textObject;
        TextObjects.push_back(textObject);
        TextObjects.push_back(textObject);
        TextObjects.at(0).Setup(200, 350, "Score : " + std::to_string(Score), 24, fontLoader.Fonts[FontNames::Main_Font]);
        TextObjects.at(0).CentreText();
        TextObjects.at(1).Setup(200, 100, "Game Over", 48, fontLoader.Fonts[FontNames::Main_Font]);
        TextObjects.at(1).SetRotationAnimation(-12, 12, 0.1);
       
        if (highScore == true)
        {
                TextObject txtObject;
                TextObjects.push_back(txtObject);
                TextObjects.at(2).Setup(200, 3, "New high score!", 24, fontLoader.Fonts[FontNames::Main_Font]);
        }

But when I go to render my third text item in my vector I get this error "Unhandled exception at 0x5361DCE2 (sfml-graphics-d-2.dll) in SpaceDestroyer.exe: 0xC0000005: Access violation reading location 0xCDCDCDD0." in xtree "_Nodeptr _Pnode = _Root();"

My TextObject has a standard constructor so even If I try

if (highScore == true)
        {
                TextObjects.push_back(TextObject());
                TextObjects.at(2).Setup(200, 3, "New high score!", 24, fontLoader.Fonts[FontNames::Main_Font]);
        }

I still get the error, what is the correct way for my to populate my vector? or is there a better way to store objects than using a vector?

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Vector of custom class, how to populate?
« Reply #1 on: October 09, 2014, 09:38:24 pm »
Since you haven't shown us TextObject or TextObjects or your drawing code, all we can do is guess, but the obvious possibility is that adding a third element to the vector makes it reallocate memory (which is normal), and something in your TextObject class gets broken when that happens (which would be a major bug).

You need to use a debugger to track down exactly where this access violation happens.  That error message implies you're using Visual Studio, so go read about how to use the debugger it comes with.

Quote
I still get the error, what is the correct way for my to populate my vector? or is there a better way to store objects than using a vector?

These are questions we simply can't answer without knowing exactly what you're trying to achieve.  Just from the code in this post, I don't even know why you want them in a container to begin with, so I have no idea which (if any) container would be best.

That said, when you want a dynamically resizing container, std::vector is almost never a bad choice.
« Last Edit: October 09, 2014, 09:39:59 pm by Ixrec »

Canvas

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Re: Vector of custom class, how to populate?
« Reply #2 on: October 09, 2014, 10:00:42 pm »
Ixrec I do apologize about not showing my TextObject code I will show it right here

#include "TextObject.h"

TextObject::TextObject()
{

}

void TextObject::Setup(float xSet, float ySet, std::string textSet, int fontSize, sf::Font& fontSet)
{
        XPos = xSet;
        YPos = ySet;
        TextString = textSet;
        FontSize = fontSize;
        Font = fontSet;
        Animated = false;
        StartRotationPosition = 0;
        EndRotationPosition = 0;
        Rotation = 0;
        RotateSpeed = 0;

        Text.setColor(sf::Color(255, 255, 255, 255));
        Text.setCharacterSize(FontSize);
        Text.setFont(Font);
        Text.setPosition(XPos, YPos);
        Text.setString(TextString);
}

TextObject::~TextObject()
{

}

void TextObject::CentreText()
{
        Text.setOrigin(Text.getLocalBounds().width / 2, Text.getLocalBounds().height / 2);
}

void TextObject::SetRotationAnimation(float startRotation, float endRotation, float speed)
{
        Animated = true;
        StartRotationPosition = startRotation;
        EndRotationPosition = endRotation;

        Rotation = 0;
        RotateSpeed = speed;
}

void TextObject::Draw(sf::RenderWindow& window)
{
        if (Animated == false)
        {
                window.draw(Text);     
        }
        else
        {
                DrawAnimation(window);
        }
       
}

void TextObject::DrawAnimation(sf::RenderWindow& window)
{
        Rotation += RotateSpeed;

        Text.setOrigin(Text.getLocalBounds().width / 2, Text.getLocalBounds().height / 2);
        Text.setRotation(Rotation);

        window.draw(Text);

        if (Rotation >= EndRotationPosition)
        {
                RotateSpeed = -RotateSpeed;
        }

        if (Rotation <= StartRotationPosition)
        {
                RotateSpeed = -RotateSpeed;
        }
}
 

Draw code goes something like this (because there is alot of calling :)

void Game::Draw()
{
        renderService.Window.clear();

        if (gameState == GameStates::MainMein)
        {
                mainMenuState.Draw(renderService.Window);
        }

        renderService.Window.display();
}

//mainMenuState.Draw method below
void State::Draw(sf::RenderWindow& window)
{
        DrawDisplayObjects(window);
        DrawButtonObjects(window);
        DrawTextObjects(window);
}

void State::DrawTextObjects(sf::RenderWindow& window)
{
        for (int i = 0; i < TextObjects.size(); i++)
        {
                TextObjects.at(i).Draw(window);
        }
}

 

Let me know if you need anymore of my code :) I have no problem in showing it all, but I do have a lot of classes

Update

Go in with the debugger it gets to this

Font.cpp
const Texture& Font::getTexture(unsigned int characterSize) const
{
    return m_pages[characterSize].texture;
}
 

characterSize = 24, still not 100% sure on what is causing this yet
« Last Edit: October 09, 2014, 10:15:39 pm by Canvas »

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Vector of custom class, how to populate?
« Reply #3 on: October 09, 2014, 10:49:51 pm »
It's been a while since I used containers of Text/Font so it's not obvious to me exactly what the problem is, but I'm sticking to my original guess that your TextObject's font member breaks when it gets moved around by the container it's in, since that's where the crash is.

As a simple test, try using a std::list instead of a std::vector and see if you still get this.  A list happens to be a "stable" or "node-based" container, meaning once you insert something it doesn't get secretly moved around later.  (note that std::vector is still flat out better for the vast majority of uses; I'm suggesting this solely as a test, not as a workaround for the bug)

If you need additional help, you should try to reduce your code to an SSCCE so it's possible for us to do more than just guess.
« Last Edit: October 09, 2014, 10:51:41 pm by Ixrec »

Canvas

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Re: Vector of custom class, how to populate?
« Reply #4 on: October 09, 2014, 11:11:58 pm »
I will give that a go tomorrow and get back in touch with you Ixrec, I will try to provide cleaner code but an easier way "maybe" is you can download my game here http://www.canvascode.co.uk/Files/SpaceDestroyer.rar. All of my code is inside of that :)

Update

If I was to do a list, how would I set up my TextObjects?

TextObject textObject;
        TextObjects.push_back(textObject);
        TextObjects.push_back(textObject);
        TextObjects.at(0).Setup(200, 100, "Space Destroyer", 32, _fontLoader.Fonts[Main_Font]);
        TextObjects.at(0).SetRotationAnimation(-12, 12, 0.1);
        TextObjects.at(1).Setup(200, 350, "High score : " + std::to_string(score) , 32, _fontLoader.Fonts[Main_Font]);
        TextObjects.at(1).CentreText();

I can't use .at anymore nore


Update

Just quickly Ixrec how would you draw the font? Pass the sf::Font in when the text is to be drawn?
« Last Edit: October 09, 2014, 11:26:45 pm by Canvas »

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Vector of custom class, how to populate?
« Reply #5 on: October 09, 2014, 11:30:00 pm »
For things like "how do I use a std::list?" you should immediately consult a reference like http://www.cplusplus.com/reference/list/list/.  There's really no need to ask for someone's help with that unless you don't know C++ well enough to understand references for it (which would be a totally different problem).

But that was just meant as a test you could do in a minute or so; if you find it non-trivial to switch from one container to another then don't waste time on it.

Canvas

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Re: Vector of custom class, how to populate?
« Reply #6 on: October 09, 2014, 11:40:33 pm »
I started to convert stuff to a list but I had a different Idea, you stated "It's been a while since I used containers of Text/Font so it's not obvious to me exactly what the problem is," so I thought why don't I stop passing in my sf::Font to each TextObject and just pass a font into the DrawTextObjects method, so now I pass in a sf::Font reference to my DrawTextObjects and now it seems to work using this code which is what I wanted :)

TextObjects.push_back(TextObject());
        TextObjects.push_back(TextObject());
        TextObjects.at(0).Setup(200, 350, "Score : " + std::to_string(Score), 24);
        TextObjects.at(0).CentreText();
        TextObjects.at(1).Setup(200, 100, "Game Over", 48);
        TextObjects.at(1).SetRotationAnimation(-12, 12, 0.1);
       
        if (highScore == true)
        {
                TextObjects.push_back(TextObject());
                TextObjects.at(2).Setup(200, 300, "New high score!", 24);
                TextObjects.at(2).CentreText();
        }

Cheers for the help Ixrec