Hi I have a 2D grid of 128x128 sized cells. Each update, if the position of the entity has moved, it is unoccupied from 9 of its surrounding cells and placed into 9 new cells of its new location. The logic works fine with 2 or 3 entities even with overlap they can go about the place unoccupying and occupying cells and updating the grid accordingly. Now when a 3rd or 4th entity passes across the player the program crashes because I am trying to unoccupy an entity from a position in the cell that is not valid.
Note:
- Each cell contains a vector of entity's CStat class containing the stats (Pos, Oldcell, CurrCell, etc)
- When an entity is removed from a vector all entities positioned above the, to-be-erased-one, need to be decremented in their position in cell.
- The cell are accessed in a strange way I know - but it is optimised trust me - as cells 7 0 3 8 1 2 6 5 4 Middle row, Top row then bottom row. It doesn't matter in the long run.
- The error is: visual studio 11\vc\include\vector line 159 - Expression: vector iterator + offset out of range
- The error is: How I am calculating the offset from the position in cell of the entity to be erased. As said this works as test data below proves but crashes upon the unoccupy function at the first cell (7) calculation.
Here are the 2 functions Please can you tell me where I am going wrong in my logic.
// ********************************************************************* //
// Name: OccupySurroundingCollCells //
// Description: //
// ********************************************************************* //
void CCollisionManager::OccupySurroundingCollCells(CStats* pEntityOne)
{
// Find out which cell we are upon and if it is not the same as the last frame's
// tile then save it and occupy cells around the entity
CalculateCellUpon(*pEntityOne->GetWorldPos()->GetPos(), pEntityOne->m_pvCurrCell);
if ((pEntityOne->m_pvCurrCell->iRow != pEntityOne->m_pvOldCell->iRow) ||
(pEntityOne->m_pvCurrCell->iCol != pEntityOne->m_pvOldCell->iCol))
{
// Release and aquisition
UnOccupyLast9Cells(pEntityOne);
Occupy9Cells(pEntityOne);
DebugPrint();
}
} // OccupySurroundingCollCells
// ********************************************************************* //
// Name: Occupy9Cells //
// Description: Place this entity into the relevant tiles as follows //
// 8 1 2 //
// 7 0 3 But programmed as: 7 0 3 8 1 2 6 5 4 //
// 6 5 4 for ease of access //
// ********************************************************************* //
void CCollisionManager::Occupy9Cells(CStats* pEntityOne)
{
stCELLVector2 vCell = *pEntityOne->m_pvCurrCell;
// Precalculate
int a = vCell.iCol - 1; // Left tile (y is col)
int b = vCell.iCol + 1; // Right tile
// MIDDLE ROW
// Cell 7
m_ppCollMap[vCell.iRow][a].m_vecCollisionEntities.push_back(pEntityOne);
pEntityOne->m_iPositionInCell[0] = m_ppCollMap[vCell.iRow][a].m_vecCollisionEntities.size();
// Cell 0
m_ppCollMap[vCell.iRow][vCell.iCol].m_vecCollisionEntities.push_back(pEntityOne);
pEntityOne->m_iPositionInCell[1] = m_ppCollMap[vCell.iRow][vCell.iCol].m_vecCollisionEntities.size();
// Cell 3
m_ppCollMap[vCell.iRow][b].m_vecCollisionEntities.push_back(pEntityOne);
pEntityOne->m_iPositionInCell[2] = m_ppCollMap[vCell.iRow][b].m_vecCollisionEntities.size();
// FIRST ROW
int iRow = vCell.iRow - 1;
// Cell 8
m_ppCollMap[iRow][a].m_vecCollisionEntities.push_back(pEntityOne);
pEntityOne->m_iPositionInCell[3] = m_ppCollMap[iRow][a].m_vecCollisionEntities.size();
// Cell 1
m_ppCollMap[iRow][vCell.iCol].m_vecCollisionEntities.push_back(pEntityOne);
pEntityOne->m_iPositionInCell[4] = m_ppCollMap[iRow][vCell.iCol].m_vecCollisionEntities.size();
// Cell 2
m_ppCollMap[iRow][b].m_vecCollisionEntities.push_back(pEntityOne);
pEntityOne->m_iPositionInCell[5] = m_ppCollMap[iRow][b].m_vecCollisionEntities.size();
// LAST ROW
iRow = vCell.iRow + 1;
// Cell 6
m_ppCollMap[iRow][a].m_vecCollisionEntities.push_back(pEntityOne);
pEntityOne->m_iPositionInCell[6] = m_ppCollMap[iRow][a].m_vecCollisionEntities.size();
// Cell 5
m_ppCollMap[iRow][vCell.iCol].m_vecCollisionEntities.push_back(pEntityOne);
pEntityOne->m_iPositionInCell[7] = m_ppCollMap[iRow][vCell.iCol].m_vecCollisionEntities.size();
// Cell 4
m_ppCollMap[iRow][b].m_vecCollisionEntities.push_back(pEntityOne);
pEntityOne->m_iPositionInCell[8] = m_ppCollMap[iRow][b].m_vecCollisionEntities.size();
// Save
*pEntityOne->m_pvOldCell = *pEntityOne->m_pvCurrCell;
} // Occupy9Cells
// ********************************************************************* //
// Name: UnOccupy9Cells //
// Description: Remove this entity from the relevant tiles. Must be //
// called before Occupy9Cells except the first time. //
// Pos -1 because they are derived from vector::size() //
// where the lowest is 1 not 0. //
// Each cell has a for loop that performs a -1 for each //
// entity's pos above the erased one. //
// Its (begin+PosInCell) is not -1 because the entities //
// above the erased are to be decremented. //
// ********************************************************************* //
void CCollisionManager::UnOccupyLast9Cells(CStats* pEntityOne)
{
stCELLVector2 vCell = *pEntityOne->m_pvOldCell;
// Precalculate
int a = vCell.iCol - 1; // Left tile
int b = vCell.iCol + 1; // Right tile
// MIDDLE ROW
// Cell 7
m_pVec = &m_ppCollMap[vCell.iRow][a].m_vecCollisionEntities;
assert((m_pVec->begin() + (pEntityOne->m_iPositionInCell[0] -1)) < m_pVec->end());
m_itToBeErased = m_pVec->begin() + (pEntityOne->m_iPositionInCell[0] -1);
for (m_it = m_itToBeErased + 1; m_it != m_pVec->end(); ++m_it)
if (m_it > m_itToBeErased)
(*m_it)->m_iPositionInCell[0] -= 1;
assert(pEntityOne->m_iPositionInCell[0] <= m_pVec->size());
m_pVec->erase(m_itToBeErased);
// Cell 0
m_pVec = &m_ppCollMap[vCell.iRow][vCell.iCol].m_vecCollisionEntities;
assert((m_pVec->begin() + (pEntityOne->m_iPositionInCell[1] -1)) < m_pVec->end());
m_itToBeErased = m_pVec->begin() + (pEntityOne->m_iPositionInCell[1] -1);
for (m_it = m_itToBeErased + 1; m_it != m_pVec->end(); ++m_it)
if (m_it > m_itToBeErased)
(*m_it)->m_iPositionInCell[1] -= 1;
assert(pEntityOne->m_iPositionInCell[1] <= m_pVec->size());
m_pVec->erase(m_itToBeErased);
// Cell 3
m_pVec = &m_ppCollMap[vCell.iRow][b].m_vecCollisionEntities;
assert((m_pVec->begin() + (pEntityOne->m_iPositionInCell[2] -1)) < m_pVec->end());
m_itToBeErased = m_pVec->begin() + (pEntityOne->m_iPositionInCell[2] -1);
for (m_it = m_itToBeErased + 1; m_it != m_pVec->end(); ++m_it)
if (m_it > m_itToBeErased)
(*m_it)->m_iPositionInCell[2] -= 1;
assert(pEntityOne->m_iPositionInCell[2] <= m_pVec->size());
m_pVec->erase(m_itToBeErased);
// FIRST ROW
int iRow = vCell.iRow - 1;
// Cell 8
m_pVec = &m_ppCollMap[iRow][a].m_vecCollisionEntities;
assert((m_pVec->begin() + (pEntityOne->m_iPositionInCell[3] -1)) < m_pVec->end());
m_itToBeErased = m_pVec->begin() + (pEntityOne->m_iPositionInCell[3] -1);
for (m_it = m_itToBeErased + 1; m_it != m_pVec->end(); ++m_it)
if (m_it > m_itToBeErased)
(*m_it)->m_iPositionInCell[3] -= 1;
assert(pEntityOne->m_iPositionInCell[3] <= m_pVec->size());
m_pVec->erase(m_itToBeErased);
// Cell 1
m_pVec = &m_ppCollMap[iRow][vCell.iCol].m_vecCollisionEntities;
assert((m_pVec->begin() + (pEntityOne->m_iPositionInCell[4] -1)) < m_pVec->end());
m_itToBeErased = m_pVec->begin() + (pEntityOne->m_iPositionInCell[4] -1);
for (m_it = m_itToBeErased + 1; m_it != m_pVec->end(); ++m_it)
if (m_it > m_itToBeErased)
(*m_it)->m_iPositionInCell[4] -= 1;
assert(pEntityOne->m_iPositionInCell[4] <= m_pVec->size());
m_pVec->erase(m_itToBeErased);
// Cell 2
m_pVec = &m_ppCollMap[iRow][b].m_vecCollisionEntities;
assert((m_pVec->begin() + (pEntityOne->m_iPositionInCell[5] -1)) < m_pVec->end());
m_itToBeErased = m_pVec->begin() + (pEntityOne->m_iPositionInCell[5] -1);
for (m_it = m_itToBeErased + 1; m_it != m_pVec->end(); ++m_it)
if (m_it > m_itToBeErased)
(*m_it)->m_iPositionInCell[5] -= 1;
assert(pEntityOne->m_iPositionInCell[5] <= m_pVec->size());
m_pVec->erase(m_itToBeErased);
// LAST ROW
iRow = vCell.iRow + 1;
// Cell 6
m_pVec = &m_ppCollMap[iRow][a].m_vecCollisionEntities;
assert((m_pVec->begin() + (pEntityOne->m_iPositionInCell[6] -1)) < m_pVec->end());
m_itToBeErased = m_pVec->begin() + (pEntityOne->m_iPositionInCell[6] -1);
for (m_it = m_itToBeErased + 1; m_it != m_pVec->end(); ++m_it)
if (m_it > m_itToBeErased)
(*m_it)->m_iPositionInCell[6] -= 1;
assert(pEntityOne->m_iPositionInCell[6] <= m_pVec->size());
m_pVec->erase(m_itToBeErased);
// Cell 5
m_pVec = &m_ppCollMap[iRow][vCell.iCol].m_vecCollisionEntities;
assert((m_pVec->begin() + (pEntityOne->m_iPositionInCell[7] -1)) < m_pVec->end());
m_itToBeErased = m_pVec->begin() + (pEntityOne->m_iPositionInCell[7] -1);
for (m_it = m_itToBeErased + 1; m_it != m_pVec->end(); ++m_it)
if (m_it > m_itToBeErased)
(*m_it)->m_iPositionInCell[7] -= 1;
assert(pEntityOne->m_iPositionInCell[7] <= m_pVec->size());
m_pVec->erase(m_itToBeErased);
// Cell 4
m_pVec = &m_ppCollMap[iRow][b].m_vecCollisionEntities;
assert((m_pVec->begin() + (pEntityOne->m_iPositionInCell[8] -1)) < m_pVec->end());
m_itToBeErased = m_pVec->begin() + (pEntityOne->m_iPositionInCell[8] -1);
for (m_it = m_itToBeErased + 1; m_it != m_pVec->end(); ++m_it)
if (m_it > m_itToBeErased)
(*m_it)->m_iPositionInCell[8] -= 1;
assert(pEntityOne->m_iPositionInCell[8] <= m_pVec->size());
m_pVec->erase(m_itToBeErased);
} // UnOccupy9Cells
Here is the test data showing the cell's vector size (the number of entities occupying each cell) remember 1 entity occupies 9 cells around it.
CCollisionManager::DebugPrint() Printing contents of collision map
CCollisionManager::DebugPrint() Collision grid size = 128
CCollisionManager::DebugPrint() World Row Max = 13
CCollisionManager::DebugPrint() World Col Max = 18
CCollisionManager::DebugPrint() [0] = (0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
CCollisionManager::DebugPrint() [128] = (0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
CCollisionManager::DebugPrint() [256] = (0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
CCollisionManager::DebugPrint() [384] = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
CCollisionManager::DebugPrint() [512] = (1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
CCollisionManager::DebugPrint() [640] = (1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
CCollisionManager::DebugPrint() [768] = (1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
CCollisionManager::DebugPrint() [896] = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
CCollisionManager::DebugPrint() [1024] = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
CCollisionManager::DebugPrint() [1152] = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
CCollisionManager::DebugPrint() [1280] = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
CCollisionManager::DebugPrint() [1408] = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
CCollisionManager::DebugPrint() [1536] = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, )
Great and profuse thanks in advance...