MonoGame Tiled – Extract Texture2D

NEZ, an open source MonoGame framework extension, provides the functionality to import and render a tiled map. (.tmx) If MonoGame and NEZ isn’t a term for you, consider reading an introduction article first.

Recap: Following code does allow us to render a tiledmap with the NEZ’s ECS system

            var tmx = Core.Content.Load<TiledMap>("Map");
            Entity mapEntity = new Entity();            
            TiledMapComponent bgComponent = new TiledMapComponent(tmx, "collision", true);
            AddComponent(bgComponent);
            mapEntity.AddComponent(bgComponent);
            Core.Scene.AddEntity(mapEntity);

But how do we only render one specific layer? And what if we would like to manipulate the Texture2D of that layer. E.g.: Applying a material, shader, matrix manipulation, …

Rendering only a specific layer is already supported by NEZ:

bgComponent.SetLayersToRender(RenderLayerNames);

Manipulating the Texture2D however, isn’t. The Texture2D behind each and every layer equals the whole Texture2D of the tileset. Hence, we need to implement our own logic.

Option 1 – RenderTarget2D

Create a new Texture2D, limit the TiledMapComponent’s render layers and call the spriteBatch.Draw within an active RenderTarget2D. Done

Option 2 – Texture2D.GetData

A RenderTarget2D requires a spriteBatch which we maybe won’t have access to. In that case, we can make use of the Texture2D’s .GetData method.

    public static class TiledTileLayerExtensions
    {
        public static Texture2D ExtractTexture2D(this TiledTileLayer layer)
        {
            List<TiledTile> tiles = layer.Tiles.Where(t => t != null).ToList();

            var mostLeft = tiles.Min(c => c.X) * Constants.TILE_WIDTH;
            var mostRight = (tiles.Max(c => c.X) * Constants.TILE_WIDTH) + Constants.TILE_WIDTH;
            var mostTop = tiles.Min(c => c.Y) * Constants.TILE_HEIGHT;
            var mostBottom = tiles.Max(c => c.Y) * Constants.TILE_HEIGHT + +Constants.TILE_HEIGHT;

            var width = mostRight - mostLeft;
            var height = mostBottom - mostTop;
            var subTextureRect = new Rectangle(mostLeft, mostTop, width, height);

            Color[] subTextureColor = new Color[width * height];

            for (int currentTile = 0; currentTile < tiles.Count; currentTile++)
            {
                TiledTile tileDetails = tiles[currentTile];

                Color[] currentTileColor = new Color[Constants.TILE_WIDTH * Constants.TILE_HEIGHT];
                tileDetails.TextureRegion.Texture2D.GetData(0, tileDetails.TextureRegion.SourceRect, currentTileColor, 0, currentTileColor.Length);

                int tX = tileDetails.X * Constants.TILE_WIDTH;
                int tY = tileDetails.Y * Constants.TILE_HEIGHT;

                for (int x = 0; x < Constants.TILE_WIDTH; x++)
                    for (int y = 0; y < Constants.TILE_HEIGHT; y++)
                        subTextureColor[(y + tY) * width + (x + tX)] = currentTileColor[y * Constants.TILE_WIDTH + x];
            }

            Texture2D subTexture = new Texture2D(Core.GraphicsDevice, width, height);
            subTexture.SetData(subTextureColor);
            return subTexture;
        }
    }

Call the extension method with

            var textureLayer = tmx?.Layers.Where(l => l.Name == "LayerToExtract").SingleOrDefault();
            return (textureLayer as TiledTileLayer)?.ExtractTexture2D();

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.