The way I handle this is each cell has a list of entities which inhabit it and each entity has a list of cells / tiles it inhabits.
This way a cell can contain multiple entities and an entity can inhabit many cells.
Whenever an entity moves it checks for collisions with other entities which inhabit the cells it is moving through.
Once it has finalised its position it removes itself from any cell lists, clears it own list of cells.
Then for every cell it currently inhaibts it adds itself to that cells list and the cell to its own list.
private void updateInhabitedTiles(){
removeFromMap();
MapTile bottomLeft = inhabitedTileMap.mapToTile(
position.x,
position.y
);
MapTile topRight = inhabitedTileMap.mapToTile(
position.x + dimensions.x,
position.y + dimensions.y
);
for(int x = bottomLeft.xPos; x <= topRight.xPos; x++){
for(int y = bottomLeft.yPos; y <= topRight.yPos; y++){
MapTile inhabitedTile = inhabitedTileMap.getTile(x, y);
inhabitedTile.addEntity(this);
inhabitedTiles.add(inhabitedTile);
}
}
}
private void removeFromMap(){
for(MapTile mapTile : inhabitedTiles){
mapTile.removeEntity(this);
}
inhabitedTiles.clear();
}
When stress testing this I had approximately 9000 colliders before I noticed any slowdown and the cell / tile resolution was 16 pixels.
I used a LinkedHashSet for my lists of Tile Inhabitants (for cells) and Inhabited tiles (for entities).