【发布时间】:2014-07-21 01:55:13
【问题描述】:
我的 tilemap 冲突解决有问题。我有一个球撞到瓷砖上。碰撞工作正常,除非碰撞发生在两个瓷砖之间。然后我的碰撞解决方案出现故障,球飞向错误的方向。我的球是长方形的,瓷砖是长方形的。
这是一个演示问题的 .gif:
球应该一次一个地从瓷砖上反射出来。
算法是这样工作的:
- 应用移动,然后检查并解决冲突。
- 找出球重叠的瓷砖。
- 如果正在检查的图块无法通过:
- 找出球与瓷砖的 X 轴和 Y 轴重叠的程度。
- 仅在浅轴上将球移出瓷砖来解决碰撞问题。 (哪个轴渗透最少)。
- 转到下一个图块。
- 如果正在检查的图块可以通过,则什么也不做。
我已经读到这种最小位移技术的问题在于,在解决碰撞后,球可能会被移动到另一个碰撞中。修复应该是,第二次运行算法。我试过这个,但没有帮助。这是我的 C++ 碰撞处理代码:
void PlayState::handleCollisions() {
// Get ball bounding box.
sf::FloatRect ballBounds = ball.sprite.getGlobalBounds();
// Find out the nearby tiles.
int leftTile = (int)floor((float)ballBounds.left / level1.TILE_WIDTH);
int rightTile = (int)ceil(((float)(ballBounds.left + ballBounds.width) / level1.TILE_WIDTH)) - 1;
int topTile = (int)floor((float)ballBounds.top / level1.TILE_HEIGHT);
int bottomTile = (int)ceil(((float)(ballBounds.top + ballBounds.height) / level1.TILE_HEIGHT)) - 1;
// For each potentially colliding tile,
for(int y = topTile; y <= bottomTile; ++y) {
for(int x = leftTile; x <= rightTile; ++x) {
// If this tile is collidable,
TileCollision collision = getCollision(x, y);
if(collision == Impassable) {
// Determine collision depth (with direction) and magnitude.
sf::FloatRect tileBounds = getTileBounds(x, y);
sf::Vector2f depth = Collision::getIntersectionDepth(ballBounds, tileBounds);
if(depth != sf::Vector2f(0, 0)) {
float absDepthX = std::abs(depth.x);
float absDepthY = std::abs(depth.y);
// Resolve the collision along the shallow axis.
if(absDepthY < absDepthX) {
// Resolve the collision along the Y axis.
ball.sprite.setPosition(ball.sprite.getPosition().x, ball.sprite.getPosition().y + depth.y);
// Perform further collisions with the new bounds.
sf::FloatRect ballBounds = ball.sprite.getGlobalBounds();
// Y-distance to the tile center.
if(distanceY < 0) {
std::cout << "Collided from TOP." << std::endl;
ball.velocity.y = -ball.velocity.y;
}
else {
std::cout << "Collided from BOTTOM." << std::endl;
ball.velocity.y = -ball.velocity.y;
}
}
else {
// Resolve the collision along the X axis.
ball.sprite.setPosition(ball.sprite.getPosition().x + depth.x, ball.sprite.getPosition().y);
// Perform further collisions with the new bounds.
sf::FloatRect ballBounds = ball.sprite.getGlobalBounds();
// X-distance to the tile center.
if(distanceX < 0) {
std::cout << "Collided from LEFT." << std::endl;
ball.velocity.x = -ball.velocity.x;
}
else {
std::cout << "Collided from RIGHT." << std::endl;
ball.velocity.x = -ball.velocity.x;
}
}
}
}
}
}
}
我尝试第二次运行该算法,如下所示:
void PlayState::update(sf::Time deltaTime) {
ball.update(deltaTime);
handleCollisions();
handleCollisions();
}
我能做些什么来解决这个问题?
【问题讨论】:
标签: c++ algorithm collision-detection