Exemple #1
0
    /// <summary>
    /// Given a CircleEntity and the vertices and position of a 2D Polygon, checks if the circle and the polygon are overlapping
    /// </summary>
    /// <param name="circle"> The circle entity in question </param>
    /// <param name="polyPosition"> The position of the polygon in question </param>
    /// <param name="poly"> The world space position of the vertices of the polygon </param>
    /// <param name="localPoly"> The local space position of the vertices of the polygon </param>
    /// <returns></returns>
    public static bool DetectCollision(CircleEntity circle, Vector polyPosition, Vector[] poly, Vector[] localPoly)
    {
        Vector relativeCirclePos = circle.position - polyPosition;
        float  seperation        = -10000;
        int    face = -1234;

        //Console.WriteLine("MOVEMNT TICK");
        for (int i = 0; i < poly.Length; i++)
        {
            //get the normal
            Vector normal = poly[i].GetNormal().Normalized();


            Vector circleToPoint = relativeCirclePos - localPoly[i];
            //dot the normal with the circle position
            float currentSeperation = Vector.Dot(normal, circleToPoint);

            //if result of dot is bigger than radius
            if (currentSeperation >= circle.Radius)
            {
                //Console.WriteLine("NO COL");
                return(false);
            }
            //return

            //if its bigger than stored penetration
            if (currentSeperation > seperation)
            {
                //store current face
                //store current penetration
                face       = i;
                seperation = currentSeperation;
            }
        }

        Vector v1          = poly[face];
        int    secondIndex = face + 1 >= poly.Length ? 0 : face + 1;
        Vector v2          = poly[secondIndex];

        float v1Dot = Vector.Dot(circle.position - v1, v2 - v1);
        float v2Dot = Vector.Dot(circle.position - v2, v1 - v2);

        if (v1Dot <= 0)
        {
            if (Mathf.DistanceSquared(v1.x, v1.y, circle.position.x, circle.position.y) > circle.Radius * circle.Radius)
            {
                //Console.WriteLine("NO COL");
                return(false);
            }
        }
        else if (v2Dot <= 0)
        {
            if (Mathf.DistanceSquared(v2.x, v2.y, circle.position.x, circle.position.y) > circle.Radius * circle.Radius)
            {
                //Console.WriteLine("NO COL");
                return(false);
            }
        }
        return(true);
    }
    /// <summary>
    /// Given a PolygonEntitiy and a Circle Entity, generates a manifold containing the information required to
    /// resolve the collision (if there was one to begin with).
    /// </summary>
    public static Manifold GenerateManifold(PolygonEntity poly, CircleEntity circle)
    {
        Manifold Result;

        Result.A            = poly;
        Result.B            = circle;
        Result.IsEmpty      = false;
        Result.ContactPoint = new List <Vector>();

        Vector relativeCirclePos = circle.position - poly.position;

        float seperation = -10000;
        int   face       = -1234;

        for (int i = 0; i < poly.GetVertices().Length; i++)
        {
            //get the normal
            Vector normal        = poly.GetFaceNormal(i).Normalized();
            Vector circleToPoint = relativeCirclePos - poly.GetLocalSpaceVertices()[i];
            //dot the normal with the circle position
            float currentSeperation = Vector.Dot(normal, circleToPoint);

            //if result of dot is bigger than radius
            if (currentSeperation > circle.Radius)
            {
                return(GenerateEmptyManifold());
            }
            //return

            //if its bigger than stored penetration
            if (currentSeperation > seperation)
            {
                face       = i;
                seperation = currentSeperation;
            }
        }


        Vector v1          = poly.GetVertices()[face];
        int    secondIndex = face + 1 >= poly.GetVertices().Length ? 0 : face + 1;
        Vector v2          = poly.GetVertices()[secondIndex];

        //if point is inside polygon
        if (seperation < EPSILON)
        {
            //normal is negative face normal
            Result.Normal           = poly.GetFaceNormal(face).Normalized() * -1f;
            Result.PenetrationDepth = circle.Radius;
            Result.ContactPoint.Add(Result.Normal * circle.Radius + circle.position);
            //penetration depth is radius
            //contact point is -normal*radius + position
        }


        //determine which voronoi region the circle lies in
        //dot with first point
        float v1Dot = Vector.Dot(circle.position - v1, v2 - v1);
        float v2Dot = Vector.Dot(circle.position - v2, v1 - v2);

        Result.PenetrationDepth = circle.Radius - seperation;

        //dot with second point
        //penetration depth is radius-seperation

        //if dot with first point is negative
        if (v1Dot <= 0)
        {
            if (Mathf.DistanceSquared(v1.x, v1.y, circle.position.x, circle.position.y) > circle.Radius * circle.Radius)
            {
                return(GenerateEmptyManifold());
            }
            Result.Normal = (v1 - poly.position).Normalized();
            Result.ContactPoint.Add(v1);
            //normal is point-center
            //contact point is point
        }
        else if (v2Dot <= 0)
        {
            if (Mathf.DistanceSquared(v2.x, v2.y, circle.position.x, circle.position.y) > circle.Radius * circle.Radius)
            {
                return(GenerateEmptyManifold());
            }
            Result.Normal = (v2 - poly.position).Normalized();
            Result.ContactPoint.Add(v2);
        }
        else
        {
            Result.Normal = poly.GetFaceNormal(face).Normalized();
            Result.ContactPoint.Add(Result.Normal * circle.Radius + circle.position);
        }

        return(Result);
    }