/// <summary>
            /// Determines if two objects have collided using Axis-Aligned Bounding Box
            /// </summary>
            /// <param name="first">The first object to check.</param>
            /// <param name="second">The second object to check.</param>
            /// <returns>True if a collision was detected, false otherwise.</returns>
            /// <remarks>
            /// https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
            ///
            ///    Ax,Ay                    Bx,By
            ///      ---------------          ---------------
            ///      -             -          -             -
            ///      -             -          -             -
            ///      -             -          -             -
            ///      -             -          -             -
            ///      ---------------          ---------------
            ///                  AX,AY                     BX,BY
            ///
            /// They are seperate if any of these statements are true:
            ///
            ///  AX is less than Bx
            ///  BX is less than Ax
            ///  AY is less than By
            ///  BY is less than Ay
            ///
            /// </remarks>
            public static CollisionResult CheckForCollision(ICollidable first, ICollidable second, Vector2 velocity)
            {
                if (first == null)
                                {
                                        throw new ArgumentNullException("first");
                                }

                                if (second == null)
                                {
                                        throw new ArgumentNullException("second");
                                }

                                Rectangle a = first.BoundingBox;
                                Rectangle b = second.BoundingBox;

                                //bool haveCollided = !(a.Right < b.X
                                //         || b.Right < a.X
                                //         || a.Bottom < b.Y
                                //         || b.Bottom < a.Y);

                                bool haveCollided = (a.Right > b.X && b.Right > a.X && a.Bottom > b.Y && b.Bottom > a.Y);

                                a.Offset(Convert.ToInt32(velocity.X), Convert.ToInt32(velocity.Y));
                                bool willCollided = (a.Right > b.X && b.Right > a.X && a.Bottom > b.Y && b.Bottom > a.Y);

                                CollisionResult collisionResult = new CollisionResult();
                                collisionResult.HaveCollided = haveCollided;
                                collisionResult.WillCollide = willCollided;
                                collisionResult.CorrectionVector = null;
                                return collisionResult;
            }
Example #2
0
		public static bool circleToCircle( Circle first, Circle second, out CollisionResult result )
		{
			result = new CollisionResult();

			// avoid the square root until we actually need it
			var distanceSquared = Vector2.DistanceSquared( first.position, second.position );
			var sumOfRadii = first.radius + second.radius;
			var collided = distanceSquared < sumOfRadii * sumOfRadii;
			if( collided )
			{
				result.normal = Vector2.Normalize( first.position - second.position );
				var depth = sumOfRadii - Mathf.sqrt( distanceSquared );
				result.minimumTranslationVector = -depth * result.normal;
				result.point = second.position + result.normal * second.radius;

				// this gets the actual point of collision which may or may not be useful so we'll leave it here for now
				//var collisionPointX = ( ( first.position.X * second.radius ) + ( second.position.X * first.radius ) ) / sumOfRadii;
				//var collisionPointY = ( ( first.position.Y * second.radius ) + ( second.position.Y * first.radius ) ) / sumOfRadii;
				//result.point = new Vector2( collisionPointX, collisionPointY );

				return true;
			}

			return false;
		}
Example #3
0
	void	OnTriggerEnter(Collider other)
	{
		if(other.gameObject.layer == LayerMask.NameToLayer("Enemy")) {

			CollisionResult	result = new CollisionResult();

			result.object0 = this.gameObject;
			result.object1 = other.gameObject;
			result.is_trigger = false;

			this.collision_results.Add(result);

		} else if(other.gameObject.layer == LayerMask.NameToLayer("EnemyLair")) {

			CollisionResult	result = new CollisionResult();

			result.object0 = this.gameObject;
			result.object1 = other.gameObject;
			result.is_trigger = false;

			this.collision_results.Add(result);

		} else if(other.gameObject.layer == LayerMask.NameToLayer("Wall")) {

			CollisionResult	result = new CollisionResult();

			result.object0 = this.gameObject;
			result.object1 = other.gameObject;
			result.is_trigger = false;

			this.collision_results.Add(result);
		}
	}
Example #4
0
File: Box.cs Project: RastaCow/Nez
        public override bool collidesWithShape( Shape other, out CollisionResult result )
        {
            // special, high-performance cases. otherwise we fall back to Polygon.
            if( other is Box )
                return ShapeCollisions.boxToBox( this, other as Box, out result );

            // TODO: get Minkowski working for circle to box
            //if( other is Circle )

            // fallthrough to standard cases
            return base.collidesWithShape( other, out result );
        }
Example #5
0
        public override bool collidesWithShape( Shape other, out CollisionResult result )
        {
            if( other is Box )
                return ShapeCollisions.circleToBox( this, other as Box, out result );

            if( other is Circle )
                return ShapeCollisions.circleToCircle( this, other as Circle, out result );

            if( other is Polygon )
                return ShapeCollisions.circleToPolygon( this, other as Polygon, out result );

            throw new NotImplementedException( string.Format( "Collisions of Circle to {0} are not supported", other ) );
        }
Example #6
0
		public static bool pointToBox( Vector2 point, Box box, out CollisionResult result )
		{
			result = new CollisionResult();

			if( box.containsPoint( point ) )
			{
				// get the point in the space of the Box
				result.point = box.bounds.getClosestPointOnRectangleBorderToPoint( point, out result.normal );
				result.minimumTranslationVector = point - result.point;

				return true;
			}

			return false;
		}
        /// <summary>
        /// Crear inicializado
        /// </summary>
        public ElipsoidCollisionManager()
        {
            gravityEnabled = true;
            gravityForce = new Vector3(0, -10, 0);
            slideFactor = 1.3f;
            movementSphere = new TgcBoundingSphere();
            eSphere = new TgcBoundingSphere();
            objetosCandidatos = new List<Collider>();
            onGroundMinDotValue = 0.72f;

            result = new CollisionResult();
            result.collisionFound = false;
            result.collisionNormal = Vector3.Empty;
            result.collisionPoint = Vector3.Empty;
            result.realMovmentVector = Vector3.Empty;
        }
Example #8
0
        public override bool collidesWithShape( Shape other, out CollisionResult result )
        {
            if( other is Polygon )
                return ShapeCollisions.polygonToPolygon( this, other as Polygon, out result );

            if( other is Circle )
            {
                if( ShapeCollisions.circleToPolygon( other as Circle, this, out result ) )
                {
                    result.invertResult();
                    return true;
                }
                return false;
            }

            throw new NotImplementedException( string.Format( "overlaps of Polygon to {0} are not supported", other ) );
        }
Example #9
0
		public static bool pointToPoly( Vector2 point, Polygon poly, out CollisionResult result )
		{
			result = new CollisionResult();

			if( poly.containsPoint( point ) )
			{
				float distanceSquared;
				var closestPoint = Polygon.getClosestPointOnPolygonToPoint( poly.points, point - poly.position, out distanceSquared, out result.normal );

				result.minimumTranslationVector = result.normal * Mathf.sqrt( distanceSquared );
				result.point = closestPoint + poly.position;

				return true;
			}

			return false;
		}
Example #10
0
	// 컬리전에 히트하는 동안 호출되는 메소드.
	void 	OnCollisionStay(Collision other)
	{
		switch(other.gameObject.tag) {

			case "Item":
			case "Enemy":
			case "Boss":
			{
				CollisionResult	result = new CollisionResult();
		
				result.object0    = this.gameObject;
				result.object1    = other.gameObject;
				result.is_trigger = false;

				CollisionManager.getInstance().results.Add(result);
			}
			break;
		}
	}
Example #11
0
		public static bool pointToCircle( Vector2 point, Circle circle, out CollisionResult result )
		{
			result = new CollisionResult();

			// avoid the square root until we actually need it
			var distanceSquared = Vector2.DistanceSquared( point, circle.position );
			var sumOfRadii = 1 + circle.radius;
			var collided = distanceSquared < sumOfRadii * sumOfRadii;
			if( collided )
			{
				result.normal = Vector2.Normalize( point - circle.position );
				var depth = sumOfRadii - Mathf.sqrt( distanceSquared );
				result.minimumTranslationVector = -depth * result.normal;
				result.point = circle.position + result.normal * circle.radius;

				return true;
			}

			return false;
		}
Example #12
0
        public static bool boxToBox( Box first, Box second, out CollisionResult result )
        {
            result = new CollisionResult();

            var minkowskiDiff = minkowskiDifference( first, second );
            if( minkowskiDiff.contains( 0f, 0f ) )
            {
                // calculate the MTV. if it is zero then we can just call this a non-collision
                result.minimumTranslationVector = minkowskiDiff.getClosestPointOnBoundsToOrigin();

                if( result.minimumTranslationVector == Vector2.Zero )
                    return false;

                result.normal = -result.minimumTranslationVector;
                result.normal.Normalize();

                return true;
            }

            return false;
        }
Example #13
0
		/// <summary>
		/// works for circles whos center is in the box as well as just overlapping with the center out of the box.
		/// </summary>
		/// <returns><c>true</c>, if to box was circled, <c>false</c> otherwise.</returns>
		/// <param name="circle">First.</param>
		/// <param name="box">Second.</param>
		/// <param name="result">Result.</param>
		public static bool circleToBox( Circle circle, Box box, out CollisionResult result )
		{
			result = new CollisionResult();

			var closestPointOnBounds = box.bounds.getClosestPointOnRectangleBorderToPoint( circle.position, out result.normal );

			// deal with circles whos center is in the box first since its cheaper to see if we are contained
			if( box.containsPoint( circle.position ) )
			{
				result.point = closestPointOnBounds;

				// calculate mtv. Find the safe, non-collided position and get the mtv from that.
				var safePlace = closestPointOnBounds + result.normal * circle.radius;
				result.minimumTranslationVector = circle.position - safePlace;

				return true;
			}

			float sqrDistance;
			Vector2.DistanceSquared( ref closestPointOnBounds, ref circle.position, out sqrDistance );

			// see if the point on the box is less than radius from the circle
			if( sqrDistance == 0 )
			{
				result.minimumTranslationVector = result.normal * circle.radius;
			}
			else if( sqrDistance <= circle.radius * circle.radius )
			{
				result.normal = circle.position - closestPointOnBounds;
				var depth = result.normal.Length() - circle.radius;

				result.point = closestPointOnBounds;
				Vector2Ext.normalize( ref result.normal );
				result.minimumTranslationVector = depth * result.normal;

				return true;
			}

			return false;
		}
Example #14
0
	void 	OnCollisionEnter(Collision other)
	{
		switch(other.gameObject.tag) {

			case "Player":
			case "Wall":
			{
				CollisionResult	result = new CollisionResult();
		
				result.object0    = this.gameObject;
				result.object1    = other.gameObject;
				result.is_trigger = false;

				if(other.contacts.Length > 0) {

					result.option0 = (object)other.contacts[0];
				}

				this.control.collision_results.Add(result);

			}
			break;
		}
	}
Example #15
0
        /// <summary>
        /// note: if circle center lies in the box the collision result will be incorrect!
        /// </summary>
        /// <returns><c>true</c>, if to box was circled, <c>false</c> otherwise.</returns>
        /// <param name="first">First.</param>
        /// <param name="second">Second.</param>
        /// <param name="result">Result.</param>
        public static bool circleToBox( Circle first, Box second, out CollisionResult result )
        {
            result = new CollisionResult();

            var closestPointOnBounds = second.bounds.getClosestPointOnRectangleBorderToPoint( first.position );

            float sqrDistance;
            Vector2.DistanceSquared( ref closestPointOnBounds, ref first.position, out sqrDistance );

            // see if the point on the box is less than radius from the circle
            if( sqrDistance <= first.radius * first.radius )
            {
                var distanceToCircle = first.position - closestPointOnBounds;
                var depth = distanceToCircle.Length() - first.radius;

                result.point = closestPointOnBounds;
                result.normal = Vector2.Normalize( distanceToCircle );
                result.minimumTranslationVector = depth * result.normal;

                return true;
            }

            return false;
        }
Example #16
0
        // something isnt right here with this one
        static bool circleToPolygon2( Circle circle, Polygon polygon, out CollisionResult result )
        {
            result = new CollisionResult();

            var closestPointIndex = -1;
            var poly2Circle = circle.position - polygon.position;
            var poly2CircleNormalized = Vector2.Normalize( poly2Circle );
            var max = float.MinValue;

            for( var i = 0; i < polygon.points.Length; i++ )
            {
                var projection = Vector2.Dot( polygon.points[i], poly2CircleNormalized );
                if( max < projection )
                {
                    closestPointIndex = i;
                    max = projection;
                }
            }

            var poly2CircleLength = poly2Circle.Length();
            if( poly2CircleLength - max - circle.radius > 0 && poly2CircleLength > 0 )
                return false;

            // we have a collision
            // find the closest point on the polygon. we know the closest index so we only have 2 edges to test
            var prePointIndex = closestPointIndex - 1;
            var postPointIndex = closestPointIndex + 1;

            // handle wrapping the points
            if( prePointIndex < 0 )
                prePointIndex = polygon.points.Length - 1;

            if( postPointIndex == polygon.points.Length )
                postPointIndex = 0;

            var circleCenter = circle.position - polygon.position;
            var closest1 = closestPointOnLine( polygon.points[prePointIndex], polygon.points[closestPointIndex], circleCenter );
            var closest2 = closestPointOnLine( polygon.points[closestPointIndex], polygon.points[postPointIndex], circleCenter );
            float distance1, distance2;
            Vector2.DistanceSquared( ref circleCenter, ref closest1, out distance1 );
            Vector2.DistanceSquared( ref circleCenter, ref closest2, out distance2 );

            var radiusSquared = circle.radius * circle.radius;

            float seperationDistance;
            if( distance1 < distance2 )
            {
                // make sure the squared distance is less than our radius squared else we are not colliding
                if( distance1 > radiusSquared )
                    return false;

                seperationDistance = circle.radius - Mathf.sqrt( distance1 );
                var edge = polygon.points[closestPointIndex] - polygon.points[prePointIndex];
                result.normal = new Vector2( edge.Y, -edge.X );
                result.point = polygon.position + closest1;
            }
            else
            {
                // make sure the squared distance is less than our radius squared else we are not colliding
                if( distance2 > radiusSquared )
                    return false;

                seperationDistance = circle.radius - Mathf.sqrt( distance2 );
                var edge = polygon.points[postPointIndex] - polygon.points[closestPointIndex];
                result.normal = new Vector2( edge.Y, -edge.X );
                result.point = polygon.position + closest2;
            }

            result.normal.Normalize();
            result.minimumTranslationVector = result.normal * -seperationDistance;

            return true;
        }
Example #17
0
        /// <summary>
        /// does an overlap check of first vs second. ShapeCollisionResult retuns the data for moving first so it isn't colliding with second.
        /// </summary>
        /// <returns><c>true</c>, if to polygon was polygoned, <c>false</c> otherwise.</returns>
        /// <param name="first">First.</param>
        /// <param name="second">Second.</param>
        /// <param name="result">Result.</param>
        public static bool polygonToPolygon( Polygon first, Polygon second, out CollisionResult result )
        {
            result = new CollisionResult();
            float timeOfCollision;

            if( polygonToPolygon( first, second, null, out result.normal, out timeOfCollision ) )
            {
                result.minimumTranslationVector = result.normal * ( timeOfCollision );
                return true;
            }

            return false;
        }
Example #18
0
        public static bool circleToPolygon( Circle circle, Polygon polygon, out CollisionResult result )
        {
            result = new CollisionResult();

            // circle position in the polygons coordinates
            var poly2Circle = circle.position - polygon.position;

            // first, we need to find the closest distance from the circle to the polygon
            float distanceSquared;
            var closestPoint = polygon.getClosestPointOnPolygonToPoint( poly2Circle, out distanceSquared, out result.normal );

            // make sure the squared distance is less than our radius squared else we are not colliding
            if( distanceSquared > circle.radius * circle.radius )
                return false;

            // figure out the mtd
            var distance = Mathf.sqrt( distanceSquared );
            var mtv = ( poly2Circle - closestPoint ) * ( ( circle.radius - distance ) / distance );

            result.minimumTranslationVector = -mtv;
            result.normal.Normalize();

            return true;
        }
Example #19
0
	public void		removeResult(CollisionResult result)
	{
		this.results.Remove(result);
	}
Example #20
0
	void 	OnTriggerEnter(Collider other)
	{
		// 여분의 것과 맞지 않는 설정이므로 일단 쌓아 버린다.
		CollisionResult	result = new CollisionResult();
		
		result.object0 = this.gameObject;
		result.object1 = other.gameObject;
		result.is_trigger = false;
		
		this.collision_results.Add(result);
	}
        /// <summary>
        /// Detección de colisiones recursiva
        /// </summary>
        /// <param name="eSphere">Sphere de radio 1 pasada a Elipsoid space</param>
        /// <param name="eMovementVector">Movimiento pasado a Elipsoid space</param>
        /// <param name="eRadius">Radio de la elipsoide</param>
        /// <param name="colliders">Objetos contra los cuales colisionar</param>
        /// <param name="recursionDepth">Nivel de recursividad</param>
        /// <param name="movementSphere">Esfera real que representa el movimiento abarcado</param>
        /// <param name="slidingMinY">Minimo valor de normal Y de colision para hacer sliding</param>
        /// <returns>Resultado de colision</returns>
        public CollisionResult doCollideWithWorld(TgcBoundingSphere eSphere, Vector3 eMovementVector, Vector3 eRadius, List<Collider> colliders, int recursionDepth, TgcBoundingSphere movementSphere, float slidingMinY)
        {
            CollisionResult result = new CollisionResult();
            result.collisionFound = false;

            //Limitar recursividad
            if (recursionDepth > 5)
            {
                return result;
            }

            //Posicion deseada
            Vector3 nextSphereCenter = eSphere.Center + eMovementVector;

            //Buscar el punto de colision mas cercano de todos los objetos candidatos
            Vector3 q;
            float t;
            Vector3 n;
            float minT = float.MaxValue;
            foreach (Collider collider in colliders)
            {
                //Colisionar Sphere en movimiento contra Collider (cada Collider resuelve la colision)
                if (collider.intersectMovingElipsoid(eSphere, eMovementVector, eRadius, movementSphere, out t, out q, out n))
                {
                    //Quedarse con el menor instante de colision
                    if(t < minT)
                    {
                        minT = t;
                        result.collisionFound = true;
                        result.collisionPoint = q;
                        result.collisionNormal = n;
                        result.collider = collider;
                    }
                }
            }

            //Si nunca hubo colisión, avanzar todo lo requerido
            if (!result.collisionFound)
            {
                //Avanzar todo lo pedido
                eSphere.moveCenter(eMovementVector);
                result.realMovmentVector = eMovementVector;
                result.collisionNormal = Vector3.Empty;
                result.collisionPoint = Vector3.Empty;
                result.collider = null;
                return result;
            }


            //Solo movernos si ya no estamos muy cerca
            if (minT >= EPSILON)
            {
                //Restar un poco al instante de colision, para movernos hasta casi esa distancia
                minT -= EPSILON;
                result.realMovmentVector = eMovementVector * minT;
                eSphere.moveCenter(result.realMovmentVector);

                //Quitarle al punto de colision el EPSILON restado al movimiento, para no afectar al plano de sliding
                Vector3 v = Vector3.Normalize(result.realMovmentVector);
                result.collisionPoint -= v * EPSILON;
            }


            //Calcular plano de Sliding, como un plano tangete al punto de colision con la esfera, apuntando hacia el centro de la esfera
            Vector3 slidePlaneOrigin = result.collisionPoint;
            Vector3 slidePlaneNormal = eSphere.Center - result.collisionPoint;
            slidePlaneNormal.Normalize();
            Plane slidePlane = Plane.FromPointNormal(slidePlaneOrigin, slidePlaneNormal);

            //Calcular vector de movimiento para sliding, proyectando el punto de destino original sobre el plano de sliding
            float distance = TgcCollisionUtils.distPointPlane(nextSphereCenter, slidePlane);
            Vector3 newDestinationPoint = nextSphereCenter - distance * slidePlaneNormal;
            Vector3 slideMovementVector = newDestinationPoint - result.collisionPoint;

            //No hacer recursividad si es muy pequeño
            slideMovementVector.Scale(slideFactor);
            if (slideMovementVector.Length() < EPSILON)
            {
                return result;
            }

            //Ver si posee la suficiente pendiente en Y para hacer sliding
            if (result.collisionNormal.Y <= slidingMinY)
            {
                //Recursividad para aplicar sliding
                doCollideWithWorld(eSphere, slideMovementVector, eRadius, colliders, recursionDepth + 1, movementSphere, slidingMinY);
            }

            
            return result;
        }
Example #22
0
File: Box.cs Project: prime31/Nez
		public override bool pointCollidesWithShape( Vector2 point, out CollisionResult result )
		{
			if( isUnrotated )
				return ShapeCollisions.pointToBox( point, this, out result );

			return base.pointCollidesWithShape( point, out result );
		}
Example #23
0
        /// <summary>
        /// Verifica si este poligono esta colisionando o va a colisionar
        /// con una esféra dada.
        /// Para esto se ubica el punto centro de la esfera en la región de voronoi
        /// que le corresponde según el poligono, de forma que obtenemos el punto
        /// mas cercano de la esfera al poligono junto al respectivo eje.
        /// </summary>
        /// <param name="sphere">Esféra 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 IntersectWithSphere(Sphere sphere, ref Vector2 distance)
        {
            CollisionResult result = new CollisionResult();
            result.triggeringBody = this;
            result.affectedBody = sphere;
            // Empezamos asumiendo que las dos figuras no
            // se encuentran intersectando
            result.intersect = false;
            result.willIntersect = false;
            // Se toman tanto la cantidad de puntos
            // como la cantidad de lados del poligono
            int sideCountPolygon = this.sides.Count;
            int pointCountPolygon = this.vertices.Count;
            // Dos valores distintos para guardar
            float minIntervalDistanceAfterMove = float.PositiveInfinity;
            float minIntervalDistance = float.PositiveInfinity;
            Vector2 translationAxis = new Vector2();

            // Ahora se estudia cada lado del poligono para verificar si el centro
            // de la esfera se encuentra perpendicular a algun punto de ese lado
            for (int sideIndex = 0; sideIndex < sideCountPolygon; sideIndex++)
            {
                Line currentSide = this.sides[sideIndex];

                // Se crea un vector paralelo al lado donde puedan proyectase
                // ambos puntos del lado actual mas el centro de la esfera
                Vector2 axis = new Vector2(currentSide.Edge.X, currentSide.Edge.Y);
                axis.Normalize();

                float minA = Vector2.Dot(axis, currentSide.StartPoint);
                float maxA = Vector2.Dot(axis, currentSide.EndPoint);
                float centerB = Vector2.Dot(axis, sphere.Center);

                float velocityProjection = Vector2.Dot(axis, distance);

                // Se realiza un chequeo preliminar antes de sumar el vector
                // de distancia
                #region Verificaciones de intersección actual

                // Si el punto centro se encuentra perpendicular a algun
                // punto del lado actual, entonces la esfera puede encontrarse en esa region
                if (minA <= centerB && maxA >= centerB)
                {
                    // Creamos un eje perpendicular a la linea para obtener la distancia
                    // entre un punto de la linea y el centro de la esfera
                    axis = new Vector2(-currentSide.Edge.Y, currentSide.Edge.X);
                    axis.Normalize();

                    // Ya que el eje es perpendicular, tanto el punto inicial de la linea
                    // como el final terminan en la misma posicion al ser proyectados
                    float pointA = Vector2.Dot(axis, currentSide.EndPoint);
                    float pointB = Vector2.Dot(axis, sphere.Center);

                    // Se obtiene el intervalo y se guarda en caso de que sea menor
                    // al intervalo anterior (La esfera se encontrara en la region de voronoi
                    // que tenga el punto mas cercano desde la esfera hacia el poligono)
                    float intervalDistance = Math.Abs(pointA - pointB);
                    if (intervalDistance < minIntervalDistance)
                    {
                        minIntervalDistance = intervalDistance;
                    }
                }
                #endregion

                // Aplicamos la proyeccion de velocidad a el lado actual
                if (velocityProjection < 0)
                {
                    minA += velocityProjection;
                }
                else
                {
                    maxA += velocityProjection;
                }

                // Si el punto centro se encuentra perpendicular a algun
                // punto del lado actual, entonces la esfera puede encontrarse en esa region
                if (minA <= centerB && maxA >= centerB)
                {
                    // Creamos un eje perpendicular a la linea para obtener la distancia
                    // entre un punto de la linea y el centro de la esfera
                    axis = new Vector2(-currentSide.Edge.Y, currentSide.Edge.X);
                    axis.Normalize();

                    // Volvemos a aplicar la proyeccion de velocidad puesto que
                    // esta vez estamos proyectando en un diferente eje
                    velocityProjection = Vector2.Dot(axis, distance);
                    // Ya que el eje es perpendicular, tanto el punto inicial de la linea
                    // como el final terminan en la misma posicion al ser proyectados
                    float pointA = Vector2.Dot(axis, currentSide.EndPoint) + velocityProjection;
                    float pointB = Vector2.Dot(axis, sphere.Center);

                    // Se obtiene el intervalo y se guarda en caso de que sea menor
                    // al intervalo anterior (La esfera se encontrara en la region de voronoi
                    // que tenga el punto mas cercano desde la esfera hacia el poligono)
                    float intervalDistance = Math.Abs(pointA - pointB);
                    if (intervalDistance < minIntervalDistanceAfterMove)
                    {
                        minIntervalDistanceAfterMove = intervalDistance;
                        translationAxis = axis;

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

            // Luego se estudia la distancia entre cada vertice del poligono
            // contra el centro de la esfera, si se encuentra alguna distancia
            // menor que las ya guardadas entonces se guarda
            for (int pointIndex = 0; pointIndex < pointCountPolygon; pointIndex++)
            {
                Vector2 currentPoint = this.vertices[pointIndex];
                // Creamos una linea que vaya desde el vertice hasta el centro
                // de la esfera, sumandole el vector de distancia al vertice
                Line line = new Line(currentPoint + distance, sphere.Center);

                Vector2 axis = new Vector2(line.Edge.X, line.Edge.Y);
                axis.Normalize();

                if (line.Lenght < minIntervalDistanceAfterMove)
                {
                    minIntervalDistanceAfterMove = line.Lenght;
                    translationAxis = axis;

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

                // Misma verificacion sin sumar el vector de distancia
                #region Verificaciones de intersección actual
                line = new Line(currentPoint, sphere.Center);

                axis = new Vector2(line.Edge.X, line.Edge.Y);
                axis.Normalize();

                if (line.Lenght < minIntervalDistance)
                {
                    minIntervalDistance = line.Lenght;
                }
                #endregion
            }

            // Se verifica si el poligono intersecta
            bool isInside = this.PointInBody(sphere.Center);
            if (isInside || minIntervalDistance < sphere.Radius)
            {
                result.intersect = true;
            }

            // Se verifica si intersectaran y aplica un vector de transicion
            // diferente dependiendo de si el centro de la esfera se encuentra
            // dentro o fuera del poligono
            isInside = this.PointInBody(sphere.Center - distance);
            if (isInside)
            {
                result.minimumTranslationVector =
                       translationAxis * (sphere.Radius + minIntervalDistanceAfterMove);
                result.willIntersect = true;
            }
            else if (minIntervalDistanceAfterMove < sphere.Radius)
            {
                result.minimumTranslationVector =
                       translationAxis * Math.Abs(sphere.Radius - minIntervalDistanceAfterMove);
                result.willIntersect = true;
            }

            result.translationAxis = translationAxis;
            return result;
        }
Example #24
0
        /// <summary>
        /// Verifica si este poligono esta colisionando o va a colisionar
        /// con otro poligono 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="polygon2">Segundo poligono con el cual se hará la verificacion</param>
        /// <param name="distance">Distancia por la cual se movera el poligono 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 IntersectWithPolygon(Polygon polygon2, ref Vector2 distance)
        {
            CollisionResult result = new CollisionResult();
            result.triggeringBody = this;
            result.affectedBody = polygon2;
            // Se asume que ambos poligonos intersectan hasta que
            // se pueda demostrar lo contrario
            result.intersect = true;
            result.willIntersect = true;
            // Se obtiene la cantidad de lados del poligono principal
            // y del segundo poligono
            int sideCountA = this.sides.Count;
            int sideCountB = polygon2.Sides.Count;
            float minIntervalDistance = float.PositiveInfinity;
            Vector2 translationAxis = new Vector2();
            // Lado actual a analizar
            Line currentSide;

            // Se realiza una verificacion por cada uno de los lados de ambos poligonos
            // hasta que pueda encontrarse alguna separación entre ambos o hasta que se hayan
            // verificado todos los lados
            for (int sideIndex = 0; sideIndex < sideCountA + sideCountB; sideIndex++)
            {
                if (sideIndex < sideCountA)
                {
                    currentSide = this.sides[sideIndex];
                }
                else
                {
                    currentSide = polygon2.Sides[sideIndex - sideCountA];
                }
                // 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 ambos poligonos sobre el mismo eje
                float minA = 0; float minB = 0; float maxA = 0; float maxB = 0;
                this.Project(ref axis, out minA, out maxA);
                polygon2.Project(ref axis, out minB, out maxB);

                // Se obtiene el intervalo entre ambos poligonos sobre el eje,
                // si el intervalo (separación) es mayor a 0 entonces los poligonos
                // 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 los poligonos tambien intersectaran al moverse
                intervalDistance = IntervalDistance(minA, maxA, minB, maxB);
                if (intervalDistance > 0) result.willIntersect = false;

                // Si ya sabemos que los poligonos 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 poligonos en esa dirección
                intervalDistance = Math.Abs(intervalDistance);
                if (intervalDistance < minIntervalDistance)
                {
                    minIntervalDistance = intervalDistance;
                    translationAxis = axis;

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

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

            result.translationAxis = translationAxis;
            return result;
        }
Example #25
0
	protected	void	on_trigger_common(Collider other)
	{
		switch(other.gameObject.tag) {

			case "Door":
			{
				CollisionResult	result = new CollisionResult();
		
				result.object0    = this.gameObject;
				result.object1    = other.gameObject;
				result.is_trigger = false;

				CollisionManager.getInstance().results.Add(result);
			}
			break;
		}
	}
Example #26
0
	void	Update()
	{
		this.resolve_collision();

		float	explode_time = 0.5f;

		// ---------------------------------------------------------------- //
		// 다음 상태로 전환할지 체크한다.

		switch(this.step.do_transition()) {

			case STEP.FLYING:
			{
				if(this.trigger_damage) {

					this.step.set_next(STEP.EXPLODE);
				}
			}
			break;

			case STEP.EXPLODE:
			{
				//if(this.explode_effect == null) {
				if(this.step.get_time() > explode_time) {

					this.step.set_next(STEP.END);
				}
			}
			break;
		}

		// ---------------------------------------------------------------- //
		// 상태 전환 시 초기화.

		while(this.step.get_next() != STEP.NONE) {

			switch(this.step.do_initialize()) {
	
				case STEP.FLYING:
				{
				}
				break;

				case STEP.EXPLODE:
				{
					this.model_node.GetComponent<Renderer>().enabled = false;
					this.explode_effect = EffectRoot.get().createYuzuExplode(this.gameObject.getPosition().Y(0.5f));

					this.coli_node.setLocalScale(Vector3.one*this.max_radius*0.0f);
				}
				break;

				case STEP.END:
				{
					this.gameObject.destroy();
				}
				break;
			}
		}

		// ---------------------------------------------------------------- //
		// 각 상태에서의 실행 처리.

		switch(this.step.do_execution(Time.deltaTime)) {

			case STEP.FLYING:
			{
				// 이동.
				this.velocity += Physics.gravity*Time.deltaTime;
				this.transform.position += this.velocity*Time.deltaTime;
			}
			break;

			case STEP.EXPLODE:
			{
				float	rate = this.step.get_time()/explode_time;

				float	scale = rate*this.max_radius;

				this.coli_node.setLocalScale(Vector3.one*scale);

				// 폭풍과의 충돌.
				// 콜라이더가 바닥에 충돌하면 그 다음 폭풍이 충돌해도 OnTriggerEnter가.
				// 호출되지 않으므로 직접 조사한다.

				RaycastHit	hit;

				if(Physics.SphereCast(this.transform.position, scale*this.coli_sphere_radius, Vector3.up, out hit, float.MinValue, LayerMask.GetMask("Enemy", "EnemyLair"))) {

					CollisionResult	result = new CollisionResult();
		
					result.object0 = this.gameObject;
					result.object1 = hit.collider.gameObject;
					result.is_trigger = true;
		
					this.collision_results.Add(result);
				}

			}
			break;
		}
	}
        /// <summary>
        /// Mover Elipsoide con detección de colisiones, sliding y gravedad.
        /// Se actualiza la posición del centro del Elipsoide
        /// </summary>
        /// <param name="characterElipsoid">Elipsoide del cuerpo a mover</param>
        /// <param name="movementVector">Movimiento a realizar</param>
        /// <param name="colliders">Obstáculos contra los cuales se puede colisionar</param>
        /// <returns>Desplazamiento relativo final efecutado al Elipsoide</returns> 
        public Vector3 moveCharacter(TgcElipsoid characterElipsoid, Vector3 movementVector, List<Collider> colliders)
        {
            //Guardar posicion original del Elipsoide
            Vector3 originalElipsoidCenter = characterElipsoid.Center;

            //Pasar elipsoid space
            Vector3 eCenter = TgcVectorUtils.div(characterElipsoid.Center, characterElipsoid.Radius);
            Vector3 eMovementVector = TgcVectorUtils.div(movementVector, characterElipsoid.Radius);
            eSphere.setValues(eCenter, 1);
            Vector3 eOrigCenter = eSphere.Center;


            //Ver si la distancia a recorrer es para tener en cuenta
            float distanceToTravelSq = movementVector.LengthSq();
            if (distanceToTravelSq >= EPSILON)
            {
                //Mover la distancia pedida
                selectPotentialColliders(characterElipsoid, movementVector, colliders);
                this.result = doCollideWithWorld(eSphere, eMovementVector, characterElipsoid.Radius, objetosCandidatos, 0, movementSphere, 1);
            }

            //Aplicar gravedad
            if (gravityEnabled)
            {
                //Mover con gravedad
                Vector3 eGravity = TgcVectorUtils.div(gravityForce, characterElipsoid.Radius);
                selectPotentialColliders(characterElipsoid, eGravity, colliders);
                this.result = doCollideWithWorld(eSphere, eGravity, characterElipsoid.Radius, objetosCandidatos, 0, movementSphere, onGroundMinDotValue);
            }

            //Mover Elipsoid pasando valores de colision a R3
            Vector3 movement = TgcVectorUtils.mul(eSphere.Center - eOrigCenter, characterElipsoid.Radius);
            characterElipsoid.moveCenter(movement);

            //Ajustar resultados
            result.realMovmentVector = TgcVectorUtils.mul(result.realMovmentVector, characterElipsoid.Radius);
            result.collisionPoint = TgcVectorUtils.mul(result.collisionPoint, characterElipsoid.Radius);


            return movement;
        }
Example #28
0
		public static bool circleToPolygon( Circle circle, Polygon polygon, out CollisionResult result )
		{
			result = new CollisionResult();

			// circle position in the polygons coordinates
			var poly2Circle = circle.position - polygon.position;

			// first, we need to find the closest distance from the circle to the polygon
			float distanceSquared;
			var closestPoint = Polygon.getClosestPointOnPolygonToPoint( polygon.points, poly2Circle, out distanceSquared, out result.normal );

			// make sure the squared distance is less than our radius squared else we are not colliding. Note that if the Circle is fully
			// contained in the Polygon the distance could be larger than the radius. Because of that we also  make sure the circle position
			// is not inside the poly.
			var circleCenterInsidePoly = polygon.containsPoint( circle.position );
			if( distanceSquared > circle.radius * circle.radius && !circleCenterInsidePoly )
				return false;

			// figure out the mtv. We have to be careful to deal with circles fully contained in the polygon or with their center contained.
			Vector2 mtv;
			if( circleCenterInsidePoly )
			{
				mtv = result.normal * ( Mathf.sqrt( distanceSquared ) - circle.radius );
			}
			else
			{
				// if we have no distance that means the circle center is on the polygon edge. Move it only by its radius
				if( distanceSquared == 0 )
				{
					mtv = result.normal * circle.radius;
				}
				else
				{
					var distance = Mathf.sqrt( distanceSquared );
					mtv = -( poly2Circle - closestPoint ) * ( ( circle.radius - distance ) / distance );
				}
			}

			result.minimumTranslationVector = mtv;
			result.point = closestPoint + polygon.position;

			return true;
		}
Example #29
0
	void OnCollisionStay(Collision other)
	{
		switch(other.gameObject.tag) {

			case "Player":
			{
				chrBehaviorPlayer	player = other.gameObject.GetComponent<chrBehaviorPlayer>();

				if(player != null) {

					CollisionResult	result = new CollisionResult();
			
					result.object0    = this.gameObject;
					result.object1    = other.gameObject;
					result.is_trigger = false;
	
					this.collision_results.Add(result);
				}
			}
			break;
		}
	}
Example #30
0
		/// <summary>
		/// checks for a collision between two Polygons
		/// </summary>
		/// <returns>The collision.</returns>
		/// <param name="first">Polygon a.</param>
		/// <param name="second">Polygon b.</param>
		public static bool polygonToPolygon( Polygon first, Polygon second, out CollisionResult result )
		{
			result = new CollisionResult();
			var isIntersecting = true;

			var firstEdges = first.edgeNormals;
			var secondEdges = second.edgeNormals;
			var minIntervalDistance = float.PositiveInfinity;
			var translationAxis = new Vector2();
			var polygonOffset = first.position - second.position;
			Vector2 axis;

			// Loop through all the edges of both polygons
			for( var edgeIndex = 0; edgeIndex < firstEdges.Length + secondEdges.Length; edgeIndex++ )
			{
				// 1. Find if the polygons are currently intersecting
				// Polygons have the normalized axis perpendicular to the current edge cached for us
				if( edgeIndex < firstEdges.Length )
					axis = firstEdges[edgeIndex];
				else
					axis = secondEdges[edgeIndex - firstEdges.Length];

				// Find the projection of the polygon on the current axis
				float minA = 0; float minB = 0; float maxA = 0; float maxB = 0;
				var intervalDist = 0f;
				getInterval( axis, first, ref minA, ref maxA );
				getInterval( axis, second, ref minB, ref maxB );

				// get our interval to be space of the second Polygon. Offset by the difference in position projected on the axis.
				float relativeIntervalOffset;
				Vector2.Dot( ref polygonOffset, ref axis, out relativeIntervalOffset );
				minA += relativeIntervalOffset;
				maxA += relativeIntervalOffset;

				// check if the polygon projections are currentlty intersecting
				intervalDist = intervalDistance( minA, maxA, minB, maxB );
				if( intervalDist > 0 )
					isIntersecting = false;


				// for Poly-to-Poly casts add a Vector2? parameter called deltaMovement. In the interest of speed we do not use it here
				// 2. Now find if the polygons *will* intersect. only bother checking if we have some velocity
				//if( deltaMovement.HasValue )
				//{
				//	// Project the velocity on the current axis
				//	var velocityProjection = Vector2.Dot( axis, deltaMovement.Value );

				//	// Get the projection of polygon A during the movement
				//	if( velocityProjection < 0 )
				//		minA += velocityProjection;
				//	else
				//		maxA += velocityProjection;

				//	// Do the same test as above for the new projection
				//	intervalDist = intervalDistance( minA, maxA, minB, maxB );
				//	if( intervalDist > 0 )
				//		willIntersect = false;
				//}


				// If the polygons are not intersecting and won't intersect, exit the loop
				if( !isIntersecting )
					return false;

				// Check if the current interval distance is the minimum one. If so store the interval distance and the current distance.
				// This will be used to calculate the minimum translation vector
				intervalDist = Math.Abs( intervalDist );
				if( intervalDist < minIntervalDistance )
				{
					minIntervalDistance = intervalDist;
					translationAxis = axis;

					if( Vector2.Dot( translationAxis, polygonOffset ) < 0 )
						translationAxis = -translationAxis;
				}
			}

			// The minimum translation vector can be used to push the polygons appart.
			result.normal = translationAxis;
			result.minimumTranslationVector = -translationAxis * minIntervalDistance;

			return true;
		}