我应该何时以及如何更新我的碰撞网格?
当前实现:
- 设置实体速度
- buildGrid():将所有有冲突的实体添加到网格中
- handleCollision(timePerFrame,实体):处理所有碰撞,相应地调整速度
- grid.clear():清除网格
- 移动实体
例如,如果我有 4000 个固定实体,只有 20 个移动实体,则每次更新都会无缘无故地删除 4000 个实体并将其添加到网格中。
仅更新需要更新的单元格的好方法是什么?
我目前唯一的想法是,在碰撞检查后,我从网格中删除移动实体,而在buildGrid()期间,我只将移动实体添加到网格中。
欢迎所有帮助。
电网实施
// CollisionGrid Cell
class Cell
{
public:
typedef std::set<Entity*> Container;
public:
void setNeighbours(Cell* left, Cell* right, Cell* up, Cell* down);
void addEntity(Entity* entity);
Container getNearbyEntities() const;
void clear();
private:
void appendEntitiesTo(Container& entities) const;
private:
Container mEntities;
protected:
Cell* mLeft;
Cell* mRight;
Cell* mUp;
Cell* mDown;
};
// CollisionGrid
class CollisionGrid
{
public:
CollisionGrid(float sceneWidth, float sceneHeight, float cellSize);
void clear();
void addEntity(Entity* entity);
Cell::Container getNearbyEntities(Entity* entity);
private:
int getIdForPosition(const sf::Vector2f position);
public:
int mCols;
int mRows;
std::vector<Cell> mCells;
private:
float mSceneWidth;
float mSceneHeight;
float mCellSize;
};
// CollisionGrid Cell
void Cell::setNeighbours(Cell* left, Cell* right, Cell* up, Cell* down)
{
mLeft = left;
mRight = right;
mUp = up;
mDown = down;
}
void Cell::addEntity(Entity* entity)
{
mEntities.insert(entity);
}
Cell::Container Cell::getNearbyEntities() const
{
Container entities = mEntities;
if (mLeft != nullptr)
mLeft->appendEntitiesTo(entities);
if (mRight != nullptr)
mRight->appendEntitiesTo(entities);
if (mUp != nullptr)
mUp->appendEntitiesTo(entities);
if (mDown != nullptr)
mDown->appendEntitiesTo(entities);
return entities;
}
void Cell::clear()
{
mEntities.clear();
}
void Cell::appendEntitiesTo(Container& entities) const
{
entities.insert(mEntities.begin(), mEntities.end());
}
// CollisionGrid
CollisionGrid::CollisionGrid(float sceneWidth, float sceneHeight, float cellSize)
: mSceneWidth(sceneWidth)
, mSceneHeight(sceneHeight)
, mCellSize(cellSize)
, mCols((int)floor(sceneWidth / cellSize))
, mRows((int)floor(sceneHeight / cellSize))
{
mCells = std::vector<Cell>(mCols*mRows);
for (int id = 0; id < mCols*mRows; ++id)
{
Cell* left = nullptr;
Cell* right = nullptr;
Cell* up = nullptr;
Cell* down = nullptr;
if (id % mCols > 0)
left = &mCells[id - 1];
if (id % mCols < mCols - 1)
right = &mCells[id + 1];
if (id > mCols - 1)
up = &mCells[id - mCols];
if (id < mCols * (mRows - 1))
down = &mCells[id + mCols];
mCells[id].setNeighbours(left, right, up, down);
}
}
void CollisionGrid::clear()
{
for (Cell& cell : mCells)
cell.clear();
}
void CollisionGrid::addEntity(Entity* entity)
{
mCells[getIdForPosition(entity->position)].addEntity(entity);
}
Cell::Container CollisionGrid::getNearbyEntities(Entity* entity)
{
return mCells[getIdForPosition(entity->position)].getNearbyEntities();
}
int CollisionGrid::getIdForPosition(const sf::Vector2f position)
{
return int(floor(position.x / mCellSize) + floor(position.y / mCellSize) * mCols);
}
一种解决方案是实现对层次结构的更新功能。您可以直接向碰撞网格、单元格和实体添加更新功能。
void CollisionGrid::Update()
{
for(vector<Cell>::iterator it = mCells.begin(); it != mCells.end(); ++it)
{
it->Update();
}
}
void Cell::Update()
{
for(set<Entity>::iterator it = mEntities.begin(); it != mEntities.end(); ++it)
{
it->Update();
}
}
void Entity::Update()
{
// Update with the entity behaviour
// For example : Move Entity
// You can create a class that inherite from Entity that will be a movable class
}
这背后的想法是,当我们更新环境的状态时,我们更新环境的每个子组件和这些组件的子组件,依此类推。每个组件根据其特定行为进行更新。例如,您可能需要添加对实体中单元格的引用,以便还可以在更新实体时更新实体正在移动的单元格。
您还可以阅读实体和组件编程,例如,这是视频游戏中常见的编程方法。