Memory usage - Tile vs Sprite

Hello, I was running some tests to see what takes more ram during runtime sprites or tiles, so I filled an array with 1million sprites and an array with 1 million tiles and Im not sure what to make of the results.

I filled the sprite array with sprite.create (16x16) sprites.
And I filled the tile array with scriptableobject.instantiate, cloning a pre existing tile that has the same sprite that is being filled in the sprite array.

The sprite array occupies 1.257gb ram while
the tile array occupies 650mb

This makes the sprites take twice as much space as the tiles, however I was under the impression that the tiles themselves contain many elements, a color, a matrix and among them also a sprite

Maybe the cloned tile sprite property is not cloning the sprite but always keeping the same sprite reference?

In essence what I wanted to ask is> if Im laying every tile during runtime, is there a reason to have more than 1 tile? I was wondering if it would be more effective to just have 1 tile and an array of sprites and use tile.sprite to change the sprite before each tile I layed. Since the tiles already set in the tilemap dont get refreshed, it seemed more effective to have just 1 tile and many sprites than having many tiles each containing 1 sprite.

However with the results of my testing I am hesitant to go this route, if someone could share some insight on this subject I would greatly appreciate it.

How did you create the sprites? What texture did you pass it? Did you create new textures for each sprite?

You can easily test if each Tile is referencing the same Sprite by just checking if the sprite of one Tile is the same sprite as another. I’m willing to bet that yes it is because a Tile doesn’t rely on the Sprite’s transform to render itself… it renders its referenced Sprite at the location of the Tile.

Thing is… there’s ways to save space with Sprites as well by sharing its assets.

You should be using TileMaps and its Tiles for what it’s designed for. And Sprites for what its designed for.

Tiles/TileMaps are useful for… well… tiling repeated images on the screen to build a much more complex scene.
Sprites for active images that move around the tile’d scene.

These concepts have been around since early game dev like the NES and the sort. See back then to save on memory and processing power so they can build lower powered machines. They didn’t render games as a large frame buffer… instead they had special processors called “PPU” (pixel processing units). Usually how it worked is that you got a tile region a bit larger than the window of the screen, this region was some WxL tiles in dimension, and a tile was a given size (like 8x8 pixels). Then in a special part of VRAM you would define a palette of tiles (like a TileMap) available. Then instead of defining each pixel on screen individually… you defined which tile from the TileMap went in each position of the tile grid on screen, as well as the position of the window (and you could move that window around to get a scrolling effect).

Then you also had sprites which were rendered separate from the tiles. They could be moved individually regardless of the background tiles (and some consoles had multiple background layers for multiple independently scrolling background tiles). Since they’re positioned independent of the background tiles, they’re used for dynamic things like the player, enemies and bullets and the sort. There was usually a maximum number of sprites allowed on screen, as well as often a maximum per scan line (games often got around this by flickering the sprites, this is why NES games often had flickering sprites in their game to put more enemies on screen).

Here is a video from ‘Modern Vintage Gamer’ explaining how the graphics of the Gameboy worked that can visually show you the difference between background tiles and sprites:

In Unity, it’s not exactly the same… especially since we no longer have the hardware limitations of back then.

BUT, the concepts are similar, and the names are chosen since they convey similar concepts.

We don’t have TileMaps as background tiles because that’s what the hardware has limited us to. Instead we use TileMaps because the concept of tile based art which grew around background tile maps is a common technique used by graphic artists in the industry… and it’s common because we used to use them due to hardware limitations. (analogy - it’s the same reason we use 24fps for film, despite the fact that we could use any… it’s just that way of doing it is historically common)

And Tiles are intended to be pulled from TileMaps to better facilitate you in the art department since many scenes are really just repeating elements of the same tile set. They’re not really there to save you memory (though that is a tangential benefit of them… though you can save that same memory in other ways), but also to save you time arting up a level by allowing you to paint a scene as a series of tiles rather than pixel by pixel.

TLDR;

Use TileMaps for tiled images.
Use Sprites for independent moving images.

2 Likes

Thanks for the reply, very informative

On the questions, on sprite.create i used the same texture2d from which the tile’s sprite derives

Am I conflating the terms sprite and tilemap? I just want to make clear that everytime I referred to a sprite in the last post I was referring to the .sprite parameter of the tile.asset. All the sprites I refer to are static sprites to which a tile refers to to decide what it will render. This question is only about tiles and the sprites that a tile can render by using Tile.sprite = Sprite;

I am creating these tile sprites dynamically from code and the question I had is if it is worth it to duplicate a tile for each sprite. I will try to make it clearer:

I am ingame and I use sprite.create to create 3 sprites - grass A, grass B, grass C

Now I have grasses A,B and C but no tiles linking to them
So now I can instantiate 3 empty tiles XYZ each with grass ABC
Then I can set tile X, tile Y and tile Z
Or I can, have 1 tile T, use tileT.sprite = grass A, settile T (grassA now), tileT.sprite = grass B, settile T (grassB now), etc for any number of tiles while having only 1 tile asset in practice

Note that I am setting these tiles always in runtime so there is never a refresh that forces the previously laid tiles to all change to the same sprite(the one currently held by tile T)