Rendering a single 2D tile from a tileset in a SkiaSharp game

In this part we are investigating rendering a single tile and finally we will create a tile renderer. The tileset that is being rendered is from Aleksandr Makarov at itch.io. To see how to add the tileset png to the project see the previous part.

The bitmap is 128 x 192 pixels. A single tile is 8 x 8 pixels. The bitmap is divided into rows and columns of tiles. The row and column is specified to render a single tile. Using the width and height of a single tile we can calculate a source rectangle in the tile set bitmap which represent the single tile we are interested in. This tile can then be rendered at any place on the screen by specifying a target rectangle which can be of a different size so the tile can be bigger or smaller than the original size.

The PixelApplication class init method loads the bitmap / image from the embedded resource. The tile is rendered using the canvas DrawBitmap method. This accepts a reference to the bitmap and a source and target rect, which determines the position and the size of the bitmap. In this case it is rendered at 4 times the original size.

    public class PixelApplication
    {
        private double width;
        private double height;
        SKBitmap tilesBitmap;
        const int TileSize = 8;   // Each tile is 8 x 8 pixels
        const int TileScaling = 4;  // The tile gets scaled with this factor so it becomes 32 x 32		
        SKRect sourceRect = new SKRect(0, 0, TileSize, TileSize);
        SKRect targetRect = new SKRect(0, 0, TileScaling * TileSize, TileScaling * TileSize);	

        public void Init(double w, double h)
        {
            width = w;
            height = h;

            // https://iknowkingrabbit.itch.io/mas-grass-land
            string resourceID = "pixelapp.Media.tileset.png";

            // https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/basics/bitmaps
            Assembly assembly = GetType().GetTypeInfo().Assembly;

            using (Stream stream = assembly.GetManifestResourceStream(resourceID))
            {
                tilesBitmap = SKBitmap.Decode(stream);
            }
        }

        public void Render(SKCanvas canvas, double updateDelta)
        {
            canvas.Clear(_fillColor);

            // Grass (1,0), Flowers (2,0), Tree (0,4)

            int tx = 0;   // Zero based row number
            int ty = 4;   // Zero based column number

            // Render the tree tile at the center of the screen
            DrawTile((float)width / 2.0f, (float)height / 2.0f, tx, ty, canvas);
        }
		
        private void DrawTile(float x, float y, int tx, int ty, SKCanvas canvas)
        {
            // Select the source rectangle from the tile set rectangle by calculating the pixel coordinates
            sourceRect.Left = tx * TileSize;
            sourceRect.Right = sourceRect.Left + TileSize;
            sourceRect.Top = ty * TileSize;
            sourceRect.Bottom = sourceRect.Top + TileSize;

            // Specify where to render the tile at the screen and with what size
            targetRect.Left = x;
            targetRect.Right = targetRect.Left + TileScaling * TileSize;
            targetRect.Top = y;
            targetRect.Bottom = targetRect.Top + TileScaling * TileSize;

            canvas.DrawBitmap(tilesBitmap, sourceRect, targetRect);
        }		
    }
	

A single tile depicting a tree should be rendered when running the code as shown in the image below.

Render a single tile