public void SetGrid(MapGridSpaceInfo[,] grid)
 {
     int i = 0;
     for (int y = 0; y < grid.GetLength(1); ++y)
     {
         for (int x = 0; x < grid.GetLength(0); ++x)
         {
             data[i] = grid[x, y].FullTileGid;
             ++i;
         }
     }
 }
    private bool shouldIgnore(MapGridSpaceInfo tile)
    {
        if (this.TileTypesToIgnore != null)
        {
            for (int i = 0; i < this.TileTypesToIgnore.Length; ++i)
            {
                if (this.TileTypesToIgnore[i] == tile.TileId)
                    return true;
            }
        }

        return false;
    }
        public MapGridSpaceInfo[,] GetGrid(MapTileSet[] tilesets)
        {
            MapGridSpaceInfo[,] grid = new MapGridSpaceInfo[width, height];
            int i = 0;

            for (int y = 0; y < height; ++y)
            {
                for (int x = 0; x < width; ++x)
                {
                    grid[x, y] = new MapGridSpaceInfo(data[i], tilesets);
                    ++i;
                }
            }

            return grid;
        }
    public void CreateGeometryForGrid(MapGridSpaceInfo[,] grid, bool editor)
    {
        if (_geometry == null)
            _geometry = new List<IntegerCollider>();

        int halfSize = this.TileRenderSize / 2;
        for (int x = 0; x < grid.GetLength(0); ++x)
        {
            for (int y = 0; y < grid.GetLength(1); ++y)
            {
                if (!shouldIgnore(grid[x, y]))
                {
                    IntegerCollider geom = aquireGeometry(editor);
                    int posY = this.FlipVertical ? (grid.GetLength(1) - y - 1) * this.TileRenderSize : y * this.TileRenderSize;
                    geom.transform.localPosition = new Vector3(x * this.TileRenderSize + halfSize, posY + halfSize, 0);
                    _geometry.Add(geom);
                }
            }
        }
    }
    public void CreateMapWithGrid(MapGridSpaceInfo[,] grid)
    {
        if (_cleared)
        {
            _width = grid.GetLength(0);
            _height = grid.GetLength(1);
            createMapUsingMesh(grid);
        }
        else if (_width != grid.GetLength(0) || _height != grid.GetLength(1))
        {
            this.Clear();
            _width = grid.GetLength(0);
            _height = grid.GetLength(1);
            createMapUsingMesh(grid);
        }
        else
        {
            Vector2[] uvs = this.MeshFilter.mesh.uv;

            for (int y = 0; y < grid.GetLength(0); ++y)
            {
                for (int x = 0; x < grid.GetLength(1); ++x)
                {
                    int tileIndex = y * _width + x;
                    int startingUVIndex = tileIndex * 4;

                    Vector2[] spriteUVs = this.Sprites[grid[x, y].TileId].uv;
                    uvs[startingUVIndex] = spriteUVs[0]; // bottom left
                    uvs[startingUVIndex + 1] = spriteUVs[1]; // bottom right
                    uvs[startingUVIndex + 2] = spriteUVs[2]; // top left
                    uvs[startingUVIndex + 3] = spriteUVs[3]; // top right
                }
            }

            this.MeshFilter.mesh.uv = uvs;
        }
    }
    private bool isFilled(MapGridSpaceInfo[,] grid, int x, int y, bool countOutOfBounds = true)
    {
        if (x < 0 || x >= grid.GetLength(0) || y < 0 || y >= grid.GetLength(1))
            return countOutOfBounds;

        return grid[x, y].TileId != 0;
    }
    private MapGridSpaceInfo[,] correctTiles(MapGridSpaceInfo[,] grid)
    {
        MapGridSpaceInfo[,] newGrid = new MapGridSpaceInfo[grid.GetLength(0), grid.GetLength(1)];

        for (int x = 0; x < grid.GetLength(0); ++x)
        {
            for (int y = 0; y < grid.GetLength(1); ++y)
            {
                newGrid[x, y] = grid[x, y];

                if (grid[x, y].TileId == 0)
                {
                    // Empty
                }
                else
                {
                    bool left = isFilled(grid, x - 1, y);
                    bool right = isFilled(grid, x + 1, y);
                    bool down = isFilled(grid, x, y - 1);
                    bool up = isFilled(grid, x, y + 1);

                    if (!left && !right && !down && !up)
                    {
                        // Lone
                        newGrid[x, y].TileId = TILE_LONE; 
                    }
                    else if (!left && !right)
                    {
                        // Column
                        if (up && down)
                            newGrid[x, y].TileId = TILE_COLUMN_MID;
                        else if (!up)
                            newGrid[x, y].TileId = this.FlipVertical ? TILE_COLUMN_BOTTOM : TILE_COLUMN_TOP;
                        else
                            newGrid[x, y].TileId = this.FlipVertical ? TILE_COLUMN_TOP : TILE_COLUMN_BOTTOM;
                    }
                    else if (!down && !up)
                    {
                        // Island
                        if (left && right)
                            newGrid[x, y].TileId = TILE_ISLAND_MID;
                        else if (!left)
                            newGrid[x, y].TileId = TILE_ISLAND_LEFT;
                        else
                            newGrid[x, y].TileId = TILE_ISLAND_RIGHT;
                    }
                    else
                    {
                        if (up && down && left && right)
                        {
                            newGrid[x, y].TileId = TILE_MID_MID;
                        }
                        else if (up && down)
                        {
                            if (right)
                                newGrid[x, y].TileId = TILE_MID_LEFT;
                            else
                                newGrid[x, y].TileId = TILE_MID_RIGHT;
                        }
                        else if (left && right)
                        {
                            if (up)
                                newGrid[x, y].TileId = this.FlipVertical ? TILE_TOP_MID : TILE_BOTTOM_MID;
                            else
                                newGrid[x, y].TileId = this.FlipVertical ? TILE_BOTTOM_MID : TILE_TOP_MID;
                        }
                        else if (up && right)
                        {
                            newGrid[x, y].TileId = this.FlipVertical ? TILE_TOP_LEFT : TILE_BOTTOM_LEFT;
                        }
                        else if (up && left)
                        {
                            newGrid[x, y].TileId = this.FlipVertical ? TILE_TOP_RIGHT : TILE_BOTTOM_RIGHT;
                        }
                        else if (down && right)
                        {
                            newGrid[x, y].TileId = this.FlipVertical ? TILE_BOTTOM_LEFT : TILE_TOP_LEFT;
                        }
                        else if (down && left)
                        {
                            newGrid[x, y].TileId = this.FlipVertical ? TILE_BOTTOM_RIGHT : TILE_TOP_RIGHT;
                        }
                    }
                }
            }
        }

        return newGrid;
    }
    private void createMapUsingMesh(MapGridSpaceInfo[,] grid)
    {
        float originX = 0; // this.transform.position.x;
        float originY = 0; // this.transform.position.y;
        float originZ = 0; // this.transform.position.z;

        int numTiles = _width * _height;
        int numTriangles = numTiles * 2;

        // Generate mesh data
        List<Vector3> vertices = new List<Vector3>();
        List<Vector3> normals = new List<Vector3>();
        List<Vector2> uvs = new List<Vector2>();
        int[] triangles = new int[numTriangles * 3]; // Clockwise order of vertices within triangles (for correct render direction)
        
        float finalY = originY + _height * this.TileRenderSize;

        for (int y = 0; y < _height; ++y)
        {
            for (int x = 0; x < _width; ++x)
            {
                int tileIndex = _width * y + x;
                int triangleIndex = tileIndex * 2 * 3;

                // Create 4 verts
                float smallY = this.FlipVertical ? finalY - y * this.TileRenderSize : originY + y * this.TileRenderSize;
                float bigY = this.FlipVertical ? smallY - this.TileRenderSize : smallY + this.TileRenderSize;
                Vector3 bottomLeft = new Vector3(originX + x * this.TileRenderSize, smallY, originZ);
                Vector3 bottomRight = new Vector3(bottomLeft.x + this.TileRenderSize, bottomLeft.y, originZ);
                Vector3 topLeft = new Vector3(bottomLeft.x, bigY, originZ);
                Vector3 topRight = new Vector3(bottomRight.x, topLeft.y, originZ);

                // Indices of verts
                int bottomLeftVert = vertices.Count;
                int bottomRightVert = bottomLeftVert + 1;
                int topLeftVert = bottomRightVert + 1;
                int topRightVert = topLeftVert + 1;

                // Assign vert indices to triangles
                triangles[triangleIndex] = topLeftVert;
                triangles[triangleIndex + 1] = bottomRightVert;
                triangles[triangleIndex + 2] = bottomLeftVert;

                triangles[triangleIndex + 3] = topLeftVert;
                triangles[triangleIndex + 4] = topRightVert;
                triangles[triangleIndex + 5] = bottomRightVert;

                // Handle UVs
                int spriteIndex = grid[x, y].TileId;

                /*if (spriteIndex >= this.Sprites.Length || spriteIndex < 0)
                {
                    Debug.LogWarning("Invalid sprite index: " + spriteIndex);
                }*/

                Vector2[] spriteUVs = this.Sprites[spriteIndex].uv;
                Vector2 bottomLeftUV = spriteUVs[0];
                Vector2 bottomRightUV = spriteUVs[1];
                Vector2 topLeftUV = spriteUVs[2];
                Vector2 topRightUV = spriteUVs[3];

                // Add vertices and vertex data to mesh data
                vertices.Add(bottomLeft);
                vertices.Add(bottomRight);
                vertices.Add(topLeft);
                vertices.Add(topRight);
                normals.Add(Vector3.up);
                normals.Add(Vector3.up);
                normals.Add(Vector3.up);
                normals.Add(Vector3.up);
                uvs.Add(bottomLeftUV);
                uvs.Add(bottomRightUV);
                uvs.Add(topLeftUV);
                uvs.Add(topRightUV);
            }
        }

        // Populate a mesh
        Mesh mesh = new Mesh();
        mesh.vertices = vertices.ToArray();
        mesh.normals = normals.ToArray();
        mesh.uv = uvs.ToArray();
        mesh.triangles = triangles;

        // Assign mesh to behaviors
        this.MeshFilter.mesh = mesh;
        this.renderer.material.mainTexture = this.Atlas;
    }