Create image from the arrangement of tiles in tileset or how to merge tiles into new texture

Excuse me, want to ask about texture.

I have a texture tileset, then I want to create a new object where the reference is from the tiles that are already in the tilesets.

how should i start ?

for now I use the renderTexture function to draw the required tiles from the tilesets, then take a snapshot so that I can retrieve them as new, drawable textures.

// mapping tiles
const tiles = [ [0, 1], [2, 3] ]

// my funct to get tiles from tilesets, and draw to render texture (crop, dll)
const toRenderTx = getRenderTexture(tiles)

// draw
const sprite = this.scene.physics.add.image(0, 0, toRenderTx)


// fc
getRenderTexture(tiles: number[][], key = 'default') {
    const tileset = 'my-tileset'
    const sourceTexture = this.scene.mapManager.tileMap?.getTileset(
      tileset
    ) as Phaser.Tilemaps.Tileset
    const { tileWidth, tileHeight } = sourceTexture

    const tileIds = tiles
    const rt = this.scene.make.renderTexture(
      {
        width: tileIds[0].length * tileWidth,
        height: tileIds.length * tileHeight,
        x: 0,
        y: 0,
      },
      false
    )
    for (let y = 0; y < tileIds.length; y++) {
      // loop X
      for (let x = 0; x < tileIds[y].length; x++) {
        const tileId = tileIds[y][x]
        const coordinate = (sourceTexture.getTileTextureCoordinates(tileId) || {
          x: 0,
          y: 0,
        }) as { x: number; y: number }
        const ft = sourceTexture.image.get().clone()
        const newRT = this.scene.make.renderTexture(
          {
            width: ft.width,
            height: ft.height,
          },
          false
        )
        newRT.draw(ft)
        newRT.setCrop(coordinate.x, coordinate.y, tileWidth, tileHeight)
        rt.draw(
          newRT,
          -coordinate.x + x * tileWidth,
          -coordinate.y + y * tileHeight
        )
      }
    }
    return rt.texture
  }

but it turns out that this method causes a very large and uncontrolled memory.
with 6 object like code above, use 3.8gb of ram.

any suggestions i can do?

Can you show what textures you want to produce?

I have a tilesets.

but I want to build a new image composed of the existing tiles in the tilesets.

For example, I want to make a picture of a chair object, where the chair object is composed of tiles with id 0, 1, 2, and 3 on the tilesets.

I’ve managed to make the function like the code I attached above, which is using render texture.

but this turns out to take a lot of memory, even for 6 objects it reaches 3gb of ram.

is there a proper way to create an new image object from tiles (tile index) in tilesets?

An example image that might illustrate it:

  • Load the tileset image using load.spritesheet(…) so you can select frames for each tile index
  • Create one render texture with the exact dimensions you need
  • Call drawFrame(texture, frame, x, y) to draw each tile

thanks, it turns out that the problem arose because I cloned the texture, the possibility that caused the ram problem to arise.

then, in the case of the code below why doesn’t it seem to work? only renders the first index.

   for (let y = 0; y < tileIds.length; y++) {
      for (let x = 0; x < tileIds[y].length; x++) {
        const tileId = tileIds[y][x]
        rt.drawFrame(tileset, tileId, x * tileWidth, y * tileHeight)
      }
    }

but when i try to change it to like this it seems to work.

    for (let y = 0; y < tileIds.length; y++) {
      for (let x = 0; x < tileIds[y].length; x++) {
        const tileId = tileIds[y][x]
        const newRT = scene.make.renderTexture(
          {
            width: tileWidth,
            height: tileHeight,
          },
          false
        )
        newRT.drawFrame(tileset, tileId, 0, 0)
        rt.draw(newRT, x * tileWidth, y * tileHeight)
      }
    }

Is rt the right size?

And add

console.log(tileset, tileId, x * tileWidth, y * tileHeight)

yeah it should be right. in my example I have tiles like this:

const tileset = "my_example_tileset"
const tileSize = 16

const tileIds = [
  [8476 , 8477, 8478],
  [8539 , 8540, 8541],
];

const resultWidth = tileIds[0].length * tileSize 
const resultHeight = tileIds.length * tileSize

const rt = this.scene.make.renderTexture(
    {
        width: resultWidth ,
        height: resultHeight ,
        x: 0,
        y: 0,
    },
    false
)

for (let y = 0; y < tileIds.length; y++) {
    for (let x = 0; x < tileIds[y].length; x++) {
        const tileId = tileIds[y][x]
        const newRT = scene.make.renderTexture(
          {
            width: tileWidth,
            height: tileHeight,
          },
          false
        )
        newRT.drawFrame(tileset, tileId, 0, 0)
        rt.draw(newRT, x * tileSize , y * tileSize)
    }
}

btw, the logs are as follows:

# console.log(tileset, tileId, x * tileWidth, y * tileHeight)
my_example_tileset 8476 0 0
my_example_tileset 8477 16 0
my_example_tileset 8478 32 0
my_example_tileset 8539 0 16
my_example_tileset 8540 16 16
my_example_tileset 8541 32 16

thanks

I don’t know why, but when I tried it again it suddenly worked.

thanks for your help once again.

I want to ask a final question, is this a safe way to create objects?

I’m planning on creating a lot of objects this way actually, because instead of reloading the sprites, using the layout of the existing tileset for the tilemap I think makes sense.

This my finally code :

const tileset = "my_example_tileset"

const tileSize = 16

const tileIds = [
  [8476 , 8477, 8478],
  [8539 , 8540, 8541],
];

const resultWidth = tileIds[0].length * tileSize 
const resultHeight = tileIds.length * tileSize

const rt = this.scene.make.renderTexture(
    {
        width: resultWidth ,
        height: resultHeight ,
        x: 0,
        y: 0,
    },
    false
)

const rt = scene.make.renderTexture(
    {
        width: tileIds[0].length * tileSize ,
        height: tileIds.length * tileSize ,
        x: 0,
        y: 0,
      },
      false
    )
    for (let y = 0; y < tileIds.length; y++) {
      for (let x = 0; x < tileIds[y].length; x++) {
        const tileId = tileIds[y][x]
        rt.drawFrame(tileset, tileId, x * tileSize , y * tileSize )
    }
}

It should be fine.

But don’t you want addToScene = true when making the render texture?