How to create a 2d collision mask?

Basically I want to create a sprite mask, but not for sprites for 2d collisions. I have been searching everywhere for an answer or a hint but the only thing I’ve found so far is a youtube video by Berneyvonbean showcasing what I want to create:

In my platformer game there are ground objects (platforms) which collide with the player.

The mask colliders change the collision of the ground and where and when they appear is up to the player inputs.

I tried modifying the ground collider every time a new mask appeared or disappeared or when the masks’ positions related to the ground changed. I taught about trying the marching squares algorithm for this, but since there are so often changes with the masks and the ground in my game, then there would be times when I would have to modify the ground collider every frame for 3 seconds straight and I don’t think that’s efficient. (one example of this would be when a ground platform moves for three seconds)

Does anyone have a solution as how to create 2d collider masks in unity, that would be efficient in my case. I also point out, that I am a starter so I have basic knowledge of how to program using c# and how to work with unity, but more advanced stuff I may not understand.

@Shadow735 - I apologize for the delay in response, I seem to be the only active moderator these days, and I am trying to keep up, but I have been very busy lately.

Firstly, I would like to point out that if your goal is to create a dynamic collider that changes depending on user input or game conditions, you might need a slightly more complex solution than a simple collision mask. But, let’s describe it here anyway.

1. Creating a custom Collider2D

This method involves creating a PolygonCollider2D at runtime and updating its points to match the desired shape. For example, you can create a polygon collider that matches the shape of your mask. Here is a barebones approach to inspire you:

void CreateSquareCollider(GameObject obj) {
    PolygonCollider2D collider = obj.AddComponent<PolygonCollider2D>();
    collider.points = new Vector2[] {
        new Vector2(-1, 1),
        new Vector2(1, 1),
        new Vector2(1, -1),
        new Vector2(-1, -1)
    };
}

2. Creating a composite Collider2D

CompositeCollider2D can be used in combination with multiple Collider2D components on the same GameObject. It merges multiple colliders into a more efficient collider representation. This could be helpful if your ground is composed of many smaller objects or if the mask changes often. You can do it programmatically like this:

void SetupCompositeCollider(GameObject obj) {
    obj.AddComponent<Rigidbody2D>();
    var compositeCollider = obj.AddComponent<CompositeCollider2D>();
    var tilemapCollider = obj.AddComponent<TilemapCollider2D>();
    tilemapCollider.usedByComposite = true;
    compositeCollider.geometryType = CompositeCollider2D.GeometryType.Polygons;
    compositeCollider.generationType = CompositeCollider2D.GenerationType.Synchronous;
}

3. Update the collider dynamically

If the mask collider needs to be updated frequently, one approach is to dynamically change the points of the PolygonCollider2D or the objects making up a CompositeCollider2D. Be aware, this could be performance heavy if changes are frequent and the collider shape is complex.

Remember, it’s often a balancing act between getting the precise collisions you want and maintaining good performance. Consider if the precision of your mask collider is worth the performance cost. You might find that a simpler approximation of the shape still gives a good gameplay experience.

As you pointed out, you might not want to modify the collider every frame, especially for more complex shapes. Instead, you can consider using an interval or triggers to change the collider less frequently. Alternatively, use simplified shapes for the collider to reduce computation.

---------EDIT---------

I think I understand better now what you are trying to do, it’s not trivial. Since you want to modify the shape of the collider dynamically based on the mask’s position, we will need to use a boolean operation library to get the resulting shape after applying the mask.

For this solution, I’m going to go ahead and assume we’re using a library such as the Clipper library to perform polygon boolean operations. Unfortunately, the algorithm for performing these operations is complex and beyond the scope of this explanation.

We are going to have to do quite a few things:

  1. Convert the shapes of the platform’s collider and the mask into a format that the library can use. The Clipper library, for example, uses its own IntPoint and Path classes to represent points and polygons.
  2. Perform a boolean difference operation between the platform’s shape and the mask’s shape. This will give you a new shape that represents the platform with the mask “cut out”.
  3. Convert the resulting shape back into a format that Unity’s PolygonCollider2D can use and assign it to the collider’s points property.

Something like this (note this is high level code and will not work as is, its just for demostration purposes)

    using ClipperLib;  // Assuming you're using the Clipper library

    void ApplyMask(PolygonCollider2D platformCollider, CircleCollider2D maskCollider) {
    // Convert the platform's shape to a format that the Clipper library can use
    Path platformPath = new Path(platformCollider.points.Select(p => new IntPoint(p.x, p.y)).ToList());

    // Convert the mask's shape to a format that the Clipper library can use
    // For simplicity, let's assume you have a function that converts a circle to a polygon
    Path maskPath = CircleToPath(maskCollider);

    // Perform the difference operation
    Clipper clipper = new Clipper();
    clipper.AddPath(platformPath, PolyType.ptSubject, true);
    clipper.AddPath(maskPath, PolyType.ptClip, true);
    Paths solution = new Paths();
    clipper.Execute(ClipType.ctDifference, solution);

    // Convert the resulting shape back to a format Unity can use
    // For simplicity, let's assume you have a function that converts a Paths object to a Vector2 array
    Vector2[] newPoints = PathsToVector2Array(solution);

    // Assign the new shape to the collider
    platformCollider.points = newPoints;
}

This is a simplified example and doesn’t cover all possible situations. For example, it doesn’t handle cases where the mask doesn’t intersect the platform, or where the mask “cuts” the platform into multiple separate shapes. These situations would require additional logic to handle correctly.

Remember that changing the shape of a collider at runtime can be an expensive operation. It’s generally best to avoid doing it every frame if possible. Consider using an interval or triggers to change the collider less frequently, or a simplified shape for the mask to reduce computation. Also maybe don’s even affect the collisions unless your play character is close to the mask etc (i.e. when its actually needed).

Start with this and dive into the clipper library, I think it’ll solve this for you when used correctly, at least other users see to have found it useful.

I hope this gets you closer to an answer.