   Best way to give access to players / enemies (design issue) [SOLVED]
  Hey everyone, I've been quite frequent on this forum lately :)  I'm making a sidescroller and I'm wondering what the best approach is for my problem.  I have my player(s)/Enemies in a stl container (players is in a vector and enemies is in a list), when I allow the player to attack (or vice-versa) I need to check for collisions between them.  So I am basically just doing a axis-bound check with AABB's.  However I'm not sure of the best approach.As of right now I'm doing something like this... void Enemy::update(std::vector<Player> pls){float h,w;for(std::vector<Player>::iterator plList = pls.begin(); plList != pls.end(); plList++){h = plList->getPosX() + plList->getWidth();w = plList->getPosY() + plList->getHeight();if( checkForCollision(plList->getPosX(), plList->getPosY(), w, h) ){health -= plList->getDamageAmount();}}}However something just seems wrong with my approach.  I'm not really sure what it is.  I just don't like passing a vector of players to the enemy.  The place that the vector of players is in my level class.  And so I thought I could have a method that gets the vector of players.  But I dunno.How does everyone else get data on their players for their enemies, or vice-versa?  Did I just design my code structure poorly or something else?I've got the following classes:Level (contains a vector of players and a list of enemies)EntityPlayer -> Inherits from EntityEnemy -> Inherits from EntityThanks :)[Edited by - -justin- on June 3, 2006 2:36:07 PM]
  Since you have a Level class, you can just add to the Entity class a member variable of type *Level(or a smart pointer) that stores the level each entity is "contained" on. Then each entity can access the level it is in, and consequently all other entities with something like enemy.Level->players.Alternatively, you can have a Level::Update() method that will "collide" the entities, and for every collision have it call a "bool Entity::CheckCollision(Entity &e)" method that checks the collision between an entity an only one other entity.   ;  Thanks I feel really really stupid now.  Good job :DThis should solve my problem for now...   ;  Since I'm also dealing with this right now, I might as well give a more general solution if you're interested. Get prepared, because it's going to be big.In the example, we have a level filled with players,enemies and rockets. We don't want to "collide" each one of them with every other one. Also, we want to handle each type of collision(player-player,player-monster,etc...) differently. Rockets don't harm players, and they don't collide with other rockets. So, we want to collide:1)Players to players2)Enemies to enemies3)Enemies to players4)Rockets to enemiesSo, these are our basic classes:include "stdafx.h"#include <vector>#include <string>#include <iostream>using namespace std;class Entity{public:string name;Entity(string s){name=s;}};class Enemy;//forward declerationclass Rocket;//forward declerationclass Player:public Entity{public:Player(string s):Entity(s){}void Collide(Player *o){if (true)//collision detection code here...cout<<"Player-Player: "<<name<<" to "<<o->name<<endl;}};class Enemy:public Entity{public:Enemy(string s):Entity(s){}void Collide(Enemy *o){if (true)//collision detection code here...cout<<"Enemy-Enemy: "<<name<<" to "<<o->name<<endl;}void Collide(Player *o){if (true)//collision detection code here...cout<<"Enemy-Player: "<<name<<" to "<<o->name<<endl;}};class Rocket:public Entity{public:Rocket(string s):Entity(s){}void Collide(Rocket *o){if (true)//collision detection code here...cout<<"Rocket-Rocket: "<<name<<" to "<<o->name<<endl;}void Collide(Player *o){if (true)//collision detection code here...cout<<"Rocket-Player: "<<name<<" to "<<o->name<<endl;}void Collide(Enemy *o){if (true)//collision detection code here...cout<<"Rocket-Enemy: "<<name<<" to "<<o->name<<endl;}};Basically, each time you add a class you add also member functions that handle collision with itself and all previous classes. Notice that we do have functions that handle,say, collisions between rockets even though I said earlier that we don't need them in this example. That's because we might decide later in development that we do want to handle those. Also, notice that we have Rocket::Colide(Player) but not Player::Colide(Rocket). Assuming those are interchangable, this will not be a problem.We then introduce the concept of "collider". It's the object with the job to "collide" entities between them. First, the abstract class Collider:class Collider{public:virtual void Collide()=0;};Derived from that, there's SingleCollider. It contains a pointer to a vector(or list) of entities of the same type. Its job is to collide every entity in the vector with every other entity in the vector only once. This will be used when we want to collide players with player,enemies with enemies,...template <class T> class SingleCollider:public Collider{public:std::vector<T> *entities;SingleCollider(vector<T> *v){entities=v;}virtual void Collide(){for (int i=0;i<(*entities).size();++i)for (int j=i+1;j<(*entities).size();++j){(*entities).Collide(&(*entities)[j]);}}};DualCollider contains 2 vectors of objects. All objects in the same vector have the same type, but the 2 vectors may have different types of objects. In fact, that is its job: It collides all entities in the first vector with all entities in the second vector. We'll use it if we want to collide all bullets to all enemies or all enemies to all players.template <class T1,class T2> class DualCollider:public Collider{public:std::vector<T1> *entities_1;std::vector<T2> *entities_2;DualCollider(vector<T1> *v1,vector<T2> *v2){entities_1=v1;entities_2=v2;}virtual void Collide(){for (int i=0;i<(*entities_1).size();++i)for (int j=0;j<(*entities_2).size();++j){(*entities_1).Collide(&(*entities_2)[j]);}}};Now, our Level class. The code is pretty self-explanatory:class Level{public:std::vector<Player> players;std::vector<Enemy> enemies;std::vector<Rocket> rockets;std::vector<Collider*> colliders;public:Level(){//Setup our colliderscolliders.push_back(new SingleCollider<Player>(&players));//Players to playerscolliders.push_back(new SingleCollider<Enemy>(&enemies));//Enemies to enemiescolliders.push_back(new DualCollider<Enemy,Player>(&enemies,&players));//Enemies to playerscolliders.push_back(new DualCollider<Rocket,Enemy>(&rockets,&enemies));//Rockets to enemies}void UpdateCollisions(){for (int i=0;i<colliders.size();++i) colliders->Collide();}void Update(){//do other stuff here...UpdateCollisions();//and here...}};Now, a little test. I add some objects of each type and see how they collide. For now, the collision test is always true, but you can go in the :Collide() methods and change the "if(true)" line to the collision detection code.int _tmain(int argc, _TCHAR* argv[]){Level level1;level1.players.push_back(Player("mikeman"));level1.players.push_back(Player("justin"));level1.enemies.push_back(Enemy("ogre"));level1.enemies.push_back(Enemy("demon"));level1.enemies.push_back(Enemy("strogg"));level1.rockets.push_back(Rocket("Rocket1"));level1.rockets.push_back(Rocket("Rocket2"));level1.rockets.push_back(Rocket("Rocket3"));level1.Update();return 0;}Notice that it's now very easy to make changes. If you go to the contructor Level() and just add:colliders.push_back(new DualCollider<Rocket,Enemy>(&rockets,&players));//Rockets to players...you'll have rockets affecting players too.   