충돌 감지 시스템을 구현하려고하는데 대부분의 경우 겹치지 않고 (또는 거의 겹치지 않고) 문자 충돌 및 벽 충돌이 발생합니다. 문제는 내가 선수 한 명을 따라 다니면서 그 선수 한 명을 만난다는 것인데, 15-20 명 정도의 선수가 선수를 밀 때 플레이어 나 다른 물건들이 벽을 통해 밀려날 수있다.C++ - 충돌 응답으로 클리핑이 발생합니다.
내 코드는 다음과 같이 작동합니다. 먼저 모든 문자를 업데이트하고 서로 충돌을 확인한 다음 벽과의 문자 충돌을 확인합니다. 문제가되는 것처럼 모든 문자를 밀어 넣으면 하나 이상의 문자를 먼 거리까지 밀어야하지만 문제를 해결하는 방법을 모르겠습니다. 필요한 경우 아래의 코드를 수정하는 방법에 대한 철저한 설명으로도 충분합니다.
문자 업데이트/충돌 :
void CharacterManager::updateAll(float elapsedTime)
{
for(std::vector<std::shared_ptr<Character>>::iterator i = _characters.begin(); i != _characters.end(); i++) {
(*i)->update(elapsedTime);
}
collisions();
}
void CharacterManager::collisions()
{
for(std::vector<std::shared_ptr<Character>>::iterator i = _characters.begin(); i != _characters.end(); i++) {
for(std::vector<std::shared_ptr<Character>>::iterator j = _characters.begin(); j != _characters.end(); j++) {
if(i == j) continue;
float xi = (*i)->position().x;
float yi = (*i)->position().y;
float xj = (*j)->position().x;
float yj = (*j)->position().y;
float dx = xi - xj;
float dy = yi - yj;
float distSquared = dx * dx + dy * dy;
float ri = (*i)->xRect().width/2;
float rj = (*j)->xRect().width/2;
if(distSquared < (ri + rj) * (ri + rj)) {
// fix collisions
float angle = atan2f(dy,dx);
float overlap = (ri + rj) - sqrt(distSquared);
if(xi < xj) {
if(yi < yj) {
(*i)->position(xi - cosf(angle) * overlap/2, yi - sinf(angle) * overlap/2);
(*j)->position(xj + cosf(angle) * overlap/2, yj + sinf(angle) * overlap/2);
} else {
(*i)->position(xi - cosf(angle) * overlap/2, yi + sinf(angle) * overlap/2);
(*j)->position(xj + cosf(angle) * overlap/2, yj - sinf(angle) * overlap/2);
}
} else {
if(yi < yj) {
(*i)->position(xi + cosf(angle) * overlap/2, yi - sinf(angle) * overlap/2);
(*j)->position(xj - cosf(angle) * overlap/2, yj + sinf(angle) * overlap/2);
} else {
(*i)->position(xi + cosf(angle) * overlap/2, yi + sinf(angle) * overlap/2);
(*j)->position(xj - cosf(angle) * overlap/2, yj - sinf(angle) * overlap/2);
}
}
// calc new velocities
float vxi = (*i)->velocity().x;
float vyi = (*i)->velocity().y;
float vxj = (*j)->velocity().x;
float vyj = (*j)->velocity().y;
float vx = vxj - vxi;
float vy = vyj - vyi;
float dotProduct = dx * vx + dy * vy;
if(dotProduct >= 0) {
float collisionScale = dotProduct/distSquared;
float xCollision = dx * collisionScale;
float yCollision = dy * collisionScale;
float combinedMass = (*i)->weight() + (*j)->weight();
float collisionWeightA = 2 * (*j)->weight()/combinedMass;
float collisionWeightB = 2 * (*i)->weight()/combinedMass;
(*i)->velocity(vxi + collisionWeightA * xCollision, vyi + collisionWeightA * yCollision);
(*j)->velocity(vxj - collisionWeightB * xCollision, vyj - collisionWeightB * yCollision);
}
}
}
}
}
벽 충돌 : 두 객체가 서로 교차 할 때
void Stage::characterCrossCollisions(std::shared_ptr<Character> character)
{
for(std::vector<std::shared_ptr<Tile>>::iterator tile = tiles.begin(); tile != tiles.end(); tile++) {
if(!(*tile)->walkable) {
sf::Rect<float> cxr = character->xRect();
sf::Rect<float> cyr = character->yRect();
sf::Rect<float> tr = (*tile)->getRect();
if(!(cxr.left > tr.left + tr.width ||
cxr.left + cxr.width < tr.left ||
cxr.top > tr.top + tr.height ||
cxr.top + cxr.height < tr.top)) {
float ox = 0;
if(character->position().x > (*tile)->position().x) {
ox = cxr.left - (tr.left + tr.width);
}
else {
ox = cxr.left + cxr.width - tr.left;
}
character->position(character->position().x - ox, character->position().y);
}
if(!(cyr.left > tr.left + tr.width ||
cyr.left + cyr.width < tr.left ||
cyr.top > tr.top + tr.height ||
cyr.top + cyr.height < tr.top)) {
float oy = 0;
if(character->position().y > (*tile)->position().y) {
oy = cyr.top - (tr.top + tr.height);
}
else {
oy = cyr.top + cyr.height - tr.top;
}
character->position(character->position().x, character->position().y - oy);
}
}
}
}
매우 흥미롭고, 이런 식의 업데이트는 절대로 생각해 본적이 없습니다. –
이 시점에서, 나는 동시에 겹치는 두 개 이상의 객체 객체와 그들의 최종 위치/속도를 해결하는 방법을 다루는 데 어려움을 겪고 있습니다. –