I need help to fix my bugs with the EdgeCollider2D | Random 2D map generation

Hey,
inspired by Student Game Dev has moved!: Unity Voxel Tutorial Part 1: Generating meshes from code I have created a slightly different version, so it can work with 2D physics.
For this I used an EdgeCollider2D which i gave the coordiantes of the squares vertices (I think) :

private void GenCollider(int x, int y)
    {
        col = GetComponent<EdgeCollider2D>();

        if (Block(x, y + 1) == 0)
        {
            // TOP
            newColVertices.Add(new Vector2(x, y));
            newColVertices.Add(new Vector2(x + 1, y));
        }

        if (Block(x, y - 1) == 0)
        {
            // BOTTOM
            newColVertices.Add(new Vector2(x, y - 1));
            newColVertices.Add(new Vector2(x + 1, y - 1));
        }

        if (Block(x - 1, y) == 0)
        {
            // LEFT
            newColVertices.Add(new Vector2(x, y));
            newColVertices.Add(new Vector2(x, y - 1));
        }

        if (Block(x + 1, y) == 0)
        {
            // RIGHT
            newColVertices.Add(new Vector2(x + 1, y));
            newColVertices.Add(new Vector2(x + 1, y - 1));
        }

I copied his way, how he achieved that there won’t be created an EdgeCollider2D for every single Block.
To test it i have created a 2D sprite which I gave a BoxCollider2D and also a Rigidbody.
When I hit the play button it works. But when I move the texture manually beneath the surface of the map it fells at first through the blocks but sometimes get stuck or gets even up again what it’s not supposed to do.

Here is my whole Code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GenerateSquares : MonoBehaviour {

    private List<int> newTriangles = new List<int>();
    private List<Vector3> newVertices = new List<Vector3>();
    private List<Vector2> newColVertices = new List<Vector2>();
    private List<Vector2> newUV = new List<Vector2>();

    private Mesh mesh;

    private EdgeCollider2D col;

    private float tUnit = 0.25f;

    private int squareCount;

    public byte[,] blocks;

    private Vector2 tStone = new Vector2(0, 0);
    private Vector2 tGrass = new Vector2(0, 1);

    private void Start()
    {
        GenTerrain();
        BuildMesh();
        UpdateMesh();
    }

    private void GenSquare(int x, int y, Vector2 texture)
    {
        mesh = GetComponent<MeshFilter>().mesh;

        newVertices.Add(new Vector3(x, y));
        newVertices.Add(new Vector3(x + 1, y));
        newVertices.Add(new Vector3(x + 1, y - 1));
        newVertices.Add(new Vector3(x, y - 1));

        newTriangles.Add(squareCount * 4);
        newTriangles.Add((squareCount * 4) + 1);
        newTriangles.Add((squareCount * 4) + 3);
        newTriangles.Add((squareCount * 4) + 1);
        newTriangles.Add((squareCount * 4) + 2);
        newTriangles.Add((squareCount * 4) + 3);

        newUV.Add(new Vector2(tUnit * texture.x, tUnit * texture.y + tUnit));
        newUV.Add(new Vector2(tUnit * texture.x + tUnit, tUnit * texture.y + tUnit));
        newUV.Add(new Vector2(tUnit * texture.x + tUnit, tUnit * texture.y));
        newUV.Add(new Vector2(tUnit * texture.x, tUnit * texture.y));

        squareCount++;
       
        GenCollider(x, y);
    }

    private void GenTerrain()
    {
        blocks = new byte[30, 60];

        for(int x = 0; x < blocks.GetLength(0); x++)
        {
            int stone = Noise(x, 0, 80, 15, 1);
            stone += Noise(x, 0, 50, 30, 1);
            stone += Noise(x, 0, 10, 10, 1);
            stone += 25;

            int dirt = Noise(x, 0, 100, 35, 1);
            dirt += Noise(x, 0, 50, 30, 1);
            dirt += 25;

            for (int y = 0; y < blocks.GetLength(1); y++)
            {
                if (y < stone)
                {
                    blocks[x, y] = 1;

                    if (Noise(x, y, 12, 16, 1) > 10)
                    {
                        blocks[x, y] = 2;

                    }
                   
                    if (Noise(x, y * 2, 16, 20, 1) > 10)
                    {
                        blocks[x, y] = 0;

                    }
                }
                else if (y < dirt)
                {
                    blocks[x, y] = 2;
                }
            }
        }
    }

    int Noise(int x, int y, float scale, float mag, float exp)
    {

        return (int)(Mathf.Pow((Mathf.PerlinNoise(x / scale, y / scale) * mag), (exp)));

    }

    void BuildMesh()
    {
        for (int px = 0; px < blocks.GetLength(0); px++)
        {
            for (int py = 0; py < blocks.GetLength(1); py++)
            {
                if (blocks[px, py] == 1)
                {
                    GenSquare(px, py, tStone);
                }
                else if (blocks[px, py] == 2)
                {
                    GenSquare(px, py, tGrass);
                }
            }
        }
    }

    byte Block(int x, int y)
    {

        if (x == -1 || x == blocks.GetLength(0) || y == -1 || y == blocks.GetLength(1))
        {
            return (byte)1;
        }

        return blocks[x, y];
    }


    private void UpdateMesh()
    {
        mesh.Clear();
        mesh.vertices = newVertices.ToArray();
        mesh.triangles = newTriangles.ToArray();
        mesh.uv = newUV.ToArray();
        mesh.RecalculateNormals();

        col.points = newColVertices.ToArray();

        squareCount = 0;
        newVertices.Clear();
        newTriangles.Clear();
        newUV.Clear();
    }

    private void GenCollider(int x, int y)
    {
        col = GetComponent<EdgeCollider2D>();

        if (Block(x, y + 1) == 0)
        {
            // TOP
            newColVertices.Add(new Vector2(x, y));
            newColVertices.Add(new Vector2(x + 1, y));
        }

        if (Block(x, y - 1) == 0)
        {
            // BOTTOM
            newColVertices.Add(new Vector2(x, y - 1));
            newColVertices.Add(new Vector2(x + 1, y - 1));
        }

        if (Block(x - 1, y) == 0)
        {
            // LEFT
            newColVertices.Add(new Vector2(x, y));
            newColVertices.Add(new Vector2(x, y - 1));
        }

        if (Block(x + 1, y) == 0)
        {
            // RIGHT
            newColVertices.Add(new Vector2(x + 1, y));
            newColVertices.Add(new Vector2(x + 1, y - 1));
        }
    }
}

Be aware, I’m a beginner.

(Since I could’nt edit my post…)

Something is wrong with the points of the EdgeCollider2D. When i tested it with a single square, it works fine. In some Tutorials i heard about that every square hast to have it’s own mesh, but I don’t know how to do this.

Looks like you are making one big mesh of verts (newColVertices), continuously adding each square to it and finally handing the entire thing over to a single EdgeCollider2D, so that is why the collider looks all wonky. I’m not sure what the mesh limitations are for an EdgeCollider2D as I’ve never procedurally generated stuff for them.

If you want to use EdgeCollider2Ds to accomplish this, I think you will either need one EdgeCollider2D component per square of geometry generated (easiest to do code-wise), or one for each group of adjacent blocks that are all contiguous, i.e., meld them into a larger block (can be quite tricky code-wise).

Followup: after tinkering a bit with EdgeCollider2D in the actual Unity editor, trying to fabricate my own collider, it seems that it’s not really a direct analogy to a mesh. It appears to be an implicit mesh derived from a crust of points going around a certain way. I think you will have to “wind” each box individually.

Thanks. This helps a lot!:slight_smile:

Yanno, you might get a lot more happiness if you consider using a BoxCollider2D on each square that is supposed to be blocked… I kinda feel that’s more what you’re trying to do anyway, right??

Could you give me an example how to set the coordinates of the boxcollider 2d to the Squares coordinates?

The docs would indicate you want to add the BoxCollider2D for each cell, and then set the .size and .offset properties appropriately.

Docs: Unity - Scripting API: BoxCollider2D

The general code is something like

var bc = MyGameObject.AddComponent<BoxCollider2D>();
 bc.size = new Vector2( 0.4f, 0.7f);
 bc.offset = new Vector2( 1.2f, 2.5f);

Try it, see how it works.

When i try this there will only be one box collider created :confused:

If you add one, there will be one. If you add more, there will be more!

You can add (apparently) as many as you like. There MAY be a limit, but then just make new GameObjects.

To see what I mean, stick this script on an empty GameObject, press PLAY, then examine that GameObject (while the engine is still in PLAY mode) and you’ll see it has ten colliders on it of varying sizes and offsets.

using UnityEngine;

public class ManyBoxCollider2Ds : MonoBehaviour
{
    void Start ()
    {
        for (int i = 0; i < 10; i++)
        {
            var bc = gameObject.AddComponent<BoxCollider2D>();
            bc.offset = Vector2.right * i * 3;
            bc.size = Vector2.one * (i + 1);
        }  
    }
}

Thanks, now there is for every Square a BoxCollider2D.
Now I tried to check, if there is a block with the value 0 a collider will be created. But that does only work for the right side :confused:

 private void GenCollider(int x, int y)
    {
        // Top-BLock-Missing
        if (Block(x, y + 1) == 0 && Block(x, y - 1) == 1 && Block(x - 1, y) == 1 && Block(x + 1, y) == 1)
        {
            var bc = gameObject.AddComponent<BoxCollider2D>();
            bc.offset = new Vector2((x) + 0.5f, (y) - 0.5f);
            bc.size = new Vector2(1, 1);
        }

        // Bottom-Block-Missing
       if (Block(x, y + 1) == 1 && Block(x, y - 1) == 0 && Block(x - 1, y) == 1 && Block(x + 1, y) == 1)
        {
            var bc = gameObject.AddComponent<BoxCollider2D>();
            bc.offset = new Vector2((x) + 0.5f, (y) - 0.5f);
            bc.size = new Vector2(1, 1);
        }

       // Right-Block-Missing
       if(Block(x, y + 1) == 1 && Block(x, y - 1) == 1 && Block(x - 1, y) == 1 && Block(x + 1, y) == 0)
        {
            var bc = gameObject.AddComponent<BoxCollider2D>();
            bc.offset = new Vector2((x) + 0.5f, (y) - 0.5f);
            bc.size = new Vector2(1, 1);
        }

        // Left-Block-Missing
        if (Block(x, y + 1) == 1 && Block(x, y - 1) == 1 && Block(x - 1, y) == 0 && Block(x + 1, y) == 1)
        {
            var bc = gameObject.AddComponent<BoxCollider2D>();
            bc.offset = new Vector2((x) + 0.5f, (y) - 0.5f);
            bc.size = new Vector2(1, 1);
        }
    }

I create a 10x10 grid of which the first 10 blocks are air (so value 0).

private void GenTerrain()
    {
        blocks = new byte[10, 10];
        for(int x = 0; x < blocks.GetLongLength(0); x++)
        {
            for(int y = 0; y < blocks.GetLongLength(1); y++)
            {
                if (y < 9)
                {
                    blocks[x, y] = 1;
                    GenSquare(x, y);
                }
                else
                {
                    blocks[x, y] = 0;
                }
            }
        }
    }

And if the block is inside of the arrays boundaries the blocks value will be set to 1

byte Block(int x, int y)
    {

        if (x == -1 || x == blocks.GetLength(0) || y == -1 || y == blocks.GetLength(1))
        {
            return (byte)1;
        }

        return blocks[x, y];
    }

3453818--273701--Help.PNG

The error is probably related to what is calling GenCollider(). You didn’t supply that code.

This is called in the start function:

public void Start()
    {
        GenTerrain();
        UpdateMesh();
    }

And there i call the GenCollider() method

private void GenSquare(int x, int y)
    {
        mesh = GetComponent<MeshFilter>().mesh;

        newVertices.Add(new Vector3(x, y));
        newVertices.Add(new Vector3(x + 1, y));
        newVertices.Add(new Vector3(x + 1, y - 1));
        newVertices.Add(new Vector3(x, y - 1));

        GenCollider(x, y);

        newTriangles.Add(blocksCount * 4);
        newTriangles.Add((blocksCount * 4) + 1);
        newTriangles.Add((blocksCount * 4) + 3);
        newTriangles.Add((blocksCount * 4) + 1);
        newTriangles.Add((blocksCount * 4) + 2);
        newTriangles.Add((blocksCount * 4) + 3);

        blocksCount++;
    }