136 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			136 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using Engine.Core;
 | 
						|
using Engine.Physics2D;
 | 
						|
 | 
						|
namespace Engine.Physics2D;
 | 
						|
 | 
						|
public class CollisionDetector2D : ICollisionDetector2D
 | 
						|
{
 | 
						|
    public bool TryDetect<T1, T2>(T1 left, T2 right, out CollisionDetectionInformation collisionInformation)
 | 
						|
        where T1 : ICollider2D
 | 
						|
        where T2 : ICollider2D
 | 
						|
    {
 | 
						|
        collisionInformation = default;
 | 
						|
        if (left is IShapeCollider2D shapeColliderLeft)
 | 
						|
        {
 | 
						|
            if (right is IShapeCollider2D shapeColliderRight)
 | 
						|
                return DetectShapeShape(shapeColliderLeft, shapeColliderRight, out collisionInformation);
 | 
						|
            else if (right is ICircleCollider2D circleColliderRight)
 | 
						|
                return DetectShapeCircle(shapeColliderLeft, circleColliderRight, out collisionInformation);
 | 
						|
        }
 | 
						|
        else if (left is ICircleCollider2D circleColliderLeft)
 | 
						|
        {
 | 
						|
            if (right is IShapeCollider2D shapeColliderRight)
 | 
						|
                return DetectCircleShape(circleColliderLeft, shapeColliderRight, out collisionInformation);
 | 
						|
            else if (right is ICircleCollider2D circleColliderRight)
 | 
						|
                return DetectCircleCircle(circleColliderLeft, circleColliderRight, out collisionInformation);
 | 
						|
        }
 | 
						|
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    private static bool DetectCircleShape(ICircleCollider2D circleCollider, IShapeCollider2D shapeCollider, out CollisionDetectionInformation collisionInformation)
 | 
						|
    {
 | 
						|
        return DetectShapeCircle(shapeCollider, circleCollider, out collisionInformation);
 | 
						|
    }
 | 
						|
 | 
						|
    private static bool DetectShapeShape(IShapeCollider2D left, IShapeCollider2D right, out CollisionDetectionInformation collisionInformation)
 | 
						|
    {
 | 
						|
        collisionInformation = default;
 | 
						|
        return DetectShapeShapeOneWay(left, right, ref collisionInformation) && DetectShapeShapeOneWay(right, left, ref collisionInformation);
 | 
						|
    }
 | 
						|
 | 
						|
    private static bool DetectShapeShapeOneWay(IShapeCollider2D left, IShapeCollider2D right, ref CollisionDetectionInformation collisionInformation)
 | 
						|
    {
 | 
						|
        System.Collections.Generic.IReadOnlyList<Vector2D> vertices = left.ShapeWorld.Vertices;
 | 
						|
        int count = vertices.Count;
 | 
						|
 | 
						|
        for (int indexProjection = 0; indexProjection < count; indexProjection++)
 | 
						|
        {
 | 
						|
            Vector2D projectionVector = vertices[indexProjection].FromTo(vertices[(indexProjection + 1) % count]).Perpendicular().Normalized;
 | 
						|
 | 
						|
            Projection1D leftProjection = left.ShapeWorld.ToProjection(projectionVector);
 | 
						|
            Projection1D rightProjection = right.ShapeWorld.ToProjection(projectionVector);
 | 
						|
 | 
						|
            if (!leftProjection.Overlaps(rightProjection, out float depth))
 | 
						|
                return false;
 | 
						|
 | 
						|
            if (collisionInformation.Detector is null || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth))
 | 
						|
                collisionInformation = new(left, right, projectionVector, depth);
 | 
						|
        }
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    private static bool DetectShapeCircle(IShapeCollider2D shapeCollider, ICircleCollider2D circleCollider, out CollisionDetectionInformation collisionInformation)
 | 
						|
    {
 | 
						|
        collisionInformation = default;
 | 
						|
 | 
						|
        System.Collections.Generic.IReadOnlyList<Vector2D> vertices = shapeCollider.ShapeWorld.Vertices;
 | 
						|
        int count = vertices.Count;
 | 
						|
 | 
						|
        for (int indexProjection = 0; indexProjection < count; indexProjection++)
 | 
						|
        {
 | 
						|
            Vector2D projectionVector = vertices[indexProjection].FromTo(vertices[(indexProjection + 1) % count]).Perpendicular().Normalized;
 | 
						|
 | 
						|
            Projection1D shapeProjection = shapeCollider.ShapeWorld.ToProjection(projectionVector);
 | 
						|
            Projection1D circleProjection = circleCollider.CircleWorld.ProjectTo(projectionVector);
 | 
						|
 | 
						|
            if (!shapeProjection.Overlaps(circleProjection, out float depth))
 | 
						|
                return false;
 | 
						|
 | 
						|
            if (collisionInformation.Detector is null || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth))
 | 
						|
                collisionInformation = new(shapeCollider, circleCollider, projectionVector, depth);
 | 
						|
        }
 | 
						|
 | 
						|
        {
 | 
						|
            Vector2D shapeToCircleProjectionVector = shapeCollider.Transform.Position.FromTo(circleCollider.CircleWorld.Center).Normalized;
 | 
						|
 | 
						|
            Projection1D shapeProjection = shapeCollider.ShapeWorld.ToProjection(shapeToCircleProjectionVector);
 | 
						|
            Projection1D circleProjection = circleCollider.CircleWorld.ProjectTo(shapeToCircleProjectionVector);
 | 
						|
 | 
						|
            if (!shapeProjection.Overlaps(circleProjection, out float depth))
 | 
						|
                return false;
 | 
						|
 | 
						|
            if (collisionInformation.Detector is null || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth))
 | 
						|
                collisionInformation = new(shapeCollider, circleCollider, shapeToCircleProjectionVector, depth);
 | 
						|
        }
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    private static bool DetectCircleCircle(ICircleCollider2D left, ICircleCollider2D right, out CollisionDetectionInformation collisionInformation)
 | 
						|
    {
 | 
						|
        collisionInformation = default;
 | 
						|
 | 
						|
        Vector2D leftToRightCenterProjectionVector = left.CircleWorld.Center.FromTo(right.CircleWorld.Center).Normalized;
 | 
						|
 | 
						|
        Projection1D leftProjection = left.CircleWorld.ProjectTo(leftToRightCenterProjectionVector);
 | 
						|
        Projection1D rightProjection = right.CircleWorld.ProjectTo(leftToRightCenterProjectionVector);
 | 
						|
 | 
						|
        bool collision = leftProjection.Overlaps(rightProjection, out float depth);
 | 
						|
 | 
						|
        if (collision)
 | 
						|
            collisionInformation = new(left, right, leftToRightCenterProjectionVector, depth);
 | 
						|
 | 
						|
        return collision;
 | 
						|
    }
 | 
						|
 | 
						|
    // private static bool DetectCircleCircle(ICircleCollider2D left, ICircleCollider2D right, out CollisionDetectionInformation collisionInformation)
 | 
						|
    // {
 | 
						|
    //     collisionInformation = default;
 | 
						|
 | 
						|
    //     Vector2D leftToRightCenter = left.CircleWorld.Center.FromTo(right.CircleWorld.Center);
 | 
						|
    //     float distanceCircleCenter = leftToRightCenter.Magnitude;
 | 
						|
    //     float radiusSum = left.CircleWorld.Radius + right.CircleWorld.Radius;
 | 
						|
 | 
						|
    //     float circleSurfaceDistance = distanceCircleCenter - radiusSum;
 | 
						|
 | 
						|
    //     bool collision = circleSurfaceDistance <= 0f;
 | 
						|
 | 
						|
    //     if (collision)
 | 
						|
    //         collisionInformation = new(left, right, leftToRightCenter.Normalized, -circleSurfaceDistance);
 | 
						|
 | 
						|
    //     return collision;
 | 
						|
    // }
 | 
						|
}
 |