2014-08-29 3 views
1

Я довольно зеленый относительно векторов, и это мой первый раз, фактически используя их для проверки на столкновение. Это для моего проекта, и я в тупике о том, как реализовать столкновение. Текущие коды проверки и ответа на столкновение, похоже, кажутся ... плохим дизайном.Vector Collision

Это мой код:

for(auto it = ArrayofEntities.begin(); it != ArrayofEntities.end(); it++) 
    { 
     CEntity * go = (*it); 

     for(auto i = ArrayofEntities.begin(); i != ArrayofEntities.end();) 
     { 
      //Collision for entities. Collision Event returns the iterator after an element is erased. 
      CEntity * other = (*i); 
      if (go != other) 
      { 
       if (!theCollision.CheckCollision(go, other, false, false, false, false)) //Checks if it has collided go with other 
       { 
        i = go->CollisionEvent(*other, ArrayofEntities); //Run collision code, setting i to the iterator which is returned. 

        //break; 
       } 
       else 
       { 
        i++; 
       } 
      } 
      else 
      { 
       i++; 
      } 
     } 
} 

CEntity является базовым классом для всех объектов.

My CheckCollision возвращает true или false при столкновении, а мое событие столкновения запускает столкновение и возвращает итератор (потому что мне может потребоваться уничтожить объекты в векторе).

Мое событие столкновения ниже

vector<CEntity*>::iterator bullet::CollisionEvent(CEntity &other, vector<CEntity*> & theArray) 
{ 
case ZOMBIE: 
    { 
     other.hp -= power * 0.01;//Effect 


     int Counter, index, bulletindex; 
     auto it = theArray.begin(); 
     //Find the bullet and the other in the array. 
     for (it = theArray.begin(), Counter = 0; it != theArray.end();it++, Counter++) 
     { 
      CEntity *go = NULL; 
      go = (*it); 
      if (go == &other) 
      { 
       index = Counter; 
      } 
      if(go->ID == BULLET && go->GetX() == GetX() && go->GetY() == GetY()) 
      { 
       bulletindex = Counter; 
      } 
     } 

     this->~bullet();//Delete the bullet 
     theArray.erase(theArray.begin() + bulletindex); 


     if(other.hp <= 0) 
     { 
      other.~CEntity(); 
      it = theArray.erase(theArray.begin() + index); //delete from array. 


      return it; 
     } 

     it = theArray.begin() + index; 
     return it; 

    } 

}

Я в основном сделал это как то, как я хотел бы сделать массив. Просто проверьте это на себя. Ошибка, которую он дает, это «Векторный Итератор не Incrementable», в первом цикле после события столкновения.

Итак, мой вопрос: 1) Что я делаю неправильно? 2) Я думаю, что это так, как проверка массивов неправильно?

Это мой школьный проект, поэтому я полностью контролирую коды.

Я бы предпочел бы быстро исправить полное переписывание всех коллизионных кодов, но если это действительно сведено к делу, я переписал свои коды.

+0

Вы аннулируете свои итераторы вашей коллекции объектов, если это «стирание» когда-либо срабатывает. И, откровенно говоря, что-то вроде этого: 'this-> ~ bullet()' имеет * horrid * запах. Аналогично с 'other. ~ CEntity()'. *Зачем* ? – WhozCraig

+0

У него ужасный запах, потому что он ужасный. Мне нужно некоторое руководство, как это сделать. Я думаю, что я попал в ловушку, пытаясь изо всех сил сделать эту работу. – user2418426

+0

Это все динамические объекты, не так ли? как в содержании все выходы сущности? Возможно, вектор умных указателей может быть мудрым, и, глядя на него, я думаю, что моя оценка ваших итераторов может быть * частично преждевременной. Последнее беспокоит меня, но вы, похоже, знаете, что 'erase()' возвращает следующий итератор, поэтому нет причин увеличивать его для правильного перечисления. И оценка недействительных итераторов определенно по-прежнему актуальна для самого внешнего цикла итерации. – WhozCraig

ответ

2

Если вы посмотрите на реализацию std::remove_if, вы увидите, что они решили проблему аннулирования итератора по-другому. вместо стирания элементов они перемещают их до конца массива.

Это может быть самым простым решением для вас. Сохраните итератор, который указывает после последнего «живого» entirty. Он начинается с .end, но по мере того, как пули попадают в вещи, вы меняете сущности на заднюю часть вашего диапазона и уменьшаете этот последний итератор.

Затем, когда вы закончите цикл по вашему массиву, вы очищаете одним вызовом до .erase.

И да, вы должны использовать либо std::unique_ptr<CEntity>, либо std::shared_ptr<CEntity> в коллекции. Таким образом, .erase не просто стирает указатель, но и указывает на объект.

+0

+1 'std :: remove_if', безусловно, будет логичным путем для этого, поскольку он будет перетаскивать все условия соответствия в конец последовательности, просеивать несоответствия вниз и давать чистое место, из которого можно уничтожить с этим единственным стиранием и очисткой всех уничтоженных сущностей. Отличное предложение. – WhozCraig

+0

Очень четкий ответ. благодаря – user2418426