Sign in to follow this  
PezMutanT

removing sprite from memory

Recommended Posts

Hi everyone! In order to represent sprites in my 2D game I've made a class structure like this: -Sprite ---Character ---Enemy ---Fire I have a class called D3DEngine, where I store Direct3D device, Direct3D-related stuff and a vector of Sprite pointers with all the sprites in the screen at the moment. But also, in the MAIN file, I have different pointers to Sprites. For example, I have a pointer to the main character and I have a vector with pointers to the enemies, too. I think this is necessary, because I want to check in the main loop things like "if every enemy is dead then advance stage". When I have to remove a sprite (e.g. an enemy is killed), I "delete" it from memory and remove it from the first vector I talked about, that's the one which stores a pointer for every sprite on scree. But when I try to remove it at the main file from the other vector (the one in the main file with all the enemies), the pointer is pointing to an unitialized sprite because it has been deleted previously, so I can't check properly if the sprite has to be killed (I have a flag for that). The thing is I think I need both vectors of sprites: the one in the D3DEngine class that represents every sprite on screen and is used to render the scene every frame, and on the other hand, the vector in the main file that represents every enemy, so I can check when all enemies are killed in order to advance stage. Is this a correct way of thinking? I am reading about references (instead of pointers) and I thought maybe I should implement one of the vectors as a vector of references (not pointers), so when I remove an sprite from one of them, the changes affect to the other one. I don't know if it's possible with references, but is there any way to do this? I hope I made it clear. Well, thanks a lot, people! ;)

Share this post


Link to post
Share on other sites
I suggest you make a struct for every sprite, this would contain a pointer to the sprite and a bool if it is dead or not, and other sprite relevant information.

Now you can fill the vector with this struct (or allocate it and use pointers) and remove the sprite and still keep the dead-or-not boolean.

BTW: why would you remove sprites if it's dead? Won't it respawn?

Share this post


Link to post
Share on other sites
Thanks for the suggestion, Decrius! :)

I remove it another time because in the main loop, when I check if all enemies are dead, I check if the size of the vector of enemies is 0.

Maybe I should try to check same thing with a different if statement, but I don't know how... When a pointer points to something that has been "deleted" (with the delete operator), it's not a NULL pointer, right? I think if I find a way to change that if statement to properly check if all enemies are dead, the problem will be solved.

Thanks you!

Share this post


Link to post
Share on other sites
Quote:
When a pointer points to something that has been "deleted" (with the delete operator), it's not a NULL pointer, right?


It's not NULL, but that shouldn't matter. Once you delete an object through a pointer, then as far as you're concerned, the object no longer exists. Attempting to use the object through the pointer will result in undefined behavior (most likely a crash).

Also, I'm not sure how this is related to your problem. How are you testing to see if a sprite is alive?

Share this post


Link to post
Share on other sites
Quote:
Original post by PezMutanT
Thanks for the suggestion, Decrius! :)

I remove it another time because in the main loop, when I check if all enemies are dead, I check if the size of the vector of enemies is 0.

Maybe I should try to check same thing with a different if statement, but I don't know how... When a pointer points to something that has been "deleted" (with the delete operator), it's not a NULL pointer, right? I think if I find a way to change that if statement to properly check if all enemies are dead, the problem will be solved.

Thanks you!


No, but its best to set a pointer to NULL when you deleted it. You cant reallocate anyways, and it can cause errors if you redelete for instance. NULL pointers are cannot be deleted anymore and you can safely check if its NULL or not.

But you can also loop through the vector, and once you found a enemy that is alive, break the loop and continue the main loop. You can check this with the boolean 'dead'.

You can also erase the structure out of the vector (if the struct has a POINTER to a sprite, and you have an array of pointers to the sprites aswell), this will delete the structure object and not the sprite. Then you can check if the vector has a enemies alive or not easily. Once the game is done you should go through the array of pointes (or vector aswell) and delete each sprite.

struct SpriteStructure
{
sprite *data;
bool dead;

SpriteStructure() : data(NULL), dead(false) {}
};

std::vector<SpriteStructure> spritestructs;
std::vector<sprite *> sprites;

Where 'sprite' contains the data, depends on if its an object or its datastructure to what type you need to use, instead of 'sprite'.

Then you allocate memory and add the pointer to sprites and make a new spritestructs element.

Once the app is done, delete all entries in sprites.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
It's not NULL, but that shouldn't matter. Once you delete an object through a pointer, then as far as you're concerned, the object no longer exists. Attempting to use the object through the pointer will result in undefined behavior (most likely a crash).

Also, I'm not sure how this is related to your problem. How are you testing to see if a sprite is alive?


I'm checking it checking the "IsKilled" boolean property of the object, but I don't access the object with the pointer I deleted (the one in the vector with all the sprites), I do it through the pointer in the vector with all the enemies to see if there's any enemy alive yet (and that pointer is pointing to the same sprite that has been deleted).

The thing is that I should be able to check if there's still any enemy alive from the main loop and that's why I use this second vector with pointers to all enemies. But once I want to delete elements from this vector I can't check the "IsKilled" boolean of the object, because it has already been deleted.

Decrius, I really appreciate your suggestion, but maybe there's a way without having to implement a new struct type. I think I would have to do a lot of changes and my code will be a little messier. Of course, thanks anyway!! ;)

Share this post


Link to post
Share on other sites
Maybe I should have explained it differently.

When a sprite needs to be removed from memory, I "delete" it in the update method where I go through the vector of all sprites, and I delete the ones that have "IsKilled" boolean set to TRUE, and I draw on screen the rest of the sprites.

My problem is how to check that all "enemies" (sprites of the derived class Enemy) in the main loop, so I can go on to another stage of the game.

I'm sorry about my explanations...

Thanks, people! ;)

Share this post


Link to post
Share on other sites
So you want to know when all the enemies are dead?

If so, you can maintain a counter that will be incremented when an enemy is created, and decremented when an enemy is destroyed. When the counter reaches 0, you know that all the enemies are dead.

But I'm still not sure how you are handling sprite deletion. Can you post the relevant snippet of code?

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
So you want to know when all the enemies are dead?

If so, you can maintain a counter that will be incremented when an enemy is created, and decremented when an enemy is destroyed. When the counter reaches 0, you know that all the enemies are dead.

But I'm still not sure how you are handling sprite deletion. Can you post the relevant snippet of code?


The problem with that counter would be that I'd have to modify my D3DEngine class in order to decrease the counter each time I delete a enemy sprite, and that would make my D3DEngine class not reusable in the future. I'd like some way that I can check it in the main loop.

This is my relevant code in the "Render()" function of my D3DEngine class. Basically I go through the vector with all the sprites, if "IsKilled" I delete it, if not I draw it.


for (iter = m_vSprites.begin(); iter != m_vSprites.end(); iter++)
{
(*iter)->Update();

if ((*iter)->IsCollidingWithOthers())
{
CheckCollisionsWith((*iter));
}

if ((*iter)->IsKilled())
{
delete (*iter);
m_vSprites.erase(iter);
iter = m_vSprites.begin();
}
else
{
(*iter)->Draw();
}
}



Hope it helps. Thank you! ;)

Share this post


Link to post
Share on other sites
First I'd like to point out that I don't have a lot of experience with this sort of thing, so you should take everything I say with a grain of salt.

You have an object that is referenced in several containers (I'm using the term reference in a loose way. Basically, anything that can "refer" to an object is a reference for this discussion). Whenever the object is deleted, all references to it need to be removed. There are basically two ways to achieve this:

1) The containers can hold a type of "smart reference" that knows if it is referring to a valid object. Then each time you traverse a container, you check to see if the reference points to a valid object, and if not, you remove the reference.

2) Whenever an object gets deleted, it tells about it to anyone who wants to know, in this case, the containers. The containers, in turn, remove the reference to the object.

Your IsKilled() function is a simple way to implement 1, but as you've noticed, it has it's problems. A more robust implementation can be achieved by using boost's smart pointers, in particular shared_ptr and weak_ptr.

2 is an example of the Observer design pattern, which you can read about here and here (of course, google will provide you with more links).

Sorry for sort of dumping all this information on you. If you have any specific questions, I'll try to explain further.

BTW, your loop doesn't work properly. When an object is deleted, you go back to the beginning of the loop, thus updating some objects more than once. Instead, you can take advantage of the fact that erase() returns an iterator to the next object after the deleted one. Your loop should look something like this:


iter = m_vSprites.begin();
while (iter != m_vSprites.end()) {
if ((*iter)->IsKilled()) {
delete (*iter);
iter = m_vSprites.erase(iter);
} else {
// Do whatever

++it;
}
}


Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
Sorry for sort of dumping all this information on you. If you have any specific questions, I'll try to explain further.


By any chance you have to be sorry, I'm very grateful for this info about the observer pattern and I am going to read about it because I want to learn how to implement it (that's the only way to learn!). I think this observer pattern should be a better approach to what I had in mind. Thanks a lot!

Quote:
Original post by Gage64
BTW, your loop doesn't work properly. When an object is deleted, you go back to the beginning of the loop, thus updating some objects more than once. Instead, you can take advantage of the fact that erase() returns an iterator to the next object after the deleted one.


I returned to the beginning because I was getting errors when deleted an element and this was the only way I could make it work. Thanks a lot for your suggestion, I will try your way, it makes more sense!

Thanks! ;)

Share this post


Link to post
Share on other sites
Quote:
Original post by PezMutanT
Quote:
Original post by Gage64
It's not NULL, but that shouldn't matter. Once you delete an object through a pointer, then as far as you're concerned, the object no longer exists. Attempting to use the object through the pointer will result in undefined behavior (most likely a crash).

Also, I'm not sure how this is related to your problem. How are you testing to see if a sprite is alive?


I'm checking it checking the "IsKilled" boolean property of the object, but I don't access the object with the pointer I deleted (the one in the vector with all the sprites), I do it through the pointer in the vector with all the enemies to see if there's any enemy alive yet (and that pointer is pointing to the same sprite that has been deleted).


Sigh.

'delete' does not have any effect on the pointer it's called upon. It affects the pointed-at thing. "The pointer you deleted" is actually the pointed-at thing you deleted. The pointer in the vector pointed to the same thing as the pointer you used for the delete statement. It now points to garbage, in the same way that the other pointer does, because the pointed-at thing does not exist any more.

Solution: don't delete when you set IsKilled. Just set it. Then have a separate pass that goes through the vector, to delete and remove all the pointers to IsKilled sprites.


void Sprite::update() {
// Among other wonderful things:
if (blarg_im_ded) { IsKilled = true; }
}

// We need a little adaptor function that will delete the pointers as a part of
// the process of checking for dead Sprites:
bool isDeadSprite(Sprite*& s) {
return s->IsKilled() { delete s; return true; }
return false;
}

// Then, assuming we have:
std::vector<Sprite*> allSprites;

// Update everything like:
std::for_each(allSprites.begin(), allSprites.end(), std::mem_fun(&Sprite::update));

// Clean up the corpses like:
allSprites.erase(std::remove_if(allSprites.begin(), allSprites.end(), isDeadSprite), allSprites.end());

Share this post


Link to post
Share on other sites
bool isDeadSprite(Sprite*& s) {
return s->IsKilled() { delete s; return true; }
return false;
}


This syntex looks strange (the second line). Assuming it's not a typo, can you please explain how it works?

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
bool isDeadSprite(Sprite*& s) {
return s->IsKilled() { delete s; return true; }
return false;
}


This syntex looks strange (the second line). Assuming it's not a typo, can you please explain how it works?
I'm guessing that was supposed to be:
if (s->IsKilled()) { delete s; return true; }
Could be wrong though.

Share this post


Link to post
Share on other sites
Thanks for your answers.

I already tried having a function designed only for checking every sprite and removing if it "IsKilled". But I still would have the same problem: I have to delete it in two different vectors (the one with all the sprites and the one in the main file with the enemy sprites), because otherwise I don't know how to check in the main loop if all enemies are dead.

The only thing I could think of is not deleting sprites until the end of the stage, simply "stop drawing" the killed ones, but I think this is an awful way to do it because of the memory wasting. I would like to be able to delete a sprite when it is killed, I think the observer pattern is a better approach to my idea.

Thanks a lot people! ;)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this