我使用SFML 2.1进行图形处理,我的游戏结构非常接近SFML书籍(SceneGraph实现等) 我的世界主要包括角色(大约1-400,四处移动)和瓷砖(3600,静止),每次移动时我都会检查碰撞
在最糟糕的情况下,有大约400个字符移动和~3600个区块,我有4000个可能的碰撞实体和800个碰撞检查调用(单独的X和Y移动)每个框架 - >总共3.2M碰撞检查。
我的几乎所有实体都有16x16像素的大小,我一直在研究实现四叉树或更简单的网格进行碰撞检测,这应该会使碰撞检查的数量下降很多。按网格我的意思是http://conkerjo.wordpress.com/2009/06/13/spatial-hashing-implementation-for-fast-2d-collisions/
但我不知道如何实现简单的网格。欢迎所有帮助。甚至有更好的方法可以强制实施这一点。
实体更新步骤。 我分别进行X / Y轴运动。因为我想在对角线碰撞时滑向实体。
水平移动实体
检查并处理碰撞
垂直移动实体
检查并处理碰撞
对所有实体重复1-4
void Entity::updateCurrent(sf::Time dt, CommandQueue& commands)
{
setPreviousPosition(getPosition());
move(sf::Vector2f(mVelocity.x, 0) * dt.asSeconds());
handleCollision();
setPreviousPosition(getPosition());
move(sf::Vector2f(0, mVelocity.y) * dt.asSeconds());
handleCollision();
}
在我尝试同时处理X和Y移动之前,我遇到了以下问题:
我不知道我是否应该在碰撞后重置X或Y位置。
碰撞处理。 我只会在实体移动时处理碰撞(目前只有角色实体,后来的投射物和一些特殊的瓷砖)
if entity is tile - >什么都不做
如果实体是字符 - >检查与角色和瓷砖的碰撞,并在碰撞发生时重置移动
void Entity::handleCollision()
{
if (getCategory() & Category::Tile)
return;
if (getCategory() & Category::Character)
{
std::set<SceneNode::Pair> collisionPairs;
checkCollision(*mSceneGraph, collisionPairs);
for (SceneNode::Pair pair : collisionPairs)
{
if (matchesCategories(pair, Category::Character, Category::NonPassableCharacterOrTile))
{
resetPreviousPosition();
break;
}
}
}
}
我只需使用SFML的intersects-function来检查碰撞。这对于这个来说是否足够好?
bool collision(const SceneNode& l, const SceneNode& r)
{
return l.getBoundingRect().intersects(r.getBoundingRect());
}
如果我要实现网格或四叉树进行碰撞检测,何时应该填充它,何时更新?我应该每次移动一个实体时更新它,还是应该尝试一次移动所有实体,然后构建网格/四叉树,然后才尝试处理所有碰撞。
所以我的问题是:(1)在这种情况下,我应该如何以及何时进行碰撞处理?我当前的实现工作正常,但我认为我经常这样做,所有我看到网格/四叉树的例子都假设我先做所有的动作,然后进行碰撞检测和处理。
和(2)何时清除/填充/更新我的网格/四叉树。例如,如果我有3600个瓷砖和3个移动字符。每次在网格中移动并尝试将其移动到不同的网格单元/树分支时,我应该寻找实体吗?
编辑:
除非有人提出更好的建议,否则我接下来会尝试下一步
更新了更新步骤。 这样聪明还是以合理的方式做到这一点?
从grid / quadtree中删除实体
水平移动实体
将实体添加到grid / quadtree
检查并处理碰撞
从grid / quadtree中删除实体
垂直移动实体
将实体添加到grid / quadtree
检查并处理碰撞
对所有实体重复1-8
Entity::move()
{
grid.getCell(getPosition()).remove(this);
... move x
grid.getCell(getPosition()).add(this);
... if collision, reset x
grid.getCell(getPosition()).remove(this);
... move y
grid.getCell(getPosition()).add(this);
... if collision, reset y
}
Entity::checkCollision()
{
list<Entity*> possibleColliders;
possibleColliders = grid.getEntitiesInRectangle(x - s, y - s, x + s, y + s);
... now only check collision against possibleColliders
}
答案 0 :(得分:-1)
我认为四叉树可以很好地工作,因为它将是独立的,将它添加到您当前的系统中确实没有问题。
您要问的重要问题可能是何时填充和更新四叉树。我认为这在很大程度上取决于您的用例。由于您有大约400个字符可以更改每个帧的位置,因此如果您尝试移动四叉树中的节点或完全重建四叉树,则可能不会产生很大差异。哪个性能更高,取决于您的算法和数据结构,这需要进行一些性能测试。
在this tutorial中,他们还建议每帧迭代重建四叉树。
对于“如何修复碰撞处理”,您需要提供更多信息/单独的SO问题,因为问题不明确是什么。