special case of a Polygon. When doing SAT collision checks we only need to check 2 axes instead of 8
Inheritance: Polygon
Beispiel #1
0
		/// <summary>
		/// zero param constructor requires that a RenderableComponent be on the entity so that the collider can size itself when the
		/// entity is added to the scene.
		/// </summary>
		public BoxCollider()
		{
			// we stick a 1x1 box in here as a placeholder until the next frame when the Collider is added to the Entity and can get more
			// accurate auto-sizing data
			shape = new Box( 1, 1 );
			_colliderRequiresAutoSizing = true;
		}
Beispiel #2
0
		public static bool intersectMovingCircleBox( Circle s, Box b, Vector2 movement, out float time )
		{
			// compute the AABB resulting from expanding b by sphere radius r
			var e = b.bounds;
			e.inflate( s.radius, s.radius );

			// Intersect ray against expanded expanded Rectangle e. Exit with no intersection if ray
			// misses e, else get intersection point p and time t as result
			var ray = new Ray2D( s.position - movement, s.position );
			if( !e.rayIntersects( ref ray, out time ) && time > 1.0f )
				return false;

			// get the intersection point
			var point = ray.start + ray.direction * time;

			// compute which min and max faces of b the intersection point p lies outside of. Note, u and v cannot have the
			// same bits set and they must have at least one bit set among them.
			int u = 0, v = 0;
			if( point.X < b.bounds.left )
				u |= 1;
			if( point.X > b.bounds.right )
				v |= 1;
			if( point.Y < b.bounds.top )
				u |= 2;
			if( point.Y > b.bounds.bottom )
				v |= 2;

			// 'or' all set bits together into a bitmask (note u + v == u | v)
			var m = u + v;

			// if all 3 bits are set then point is in a vertex region
			if( m == 3 )
			{
				// must now intersect segment against the capsules of the two edges meeting at the vert and return the best time,
				// if one or more hit
				// https://play.google.com/books/reader?printsec=frontcover&output=reader&id=VSoIBwAAAEAJ&pg=GBS.PA267
				// https://github.com/noonat/hello/blob/580b986f3bb27b93645087441d2744eeb99d6d35/hello/collisions/Collision.hx#L675
				//throw new NotImplementedException();
				Debug.log( "m == 3. corner {0}", Time.frameCount );
			}

			// if only one bit is set in m then point is in a face region
			if( ( m & ( m - 1 ) ) == 0 )
			{
				Debug.drawHollowBox( point, 4, Color.Black, 0.4f );
				// do nothing. time from the expanded rect intersection is the correct time
				return true;
			}

			// point is on an edge region. intersect against the capsule at the edge.

			return true;
		}
Beispiel #3
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;
		}
Beispiel #4
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;
        }
Beispiel #5
0
        /// <summary>
        /// checks the result of a box being moved by deltaMovement with second
        /// </summary>
        /// <returns><c>true</c>, if to box cast was boxed, <c>false</c> otherwise.</returns>
        /// <param name="first">First.</param>
        /// <param name="second">Second.</param>
        /// <param name="deltaMovement">Delta movement.</param>
        /// <param name="hit">Hit.</param>
        public static bool boxToBoxCast( Box first, Box second, Vector2 movement, out RaycastHit hit )
        {
            // http://hamaluik.com/posts/swept-aabb-collision-using-minkowski-difference/
            hit = new RaycastHit();

            // first we check for an overlap. if we have an overlap we dont do the sweep test
            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
                var mtv = minkowskiDiff.getClosestPointOnBoundsToOrigin();
                if( mtv == Vector2.Zero )
                    return false;

                hit.normal = -mtv;
                hit.normal.Normalize();
                hit.distance = 0f;
                hit.fraction = 0f;

                return true;
            }
            else
            {
                // ray-cast the movement vector against the Minkowski AABB
                var ray = new Ray2D( Vector2.Zero, -movement );
                float fraction;
                if( minkowskiDiff.rayIntersects( ref ray, out fraction ) && fraction <= 1.0f )
                {
                    hit.fraction = fraction;
                    hit.distance = movement.Length() * fraction;
                    hit.normal = -movement;
                    hit.normal.Normalize();
                    hit.centroid = first.bounds.center + movement * fraction;

                    return true;
                }
            }

            return false;
        }
Beispiel #6
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;
		}
Beispiel #7
0
 public BoxCollider( float x, float y, float width, float height )
 {
     _localOffset = new Vector2( x, y );
     shape = new Box( width, height );
 }
Beispiel #8
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;
        }
Beispiel #9
0
        static RectangleF minkowskiDifference( Box first, Box second )
        {
            var topLeft = first.position - second.bounds.max;
            var fullSize = first.bounds.size + second.bounds.size;

            return new RectangleF( topLeft.X, topLeft.Y, fullSize.X, fullSize.Y );
        }
Beispiel #10
0
 public RectangleF minkowskiDifference( Box other )
 {
     var topLeft = position - other.bounds.max;
     var fullSize = bounds.size + other.bounds.size;
     return new RectangleF( topLeft.X, topLeft.Y, fullSize.X, fullSize.Y );
 }
Beispiel #11
0
		static RectangleF minkowskiDifference( Box first, Box second )
		{
			// we need the top-left of our first box but it must include our motion. Collider only modifies position with the motion so we
			// need to figure out what the motion was using just the position.
			var positionOffset = first.position - ( first.bounds.location + first.bounds.size / 2f );
			var topLeft = first.bounds.location + positionOffset - second.bounds.max;
			var fullSize = first.bounds.size + second.bounds.size;

			return new RectangleF( topLeft.X, topLeft.Y, fullSize.X, fullSize.Y );
		}
Beispiel #12
0
		/// <summary>
		/// checks to see if circle overlaps box and returns (via out param) the point of intersection
		/// </summary>
		/// <returns><c>true</c>, if circle box was tested, <c>false</c> otherwise.</returns>
		/// <param name="circle">Circle.</param>
		/// <param name="box">Box.</param>
		/// <param name="point">Point.</param>
		public static bool testCircleBox( Circle circle, Box box, out Vector2 point )
		{
			// find the point closest to the sphere center
			point = box.bounds.getClosestPointOnRectangleFToPoint( circle.position );

			// circle and box intersect if sqr distance from circle center to point is less than the circle sqr radius
			var v = point - circle.position;
			float dist;
			Vector2.Dot( ref v, ref v, out dist );

			return dist <= circle.radius * circle.radius;
		}