C++ 二维组碰撞检测

C++ 二维组碰撞检测,c++,collision-detection,C++,Collision Detection,我正在尝试在我的游戏中实现碰撞检测,但一开始看起来很简单的东西已经变成了一个怪物,如果没有一些帮助,我无法完全解决它 游戏在某种程度上会是一个即时战略游戏,但现在它只是一堆可以被告知移动到屏幕上特定位置的单位。但是,这些单位一直只消失在一个单位中,所以我为每个单位定义了边界框,并在游戏循环中移动这些单位后测试它们之间的碰撞,以便将它们分开 这不起作用,因为我没有实现一种方法来知道我正在转移的特定单元没有取代其他单元的位置(我已经迭代过) 我试图保持已经占据的位置(或区域),以便在没有单位的地方转

我正在尝试在我的游戏中实现碰撞检测,但一开始看起来很简单的东西已经变成了一个怪物,如果没有一些帮助,我无法完全解决它

游戏在某种程度上会是一个即时战略游戏,但现在它只是一堆可以被告知移动到屏幕上特定位置的单位。但是,这些单位一直只消失在一个单位中,所以我为每个单位定义了边界框,并在游戏循环中移动这些单位后测试它们之间的碰撞,以便将它们分开

这不起作用,因为我没有实现一种方法来知道我正在转移的特定单元没有取代其他单元的位置(我已经迭代过)

我试图保持已经占据的位置(或区域),以便在没有单位的地方转移。但在某些情况下,这也不起作用,例如当一个单元在屏幕的四个角中的任何一个移动时,它不能超出屏幕的边界,也不能占据与其碰撞的单元所占据的区域

我仍然很确定,我把一些可以用不同方法轻松完成的事情复杂化了

每个单元都有自己的边界球体、位置、方向向量和速度向量

class Unit {
    friend class Party;
    protected:
        float xPos, yPos;
        float destX, destY;
        float detectionRange;
        Vector *vel;
        Vector *dest;

        int dir;
        int offset;
        int width, height;

        Circle *circle;                 //Bounding Circle
        ...
    public:
        ...
};

//Collision Checking
void Party::checkCollisions() {
    bool noCol;
    float dx, dy;
    Circle *mCircle = NULL;
    Circle *sCircle = NULL;

    do {
        noCol = true;
        for(int i=0; i<numUnits; i++) {
            mCircle = units[i]->getCircle();
            for(int j=0; j<numUnits; j++) {
                if(j==i) {
                    continue;
                }

                sCircle = units[j]->getCircle();
                if(mCircle->isColliding(sCircle)) {
                    noCol = false;
                   mCircle->getShifts(sCircle, &dx, &dy);
                   units[i]->shift(dx, dy);
                   units[j]->shift(-dx, -dy);
                }
            }
        }
    } while(noCol == false);
}

//IsColliding. This is overriden for isColliding(Circle *circle), but here
//you see the actual algorithm.
bool Circle::isColliding(float X, float Y, int rad) {
    float mag = sqrt((X-x)*(X-x) + (Y-y)*(Y-y));

    if(mag <= (radius + rad)){
        return true;
    }

    return false;
}

//Get Shifts
void Circle::getShifts(Circle *c, float *dx, float *dy) {
    float x1 = x - c->x;
    float y1 = y - c->y;

    if(x1 > -1 && x1 < 1) {
        x1 = 1;
    }

    if(y1 > -1 && y1 < 1) {
        y1 = 1;
    }

    *dx = x1/fabs(x1);
    *dy = y1/fabs(y1);
}
类单位{
朋友班聚会;
受保护的:
浮动XPO、YPO;
浮动destX,destY;
浮动检测范围;
向量*vel;
向量*dest;
int dir;
整数偏移量;
int宽度、高度;
圆*圆;//边界圆
...
公众:
...
};
//碰撞检查
无效方::检查冲突(){
布尔诺科尔;
浮动dx,dy;
圆圈*mCircle=NULL;
圆*圆=空;
做{
noCol=真;
对于(int i=0;igetCircle();
对于(int j=0;jgetCircle();
if(mCircle->isColliding(sCircle)){
noCol=假;
mCircle->GetShift(sCircle、dx和dy);
单位[i]->移位(dx,dy);
单位[j]->移位(-dx,-dy);
}
}
}
}while(noCol==false);
}
//IsColliding。这对于IsColliding(圆*圆)是被覆盖的,但是在这里
//你可以看到实际的算法。
布尔圆::isColliding(浮点X、浮点Y、整数rad){
浮磁=sqrt((X-X)*(X-X)+(Y-Y)*(Y-Y));
if(magx;
浮动y1=y-c->y;
如果(x1>-1&&x1<1){
x1=1;
}
如果(y1>-1&&y1<1){
y1=1;
}
*dx=x1/fabs(x1);
*dy=y1/fabs(y1);
}
显示了我到目前为止所得到的,但很明显,它非常容易出错,并且有不必要的单位移动


我想要的是,当两个或多个单位聚集在一起时,它们会自然聚集。但所有单位不会始终形成一个群体。因为每个单位都有不同的探测范围,所以可以将一个或多个单位从群体中分离出来。我想要这样,以便以后我可以选择和移动不同的单位组。

为什么不应用方向向量到每个单元,并使它们相对地朝向该向量?例如,如果生成的向量指向东北45度,并且距离您的组的当前位置30米(当前位置应该是整个组的位置平均值,或者通过一些方案,例如与最近单元相关的方案)只需将每个单位相对于其自身位置移动到该位置。现在,你应该设置一个碰撞系统,以允许你处理诸如敌方单位通过你的小组冲锋或你的小组与某个静止物体接触等情况。现在,对于你的角碰撞问题,你应该添加一个额外的碰撞如果您想让触摸装置推动被触摸装置,请检查确保碰撞装置所接触的装置能够自行重新定位(即,他没有被四面包围)。否则,您只需让触摸装置停在原位即可


您可以将其用作参考:

听起来好像您的冲突代码已关闭。您的边界卷、框是什么?旋转框是什么

尝试使用圆圈作为单位边界。大多数游戏使用圆圈作为单位边界,因为它更便宜、更准确。另外,圆圈->圆圈碰撞代码也非常便宜

如果所有的单位都被要求移动到一个特定的位置,他们应该继续推进其他单位,而不是彼此内部移动。我可以想象一些发生在大群体中的奇怪情况,比如从其他单位中突入的单位,但稍后再处理

只要确保一旦一个单位与一个物体发生碰撞,代码就会“推”出该单位的位置。或者,按其方向*速度将其推回去

  • 对于每个单元,存储该单元想要的位置
  • 继续将装置移动到该位置
  • 对于所有单元(您在此步骤中处理所有单元):发生碰撞时,将单元推离碰撞一小段距离。即,如果需要将单元移动(x:10.0;y:10.0)以避免碰撞,请将其移动(x:1.0;y:1.0)相反,当两个单位发生碰撞时,你们可以将它们同时推离碰撞点,但要保持一小步,即使这不会立即解决碰撞问题
  • 重复#3 N次(N应为10..50左右)或直到任何装置均未发生碰撞
  • 这是一种愚蠢的方法,可以自动处理所有问题。当您将多个对象放置在同一位置,并且希望将它们移到一些合理的位置,使它们不再碰撞时,此算法也很有用

    或者你也可以学习。Java演示可用。这将在不滥用碰撞检测的情况下处理单元碰撞/编队


    struct-Vec2{
    浮动x;
    浮动y;
    Vec2(){
    }
    Vec2(浮点x_u2;,浮点y_2;)
    :x(x_uu),y(y_u){
    }
    Vec2(常数Vec2和其他)
    :x(其他.x),y(其他.y){
    }
    Vec2&oper
    
    struct Vec2{
        float x;
        float y;
        Vec2(){
        }
        Vec2(float x_, float y_)
        :x(x_), y(y_){
        }
        Vec2(const Vec2& other)
        :x(other.x), y(other.y){
        }
        Vec2& operator*=(const float f){
            x *= f; y *= f;
            return *this;
        }
    };
    
    struct Circle{
        Vec2 pos; 
        float radius;
    };
    
    float dot(const Vec2& arg1, const Vec2& arg2){
        return arg1.x*arg2.x + arg1.y*arg2.y;
    }
    
    float length(const Vec2& arg){
       return sqrtf(dot(arg, arg));
    }
    
    Vec2 operator-(const Vec2& arg1, const Vec2& arg2){
       return Vec2(arg1.x - arg2.x, arg1.y - arg2.y);
    }
    
    Vec2 scale(const Vec2& arg, const float scale){
       return Vec2(arg.x*scale, arg.y*scale);
    }
    
    bool collide(const Circle& c1, const Circle& c2){
        Vec2 diff = c1.pos - c2.pos;
        float maxSquareDistance = c1.radius+c2.radius;
        maxSquareDistance *= maxSquareDistance;
        return (dot(diff, diff) < maxSquareDistance);
    }
    
    Vec getShiftVector(const Circle& c1, const Circle& c2){
        diff = c2.pos - c1.pos;
        maxSquareDistance = c1.radius + c2.radius;
        maxSquareDistance *= maxSquareDistance;
        float squareDistance = dot(diff, diff);
        if (squareDistance > maxSquareDistance)
           return Vec2(0, 0);
    
        float distance = sqrtf(squareDistance)
        if (distance){
            diff.x /= distance;
            diff.y /= distance;
        }
        else{
            diff = Vec2(1, 0);
        }
    
        float scaleFactor = c1.radius + c2.radius - distance;
    
        diff.x *= scaleFactor;
        diff.y *= scaleFactor;
    
        return diff;        
    }