Search code examples
xamlmauigame-development

In Maui, how can I set Grid\Border\Frame background as tiled, given a sample tile for it to fill with?


I am developing a Maui game and I want to set each game level background (Grid but could also be Border\Frame) according to its level type. I want to do so using a sample tile image that will be duplicated to fill the background.

Is this possible out of the box? Or should I write a custom control for it?

For example i'm looking for something like: (More explanation added)

<Border>
    <Border.Background>
        <Image Source="volcano_tile.png" Mode="Tiled"/>
    </Border.Background>
</Border>

volcano_tile.png:

enter image description here

And the expected result would be to fill the entire border background with multiple tiles:

enter image description here

Thanks!


Solution

  • I did not find a standard easy xaml way to do it, so I have implemented a solution using SkiaSharp:

    This is my Tester code:

    First, I have created a helper class that receives width and height of the wanted target tiled image, and the tileImage itself. Using SKBitmap, it builds and returns the tiled image:

    internal class ImageTiler
    {
        public static SKBitmap CreateTiledImage(int width, int height, SKBitmap tileImage)
        {
            // Create a new bitmap with the desired dimensions
            var tiledBitmap = new SKBitmap(width, height);
            using (var canvas = new SKCanvas(tiledBitmap))
            {
                // Loop through the width and height of the new image
                for (int y = 0; y < height; y += tileImage.Height)
                {
                    for (int x = 0; x < width; x += tileImage.Width)
                    {
                        // Draw the tile image at the current position
                        canvas.DrawBitmap(tileImage, x, y);
                    }
                }
            }
            return tiledBitmap;
        }
    
        public static SKBitmap LoadImage(string resourcePath)
        {
            var assembly = Assembly.GetExecutingAssembly();
            var resourceName = $"TilesTester.Resources.Images.{resourcePath}";
            
            //var imageSource = ImageSource.FromFile(resourcePath);
            using (var stream = assembly.GetManifestResourceStream(resourceName))
            {
                return SKBitmap.Decode(stream);
            }
        }
    }
    

    Than I have loaded my resource png tile image, and used the ImageTiler to build and display it using a SKCanvasView:

    // Load the image to be tiled
    string imagePath = "volcanotile.png";
    SKBitmap tileImage = ImageTiler.LoadImage(imagePath);
    
    // Define the dimensions of the new image
    int newWidth = 800;
    int newHeight = 600;
    
    // Create the tiled image
    SKBitmap tiledImage = ImageTiler.CreateTiledImage(newWidth, newHeight, tileImage);
    
    var canvasView = new SKCanvasView();
    canvasView.PaintSurface += (sender, args) =>
    {
        var canvas = args.Surface.Canvas;
        canvas.Clear();
        canvas.DrawBitmap(tiledImage, new SKRect(0, 0, newWidth, newHeight));
    };
    
    // Add the SKImageView as a Content to the page
    Content = canvasView;
    

    The result (Modified screenshot after changing to better Tile image and adding dynamic Tile selection): enter image description here