About Store Forum Documentation Contact



Post Reply 
Best way to manage pointers
Author Message
Ozmodian Offline
Member

Post: #1
Best way to manage pointers
Hi All,

I am working on a new project and 1 thing has become clear to me, I don't think i know how best to manage pointers. In the scenario below, I will explain the 2 approaches i have taken but I know there is a better way.

Simple Scenario (pseudocode):
Memc<bullets>
Memc<enemies>
Memc<shooters>

So Shooters shoot bullets at enemies (the bullets follow the enemy until they hit). Simple.

I want to know on a bullet who shot it and where it is going. Again simple.

1) I have tried storing an enemies* reference in bullets but as you are adding and removing bullets, those memory addresses may change. I know you can use a memx but i feel that would leave a ton of holes and take up way too much memory. Maybe not, that is why i am asking.

I can't store an enemies& because i get a compilation error. Am i doing something wrong?

error C2758: 'Bullet::shooter' : must be initialized in constructor base/member initializer list

2) The solution that does work is assigning a simple uint ID to each bullet, shooter and enemy. so on bullet i store the ID of the shooter and enemy. and use a binary search (which is pretty quick) each frame to find where the enemy currently is and adjust course. This works and i have tried it with a fairly large number of enemies and bullets and not seen any slowdown, it just seems wastful.

So long story short, what is the correct way to manage pointers?
02-21-2015 05:35 PM
Find all posts by this user Quote this message in a reply
Tottel Offline
Member

Post: #2
RE: Best way to manage pointers
I'm a bit confused by some things:

1. Small thing, just making sure: Your pseudo-code is Memc<Bullet>, Memc<Enemy>, Memc<Shooter> right? Memory containers storing single objects.

2. You mean you store a reference to the container with all enemies in every bullet? I'm not a big fan of globals, but honestly, making all containers global would help a lot. Just like EE manages the world objects.

So yeah, I guess that would be my solution: Make it global. pfft

EDIT: Also, can you show how you try to store your enemies&?
(This post was last modified: 02-21-2015 07:37 PM by Tottel.)
02-21-2015 07:35 PM
Find all posts by this user Quote this message in a reply
Rubeus Offline
Member

Post: #3
RE: Best way to manage pointers
You could make the ID the index in the container; if you have multiple types that shoot said bullet, store the type(which container) and the ID/index of the shooter. This is the method I use.

In your example, just make sure all bullets fired by the shooter have expired and been removed before removing the shooter from the container. I use time limits.
(This post was last modified: 02-21-2015 10:17 PM by Rubeus.)
02-21-2015 10:15 PM
Find all posts by this user Quote this message in a reply
georgatos7 Offline
Member

Post: #4
RE: Best way to manage pointers
If i understand the problem, maybe this will do:

Code:
bool Init()
{
    //.....  

   enemyContainer.New();
   bulletContainer.New();
  
   //.....
   return true;
}

Memc<enemy> enemyContainer;
Memc<bullet> bulletContainer;

class enemy
{
   int hp = 10;
}

class bullet
{  
   enemy *targetEnemy;
  
   void setTarget(enemy *myEnemy)
   {
      targetEnemy = myEnemy;
   }
  
   enemy *getTarget()
   {
      return targetEnemy;
   }
}

int globalPrint = 0;

void Draw()
{
   //.....
  
   if(Kb.bp(KB_K))
   {
      bulletContainer[0].setTarget(&enemyContainer[0]);
    
      //THIS GETS THE TARGET'S HP BUT IT ACCESSES THE DATA FROM THE BULLET OBJECT
      globalPrint = bulletContainer[0].getTarget().hp;  
      
   }
   D.text(0, 0, S+"HP: "+globalPrint);

   //.....
}

Don't know if this is an awkward way to access this. I think it's ok.

EDIT: Oh havent tried changing the address to see where that thing is pointing to since it sounds like case 1. Will do tommorow when im on pc.

EDIT2: Also binary needs something like 20 searches max to find what you want out of a million entries so it seems like a good solution but it might feel a bit sloppy, i would be interested also in a more optimized solution. What rubeus said sounds like a good one.
(This post was last modified: 02-22-2015 01:36 AM by georgatos7.)
02-21-2015 11:00 PM
Find all posts by this user Quote this message in a reply
Esenthel Offline
Administrator

Post: #5
RE: Best way to manage pointers
Hi!

The best way is to use Memx containers smile

If you're using your own object classes not based on Game.Obj, then let them have a unique ID:

Code:
class OBJ
{
  ~OBJ() {_id.zero     ();}
   OBJ() {_id.randomize();}

       C UID  & id ()C {return _id ;}

remember to save/load the ID save load methods.

With this ID you can now use the engine's Reference class:
Code:
/******************************************************************************/
T1(TYPE) struct Reference // Reference, this is a pointer to an object which may be deleted but its memory is still valid and possibly occupied by another object of similar class
{
   // get / set
   void  clear     ()  {_object=NULL; _object_id.zero ();            } // clear reference to NULL
   Bool  empty     ()C {return       !_object_id.valid();            } // perform a check if the reference is empty (doesn't want to point to any object at all)
   Bool  valid     ()C {return  _object && _object->id()==_object_id;} // perform a check if the reference is valid (points to an existing object with matching id)
   TYPE* validPtr  ()C {return   valid() ? _object : NULL           ;} // return  a pointer   to object that is valid
C UID & objectID  ()C {return  _object_id                          ;} // return  a              object ID
   TYPE& operator()()C {return *_object                             ;} // return  a reference to object, usage of this method must be preceded by performing a reference validation using 'valid' method
   TYPE* operator->()C {return  _object                             ;} // return  a reference to object, usage of this method must be preceded by performing a reference validation using 'valid' method

   // compare
   T1(OBJECT)   Bool operator==(OBJECT           *object)C {return T._object==     object && (object ? T._object_id==     object->id() : true );} // if reference points to 'object'
   T1(OBJECT)   Bool operator==(OBJECT           &object)C {return T._object==    &object &&           T._object_id==     object .id()         ;} // if reference points to 'object'
   T1(TYPE2 )   Bool operator==(Reference<TYPE2> &ref   )C {return T._object==ref._object &&           T._object_id==ref._object_id            ;} // if references are equal

   T1(OBJECT)   Bool operator!=(OBJECT           *object)C {return T._object!=     object || (object ? T._object_id!=     object->id() : false);} // if reference doesn't point to 'object'
   T1(OBJECT)   Bool operator!=(OBJECT           &object)C {return T._object!=    &object ||           T._object_id!=     object .id()         ;} // if reference doesn't point to 'object'
   T1(TYPE2 )   Bool operator!=(Reference<TYPE2> &ref   )C {return T._object!=ref._object ||           T._object_id!=ref._object_id            ;} // if references are not equal

   // io
   void save(File &f)C; // save 'object_id'
   Bool load(File &f) ; // load 'object_id' and set 'object' pointer to NULL, actual linking pointer to the object should be performed later using 'link' method

   // link
   void link(); // link the reference with existing World object, this method should be called only inside 'Game::Obj::linkReferences' or 'Game::World.link_references'

   // construct
   Reference(         ) {T._object=NULL;                                    T._object_id.zero();}
   Reference(TYPE &obj) {T._object=&obj;        T._object_id=obj .id();                         }
   Reference(TYPE *obj) {T._object= obj; if(obj)T._object_id=obj->id();else T._object_id.zero();}

private:
   TYPE *_object;
   UID   _object_id;
};
/******************************************************************************/
Thanks to Reference you can even try referencing the game object even after it's gone!
It's valid and validPtr methods will just return false and NULL.

This is the best way!

Do not use Memc because the memory addresses / indexes may change.

This approach is done across the engine, and I'm using it for my own projects.
02-22-2015 10:22 PM
Find all posts by this user Quote this message in a reply
Ozmodian Offline
Member

Post: #6
RE: Best way to manage pointers
Hi Esenthel,

I will try the Reference class, it looks interesting. Thanks a lot for pointing it out to me.
02-23-2015 01:10 AM
Find all posts by this user Quote this message in a reply
Ozmodian Offline
Member

Post: #7
RE: Best way to manage pointers
Hi Esenthel,

Ok, so i started changing all my references to use Reference and have 2 critical things i need to understand.

1) Do i have to use a Memx with Reference? For instance if I pass something like bullet.init(Shooters[i],Enemies[i]) and in init i have init(Shooter &s, Enemy &e) and do T.shooterReference = s; T.enemyReference = e. If a memc is used and the memory address changes, will the Reference pointer still be valid?

2) For the Save/Load functions, load says "load 'object_id' and set 'object' pointer to NULL, actual linking pointer to the object should be performed later using 'link' method" but link says "this method should be called only inside 'Game::Obj::linkReferences' or 'Game::World.link_references'". Since i don't have a Game::Obj or Game::World will this even work?
(This post was last modified: 02-26-2015 04:18 AM by Ozmodian.)
02-26-2015 04:17 AM
Find all posts by this user Quote this message in a reply
Esenthel Offline
Administrator

Post: #8
RE: Best way to manage pointers
1) You need Memx, as Reference stores pointer+ID (can't do Memc)
2) for your own classes, ignore the 'link' method and use your own, it's about finding an object with desired ID, and then assigning it again to that reference

something like that:
Code:
Reference<Obj>    target;
void linkReferences()
   {
      target=FindObj(target.objectID());
   }
02-26-2015 04:44 AM
Find all posts by this user Quote this message in a reply
Ozmodian Offline
Member

Post: #9
RE: Best way to manage pointers
I figured those were the answers. Thanks for verifying. Glad that i understood it!

As always, thanks for taking the time!
02-26-2015 06:10 AM
Find all posts by this user Quote this message in a reply
Post Reply