Sign in to follow this  
suliman

checking a "dead pointer"

Recommended Posts

hi in my rts, lets say 50 good guys find a bad guy and all start shooting at it. Their "unit * targetUnit" is set to this bad guy. Eventually he dies and he is removed. But all these good guys will then target something that doesn't exist, causing a crash or other unpleasant results. How to check if the pointer no longer points to a instance of the type its supposed to point at? Can I do that at all? To have a victim store a pointer to every one that targets him and at the moment of death clear all those attacker's target seems like overkill. Where do I go? Thanks Suliman

Share this post


Link to post
Share on other sites
I dont think there is a way to test if a pointer is valid or not.
What you could do is some sort of reference counting system. Everytime an unit targets another one, increase a counter for the enemy unit and when they target something else decrease it, so you end up with a counter holding how many units have targeted. Now instead of deleting the unit outright mark it as dead and let the other units find other targets, once the counter is at 0 then delete the unit.

There are other ways you can approach the problem as well :)

Hope that gives some help.

Share this post


Link to post
Share on other sites
Hey,

My personal preference is to have a messaging system so that when the object 'dies', it broadcasts a 'OBJECT_DEAD' message with some attached info, so that the next time that the good guys are about to update, they check and realise that the target's dead. Basically, the same as grekster had, except my system would actively inform every other game class. There's a bunch of other cool stuff that you can use general messages for too.

Just my thoughts,

--CJM

Share this post


Link to post
Share on other sites
I think there is another way , instead of just removing the dying enemy from the list , just remove it , but don't delete it, add it to temp list , and set some flag to dead = true.

Now once the player updates its AI , he checks if the target is dead , if it is the selects other enemy or do something else.

The idea to use temp list , is because you allocate memory , and use it all the time , just by adding removing it to current enemy list. This might be faster then just allocating and deleting memory all the time.

Share this post


Link to post
Share on other sites
Essentially, what you want is some kind of "handle" to the targetted unit. If each object has a unique "object id", and this object id can be used in some kind of table (perhaps a std::map if you're using C++) to get a pointer to the object, then you're good to go. When an object is created, it gets inserted into the table - when it's destroyed, it goes away. When the unit fires, look up the object id it's targetting. If that object doesn't exist, you can use some logic there - either auto-target something else, or simply lose its target.

Share this post


Link to post
Share on other sites
Quote:
Original post by DMINATOR
I think there is another way , instead of just removing the dying enemy from the list , just remove it , but don't delete it, add it to temp list , and set some flag to dead = true.


DMINATOR, a problem I see with this is how long do you keep objects around in the 'temp' list before freeing the memory? If you have thousands of units being created and dying, you will want to release the memory from long-dead units. It could be done, but I think something like an ID that you can look up each tick is a more stable way to go.

Share this post


Link to post
Share on other sites
Quote:
Original post by RDragon1
DMINATOR, a problem I see with this is how long do you keep objects around in the 'temp' list before freeing the memory? If you have thousands of units being created and dying, you will want to release the memory from long-dead units. It could be done, but I think something like an ID that you can look up each tick is a more stable way to go.


I don't release If I want to add new unit to the scene , I just select one from the temp list , override its params (set new health , position , animation) . And put it to the processing list. It is easy fast and the best way I have seen. I am using something similar for my particle engine.

Share this post


Link to post
Share on other sites
This can easily be achieved by storing a pointer-to-a-pointer in your "good guys". Then you simply check for *target being NULL rather than target itself being NULL.
Of course your master pointers will need to be stored somewhere where they wont move, like a plain old array.
It'll work, and it's perhaps more efficient than broadcasting messages.

It doesn't really have to be pointers either. any kind of system using a double-lookup of some kind will work, if you'd rather use indexes.
I'm sure you'll come up with something good enough.

Share this post


Link to post
Share on other sites
hmm i'll use the easiest method that i know of.

since units still are going to be corpses for a while after death, I keep the unit, removes all iterators in "alive-lists" and puts it in a corpse-list.

When the attacker checks next time, it'll see that it's victim is in the corpse list and can just set it's attackUnit pointer to 0, allowing it to pick a new target that isn't already dead.

The units will not be really removed before the corpses are decayed. Works fine for my rts...

Thanks for your help
Suliman

Share this post


Link to post
Share on other sites
Since you might want to eventually have a necromancer unit (ala warcraft3)...

I would have two functions-- killUnit and removeUnit. killUnit , would be the same as if the unit was killed in battle (sets its Alive bool to false). RemoveUnit would actually free the memory, setting its pointer to null.

Share this post


Link to post
Share on other sites
boost's weak_ptr<> is a good way of acheiving this.
You can have an array of smart_ptr<>s as the master list and only keep weak_ptr<>s to thiem in other places. That way you can use the .lock() method of the weak_ptr to find out if it still exists.

Share this post


Link to post
Share on other sites
In my RTS I used a UniqueID for every unit... so if the UniqueId wasn't the same as their target, they assumed it was gone.

Worked flawless... :D

Share this post


Link to post
Share on other sites
Off the top of my head, one way to handle uniqueIds might be as follows:


class IdKeyedThingy {
static map<int, IdKeyedThingy*> registry;
static int nextId;
IdKeyedThingy();

public:
static int create() {
int currentId = nextId;
registry[currentId] = new IdKeyedThingy;
nextId++; // ensure we continue to get unique IDs
return currentId;
}

static void kill(int which) {
delete registry[which];
registry[which] = null;
// if 'which' was invalid, this will insert a "default-constructed
// IdKeyedThingy*" - i.e. null pointer - with that key into the map, then
// delete the null pointer (which is safe), then return a reference to the
// null value and re-write it as null (which all basically has no effect
// but is safe). The net effect is that you build up bogus keys and waste
// some space but it should at least work.
// If that bugs you, "do it properly" with .find(), .insert() etc.
}

static IdKeyedThingy* get(int which) {
return registry[which];
// if invalid or previously killed, a null pointer is returned - but now
// at least it's a *valid* pointer.
}
}

// You could also put the management stuff outside the class, e.g. as globals in
// a namespace, or something.

// Usage example:
Enemy e, e2;
int target = IdKeyedThingy::create();
e.target = target;
e2.target = target;
e.fire(); // where the implementation will ::get() the thingy
// and check for a null pointer.
if (IdKeyedThingy::get(target) && IdKeyedThingy::get(target)->hp <= 0 ) {
IdKeyedThingy::kill(target);
}
e2.fire(); // no problem; can easily determine that it's already dead.



Can be further improved by use of the Null Object pattern, functors for removal (in general, making the class aware of the conditions that trigger a kill() and letting it do the work), and so on.

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