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

Author Topic: Deleting Sprites in a vector!?STUCK  (Read 4870 times)

0 Members and 1 Guest are viewing this topic.

PopaF3lla010

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Deleting Sprites in a vector!?STUCK
« on: January 29, 2014, 05:28:16 pm »
Hello SFML community,

I'm using SFML 2.1 with xcode 5 on my macbook air and I am somewhat new to SFML & C++(I have a couple of months under my belt).  I am in need of some help when it comes to Sprites & memory management (EXAMPLE: removing bullets when they go off screen, etc). I am creating a platform game and I have been stuck for weeks trying to figure this out. I have looked on a good amount of forums regarding this issue and I've come across examples where erase(it) being used inside of a for loop using an iterator. I've tried this but it does not work for me.

I would like to know how to clear out a vector that contains Sprites (or class objects w/ Sprites) using an iterator. And I would like these Sprites to be cleared out based on a boolean value. Which ever way I try to implement this I get an BAD_ACCESS error or the program crashes after the Sprite or object is removed from the vector using erase(). I have tried ever way I can think of but nothing works.

Instead of posting my game which contains hundreds of lines of code I wrote a simpler code, please examine it and help me understand what I am doing wrong. :(


#include <SFML/Graphics.hpp>
//#include "ResourcePath.hpp"
#include <iostream>
#include <vector>





int main()
{

    bool is_Alive;
    is_Alive = true;
    sf::Sprite* Sprite;
    Sprite = new sf::Sprite;

    std::vector<sf::Sprite> SpriteVector;
    typedef std::vector<sf::Sprite>::iterator iter;

    //loading projectile image
    sf::Texture* projectileImage;
    projectileImage = new sf::Texture;
    projectileImage->loadFromFile("fireball.png");

    Sprite->setTexture(*projectileImage);


    //Creating game window
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML Game");

    //set famerate to 60 FPS
    window.setFramerateLimit(60);

    window.setKeyRepeatEnabled(false);

    sf::Event event;

    float moveSpeed = 0;

    //variable that keeps game loop running
    bool play = true;
    //Game Loop
    while (play == true)
    {

        //Events

        while (window.pollEvent(event))
        {

            if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space)
            {
                SpriteVector.push_back(*Sprite);
            }




            if (event.type == sf::Event::Closed)
           {

           }


       }

        //LOGIC-----------------------------------------------------------------------------------------------------

        std::cout << "SpriteVector is..." << SpriteVector.size() << "\n";

        for (iter it = SpriteVector.begin(); it != SpriteVector.end(); it++)
        {
            if ((it)->getPosition().y <= 600)
        {
        (it)->move(5, 5);
        }
        }

        //RENDERING
        window.clear();
        for (iter it = SpriteVector.begin(); it != SpriteVector.end(); it++)
        {
        if ((it)->getPosition().y <= 600)
        {
         window.draw(*it);
        }
        if ((it)->getPosition().y >= 601)
        {
         SpriteVector.erase(it);
         std::cout << "Erasing..." << (&it) << "Container size..." << SpriteVector.size() << "\n";
        }
        }
        window.display();
    }

    //Clean Up
    window.close();
    return 0;
}

 
« Last Edit: January 29, 2014, 05:39:02 pm by PopaF3lla010 »

Azaral

  • Full Member
  • ***
  • Posts: 110
    • View Profile
Re: Deleting Sprites in a vector!?STUCK
« Reply #1 on: January 29, 2014, 05:49:08 pm »
First, don't use new and delete. Instead, use smart pointers. Then, you do not have to worry about ever using delete.

Second, this is wrong for how you have it.
SpriteVector.erase(it);
 

For what you have it should be something like
 delete SpriteVector (*it);
 (*it) = nullptr; //or = NULL
//or something similar to this, iterator access is something i dont use much so i can never quite remember how to use them
 

Third, why are you doing this to begin with?
Instead, you should not use pointers for these operations. Just creating an instance will suffice.

Example

Instead of
sf::Sprite* Sprite;
Sprite = new sf::Sprite;
....

sf::Texture* projectileImage;
projectileImage = new sf::Texture;
projectileImage->loadFromFile("fireball.png");
 

This can be made into

sf::Texture projectileImage("fireball.png");
sf::Sprite projectileSprite( projectileImage );

 

Also, instead of removing dead sprites (in this case projectiles no longer needed). Have a bool that says if it is active or not. Whenever you parse the projectile vector you can just check to see if it is active, and skip it if it is not. Then, when you need to make a new projectile, just find an inactive one and set it's variables to what you want the new one to be and activate it.

This is faster than deleting and pushing on the vector. Every time you delete something in a vector, the vector has to recopy everything that came after the one you deleted. So if you have 10 elements, and you delete the 3, it has to recopy 4-10. When you add a new one, then you have to make a copy, and in some cases the vector will grab a bunch more memory for later use. Instead, you should only make a new projectile if all your previous projectiles are still active.

Example

Instead of this...

for (iter it = SpriteVector.begin(); it != SpriteVector.end(); it++)
        {
            if ((it)->getPosition().y <= 600)
        {
        (it)->move(5, 5);
        }
        }

        //RENDERING
        window.clear();
        for (iter it = SpriteVector.begin(); it != SpriteVector.end(); it++)
        {
        if ((it)->getPosition().y <= 600)
        {
         window.draw(*it);
        }
        if ((it)->getPosition().y >= 601)
        {
         SpriteVector.erase(it);
         std::cout << "Erasing..." << (&it) << "Container size..." << SpriteVector.size() << "\n";
        }
        }
        window.display();
 

I would do this...
//projectiles is a vector of projectiles
//projectile is a class that has a sf::Vector2f position, sf::Sprite sprite, and a bool isActive.
for(unsigned int i = 0; i < projectiles.size(); i++) //personal preference here. I prefer index access vs iterator access
{
      if( projectiles[i].isActive  )
     {
           projectiles[i].move(5,5);
     }

     if( projectiles[i].getPosition().y > 600 )
     {
            projectiles[i].isActive = false;
     }
}

window.clear();

for(unsigned int i = 0; i < projectiles.size(); i++)
{
      if( projectiles[i].isActive )
      {
            window.draw( projectiles[i].sprite );
      }
}

window.display();
« Last Edit: January 29, 2014, 06:05:58 pm by Azaral »

PopaF3lla010

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Re: Deleting Sprites in a vector!?STUCK
« Reply #2 on: January 29, 2014, 06:31:26 pm »
Thanks for the reply! Having a container with objects already in it and only adding to the container if all the objects are being used is the way to go here, smh I never thought of that!

I was using pointers just to try to implement the code a different way to see if it worked but your right they are not needed here.

Now, let say I want to reset these vectors to their original size once a new level starts, what would be the correct way so that I do not get a BAD_ACCESS error? What way do you use to delete items in a vector?
« Last Edit: January 29, 2014, 06:42:40 pm by PopaF3lla010 »

Azaral

  • Full Member
  • ***
  • Posts: 110
    • View Profile
Re: Deleting Sprites in a vector!?STUCK
« Reply #3 on: January 29, 2014, 06:40:27 pm »
Well the error was a result of what you were doing.

To reset a vector just call it's clear() function. clear() pretty much gets rid of everything in the vector.  cplusplus.com has all the references you need to the std c++ stuff.

PopaF3lla010

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Re: Deleting Sprites in a vector!?STUCK
« Reply #4 on: January 29, 2014, 06:46:08 pm »
Ive tired clear() and I get the same error. Do I need to stop iterating through the vector before I can call clear/erase/ or delete?

Azaral

  • Full Member
  • ***
  • Posts: 110
    • View Profile
Re: Deleting Sprites in a vector!?STUCK
« Reply #5 on: January 29, 2014, 06:55:38 pm »
When are you calling clear and what is your vector storing? Also, what line is causing the BAD_ACCESS error?
« Last Edit: January 29, 2014, 06:58:47 pm by Azaral »

PopaF3lla010

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • Email
Re: Deleting Sprites in a vector!?STUCK
« Reply #6 on: January 29, 2014, 07:56:40 pm »
Thanks Azaral I finally got it working using your index method. Sprite and texture are no longer pointers. I guess the iterator method is just not for me.


 for (unsigned int i = 0; i < SpriteVector.size(); i++)
        {
            if (SpriteVector[i].getPosition().y <= 600)
        {
        SpriteVector[i].move(5, 5);
        }
        }

        //RENDERING
        window.clear();
        for (unsigned int i = 0; i < SpriteVector.size(); i++)
        {
        if (SpriteVector[i].getPosition().y <= 600)
        {
         window.draw(SpriteVector[i]);
        }
        else if (SpriteVector[i].getPosition().y >= 601)
        {
         SpriteVector.erase(SpriteVector.begin() + i); //this succesfully removes the object from the vector
         std::cout << "Container size..." << SpriteVector.size() << "\n";
        }
        }

 

Thanks again Azaral

Azaral

  • Full Member
  • ***
  • Posts: 110
    • View Profile
Re: Deleting Sprites in a vector!?STUCK
« Reply #7 on: January 29, 2014, 09:20:05 pm »
Glad you got your problem sorted out.