何时以及如何更新碰撞网格



我应该何时以及如何更新我的碰撞网格?

当前实现:

  1. 设置实体速度
  2. buildGrid():将所有有冲突的实体添加到网格中
  3. handleCollision(timePerFrame,实体):处理所有碰撞,相应地调整速度
  4. grid.clear():清除网格
  5. 移动实体

例如,如果我有 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
    }

这背后的想法是,当我们更新环境的状态时,我们更新环境的每个子组件和这些组件的子组件,依此类推。每个组件根据其特定行为进行更新。例如,您可能需要添加对实体中单元格的引用,以便还可以在更新实体时更新实体正在移动的单元格。

您还可以阅读实体和组件编程,例如,这是视频游戏中常见的编程方法。

最新更新