Esempio n. 1
0
        /// <summary>
        /// Verifica si este poligono esta colisionando o va a colisionar
        /// con una caja (rectangulo) dada
        /// Esta verificación se realiza utilizando SAT (Separating Axis Theorem) la cual explica
        /// que, si existe una linea en el plano que pueda separar dos distintas figuras en diferentes
        /// lados por completo, entonces estas figuras no están colisionando.
        /// Nota: Este teorema solo debería aplicarse ante poligonos concavos, de otra forma el algoritmo
        /// no daria una respuesta correcta ante poligonos convexos.
        /// </summary>
        /// <param name="box">Caja con la cual se hará la verificacion</param>
        /// <param name="distance">Distancia por la cual se movera este poligono</param>
        /// <param name="result">Referencia del objeto que contendrá la información necesaria sobre 
        /// si se esta intersectando, si se intersectará y la distancia necesaria 
        /// para evitar una intersección</param>
        protected override CollisionResult IntersectWithBox(Box box, ref Vector2 distance)
        {
            CollisionResult result = new CollisionResult();
            result.triggeringBody = this;
            result.affectedBody = box;
            // Se asume que ambas figuras intersectan hasta que
            // se pueda demostrar lo contrario
            result.intersect = true;
            result.willIntersect = true;
            // Se obtiene la cantidad de lados del poligono y del
            // rectangulo (Para el rectangulo solo es necesario estudiar dos lados)
            int sideCountPolygon = this.sides.Count;
            int sideCountRectangle = 2;
            float minIntervalDistance = float.PositiveInfinity;
            Vector2 translationAxis = new Vector2();
            // Lado actual a analizar
            Line currentSide;

            // Se realiza una verificacion por cada uno de los lados del poligono y por dos lados
            // perpendiculares del rectangulo hasta que pueda encontrarse alguna separación entre
            // ambas o hasta que se hayan verificado todos los lados
            for (int sideIndex = 0; sideIndex < sideCountPolygon + sideCountRectangle; sideIndex++)
            {
                if (sideIndex < sideCountPolygon)
                {
                    currentSide = this.sides[sideIndex];
                }
                else
                {
                    if (sideIndex - sideCountPolygon == 0)
                    {
                        currentSide = box.Sides[0];
                    }
                    else
                    {
                        currentSide = box.Sides[1];
                    }
                }

                // Se obtiene un Vector perpendicular al lado actual con valores unitarios,
                // esto servira para obtener el eje sobre el cual deben hacerse las proyecciones
                Vector2 axis = new Vector2(-currentSide.Edge.Y, currentSide.Edge.X);
                axis.Normalize();

                // Se proyectan ambas figuras sobre el mismo eje
                float minA = 0; float minB = 0; float maxA = 0; float maxB = 0;
                this.Project(ref axis, out minA, out maxA);
                box.Project(ref axis, out minB, out maxB);

                // Se obtiene el intervalo entre ambas figuras sobre el eje,
                // si el intervalo (separación) es mayor a 0 entonces las figuras
                // no están intersectando
                float intervalDistance = IntervalDistance(minA, maxA, minB, maxB);
                if (intervalDistance > 0) result.intersect = false;

                // Luego se realizan los mismos calculos pero sumando el vector
                // de velocidad al poligono en (posible) movimiento
                float velocityProjection = Vector2.Dot(axis, distance);

                //if (velocityProjection < 0)
                //{
                    minA += velocityProjection;
                //}
                //else
                //{
                    maxA += velocityProjection;
                //}

                // Si el intervalo de distancia es menor a 0 con el poligono en movimiento,
                // entonces las figuras tambien intersectaran al moverse
                intervalDistance = IntervalDistance(minA, maxA, minB, maxB);
                if (intervalDistance > 0) result.willIntersect = false;

                // Si ya sabemos que las figuras estan intersectando y van a intersectar,
                // no hay mucho mas que hacer aquí asi que terminamos las verificaciones
                if (result.intersect == false && result.willIntersect == false)
                {
                    break;
                }

                // Si el intervalo de distancia es el minimo, se guarda
                // junto con el eje donde fue encontrado para asi poder separar
                // a las figuras en esa dirección
                intervalDistance = Math.Abs(intervalDistance);
                if (intervalDistance < minIntervalDistance)
                {
                    minIntervalDistance = intervalDistance;
                    translationAxis = axis;

                    Vector2 d = this.Center - box.Center;
                    if (Vector2.Dot(d, translationAxis) < 0)
                    {
                        translationAxis = -translationAxis;
                    }
                }
            }

            // El vector minimo de transición
            // servira para separar ambas figuras en caso de que colisionen.
            if (result.willIntersect)
            {
                result.minimumTranslationVector =
                       translationAxis * minIntervalDistance;
            }

            result.translationAxis = translationAxis;
            return result;
        }
Esempio n. 2
0
        /// <summary>
        /// Verifica si este rectangulo esta colisionando o va a colisionar
        /// con otro rectangulo dado.
        /// Esta verificación se realiza utilizando SAT (Separating Axis Theorem) la cual explica
        /// que, si existe una linea en el plano que pueda separar dos distintas figuras en diferentes
        /// lados por completo, entonces estas figuras no están colisionando.
        /// Nota: Este teorema solo debería aplicarse ante poligonos concavos, de otra forma el algoritmo
        /// no daria una respuesta correcta ante poligonos convexos.
        /// </summary>
        /// <param name="box">Segundo rectangulo con el cual se hará la verificacion</param>
        /// <param name="distance">Distancia por la cual se movera el rectangulo principal (this)</param>
        /// <param name="result">Referencia del objeto que contendrá la información necesaria sobre 
        /// si se esta intersectando, si se intersectará y la distancia necesaria 
        /// para evitar una intersección</param>
        protected override CollisionResult IntersectWithBox(Box box, ref Vector2 distance)
        {
            CollisionResult result = new CollisionResult();
            result.triggeringBody = this;
            result.affectedBody = box;
            // Se asume que ambos rectangulos intersectan hasta que
            // se pueda demostrar lo contrario
            result.intersect = true;
            result.willIntersect = true;
            float minIntervalDistance = float.PositiveInfinity;
            Vector2 translationAxis = new Vector2();
            Line currentSide;
            Vector2 axis = Vector2.Zero;

            // Se realiza una verificacion por dos lados perpendiculares de cada rectangulo
            // hasta que pueda encontrarse alguna separación entre ambos o hasta que se hayan
            // verificado todos los lados
            for (int edgeIndex = 0; edgeIndex < 4; edgeIndex++)
            {
                if (edgeIndex < 2)
                {
                    if (edgeIndex == 0)
                    {
                        currentSide = this.sides[0];
                    }
                    else
                    {
                        currentSide = this.sides[1];
                    }
                }
                else
                {
                    if (edgeIndex - 2 == 0)
                    {
                        currentSide = box.sides[0];
                    }
                    else
                    {
                        currentSide = box.sides[1];
                    }
                }

                // Se obtiene un Vector perpendicular al lado actual con valores unitarios,
                // esto servira para obtener el eje sobre el cual deben hacerse las proyecciones
                axis.X = -currentSide.Edge.Y;
                axis.Y = currentSide.Edge.X;
                axis.Normalize();

                // Se proyectan ambos rectangulos sobre el mismo eje
                float minA = 0; float minB = 0; float maxA = 0; float maxB = 0;
                this.Project(ref axis, out minA, out maxA);
                box.Project(ref axis, out minB, out maxB);

                // Se obtiene el intervalo entre ambos rectangulos sobre el eje,
                // si el intervalo (separación) es mayor a 0 entonces los rectangulos
                // no están intersectando
                float intervalDistance = IntervalDistance(minA, maxA, minB, maxB);
                if (intervalDistance > 0) result.intersect = false;

                // Luego se realizan los mismos calculos pero sumando el vector
                // de velocidad al rectangulo en (posible) movimiento
                float velocityProjection;
                Vector2.Dot(ref axis, ref distance, out velocityProjection);

                //if (velocityProjection < 0)
                //{
                    minA += velocityProjection;
                //}
                //else
                //{
                    maxA += velocityProjection;
                //}

                // Si el intervalo de distancia es menor a 0 con el rectangulo en movimiento,
                // entonces las rectangulos tambien intersectaran al moverse
                intervalDistance = IntervalDistance(minA, maxA, minB, maxB);
                if (intervalDistance > 0) result.willIntersect = false;

                // Si ya sabemos que los rectangulos estan intersectando y van a intersectar,
                // no hay mucho mas que hacer aquí asi que terminamos las verificaciones
                if (result.intersect == false && result.willIntersect == false)
                {
                    break;
                }

                // Si el intervalo de distancia es el minimo, se guarda
                // junto con el eje donde fue encontrado para asi poder separar
                // a los rectangulos en esa dirección
                intervalDistance = Math.Abs(intervalDistance);
                if (intervalDistance < minIntervalDistance)
                {
                    minIntervalDistance = intervalDistance;
                    translationAxis = axis;

                    Vector2 d;
                    Vector2 secondBodyCenter = box.Center;
                    Vector2.Subtract(ref this.center, ref secondBodyCenter, out d);

                    float dot;
                    Vector2.Dot(ref d, ref translationAxis, out dot);
                    if (dot < 0)
                    {
                        Vector2.Multiply(ref translationAxis, -1, out translationAxis);
                    }
                }
            }

            // El vector minimo de transición
            // servira para separar ambos rectangulos en caso de que colisionen.
            if (result.willIntersect)
            {
                Vector2.Multiply(ref translationAxis, minIntervalDistance, out result.minimumTranslationVector);
            }

            result.translationAxis = translationAxis;
            return result;
        }