removing sprite from memory

Started by
13 comments, last by PezMutanT 15 years, 12 months ago
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! ;)
Advertisement
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?
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
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!
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?
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.

[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
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!! ;)
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! ;)
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?
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! ;)
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;    }}

This topic is closed to new replies.

Advertisement