Circle-Rectangle collision detection (intersection)

前端 未结 24 1692
无人共我
无人共我 2020-11-22 02:55

How can I tell whether a circle and a rectangle intersect in 2D Euclidean space? (i.e. classic 2D geometry)

24条回答
  •  余生分开走
    2020-11-22 03:13

    Here's my C code for resolving a collision between a sphere and a non-axis aligned box. It relies on a couple of my own library routines, but it may prove useful to some. I'm using it in a game and it works perfectly.

    float physicsProcessCollisionBetweenSelfAndActorRect(SPhysics *self, SPhysics *actor)
    {
        float diff = 99999;
    
        SVector relative_position_of_circle = getDifference2DBetweenVectors(&self->worldPosition, &actor->worldPosition);
        rotateVector2DBy(&relative_position_of_circle, -actor->axis.angleZ); // This aligns the coord system so the rect becomes an AABB
    
        float x_clamped_within_rectangle = relative_position_of_circle.x;
        float y_clamped_within_rectangle = relative_position_of_circle.y;
        LIMIT(x_clamped_within_rectangle, actor->physicsRect.l, actor->physicsRect.r);
        LIMIT(y_clamped_within_rectangle, actor->physicsRect.b, actor->physicsRect.t);
    
        // Calculate the distance between the circle's center and this closest point
        float distance_to_nearest_edge_x = relative_position_of_circle.x - x_clamped_within_rectangle;
        float distance_to_nearest_edge_y = relative_position_of_circle.y - y_clamped_within_rectangle;
    
        // If the distance is less than the circle's radius, an intersection occurs
        float distance_sq_x = SQUARE(distance_to_nearest_edge_x);
        float distance_sq_y = SQUARE(distance_to_nearest_edge_y);
        float radius_sq = SQUARE(self->physicsRadius);
        if(distance_sq_x + distance_sq_y < radius_sq)   
        {
            float half_rect_w = (actor->physicsRect.r - actor->physicsRect.l) * 0.5f;
            float half_rect_h = (actor->physicsRect.t - actor->physicsRect.b) * 0.5f;
    
            CREATE_VECTOR(push_vector);         
    
            // If we're at one of the corners of this object, treat this as a circular/circular collision
            if(fabs(relative_position_of_circle.x) > half_rect_w && fabs(relative_position_of_circle.y) > half_rect_h)
            {
                SVector edges;
                if(relative_position_of_circle.x > 0) edges.x = half_rect_w; else edges.x = -half_rect_w;
                if(relative_position_of_circle.y > 0) edges.y = half_rect_h; else edges.y = -half_rect_h;   
    
                push_vector = relative_position_of_circle;
                moveVectorByInverseVector2D(&push_vector, &edges);
    
                // We now have the vector from the corner of the rect to the point.
                float delta_length = getVector2DMagnitude(&push_vector);
                float diff = self->physicsRadius - delta_length; // Find out how far away we are from our ideal distance
    
                // Normalise the vector
                push_vector.x /= delta_length;
                push_vector.y /= delta_length;
                scaleVector2DBy(&push_vector, diff); // Now multiply it by the difference
                push_vector.z = 0;
            }
            else // Nope - just bouncing against one of the edges
            {
                if(relative_position_of_circle.x > 0) // Ball is to the right
                    push_vector.x = (half_rect_w + self->physicsRadius) - relative_position_of_circle.x;
                else
                    push_vector.x = -((half_rect_w + self->physicsRadius) + relative_position_of_circle.x);
    
                if(relative_position_of_circle.y > 0) // Ball is above
                    push_vector.y = (half_rect_h + self->physicsRadius) - relative_position_of_circle.y;
                else
                    push_vector.y = -((half_rect_h + self->physicsRadius) + relative_position_of_circle.y);
    
                if(fabs(push_vector.x) < fabs(push_vector.y))
                    push_vector.y = 0;
                else
                    push_vector.x = 0;
            }
    
            diff = 0; // Cheat, since we don't do anything with the value anyway
            rotateVector2DBy(&push_vector, actor->axis.angleZ);
            SVector *from = &self->worldPosition;       
            moveVectorBy2D(from, push_vector.x, push_vector.y);
        }   
        return diff;
    }
    

提交回复
热议问题