Trying to improve performance of 2D game on Android

Godot Version

v4.4.1.stable.mono.official [49a5bc7b6]

Question

I am working on an android game and I want to see if I can make it run better. The game is a puzzle game where the board is made up of controls.

I currently have the project set to “compatibility” renderer based on this document.

Here is what the largest (11x11) board looks like:

This scene takes about 12ms to render on my phone:
Godot_v4.4.1-stable_mono_win64_2025-04-16_20-41-54

The game board canvas layer has a control node that houses all the tile controls, and a camera2d for zoom/pan movement

If I set visible = false on the root control of the board, the Render Canvas step goes from 12ms to 2ms. So I think this is where a majority of the render time is coming from.

Each tile on the board is a control with several children, but most of them are not visible.

This is what the base tile template looks like:

However when I setup the board, I try to free/remove everything possible.

else if (tile.Type == YardSweeperTileType.Loot)
{
	MyGrass.GuiInput += (inputEvent) => ClickTile(inputEvent, tile);

	var CoinSprite = TileButton.GetNode<TextureRect>("CoinSprite");
	CoinSprite.Visible = false;
	CoinSprite.Texture = GD.Load<Texture2D>("res://art/coin" + tile.Value + ".png");
	Label LootText = TileButton.GetNode<MarginContainer>("LootTextContainer").GetNode<Label>("LootText");
	LootText.Text = tile.Value + "";
	var SkullSprite = TileButton.GetNode<CanvasItem>("SkullSprite");
	SkullSprite.Visible = false;

	var GraveTextContainer = TileButton.GetNode("GraveTextContainer");
	TileButton.RemoveChild(GraveTextContainer);
	GraveTextContainer.Free();
	var GraveSprite = TileButton.GetNode("GraveSprite");
	TileButton.RemoveChild(GraveSprite);
	GraveSprite.Free();
	var VeinSprite = TileButton.GetNode("VeinSprite");
	TileButton.RemoveChild(VeinSprite);
	VeinSprite.Free();
	var RockSprite = TileButton.GetNode("RockSprite");
	TileButton.RemoveChild(RockSprite);
	RockSprite.Free();
}

Because of this, all the tiles should only have visible what is necessary to draw. While there are layers (coins below grass and above dirt), those are all visible = false, and removed and freed when possible.

So far I have tried changing out the TextureRects for Sprite2Ds, but I did not measure a performance change.

Is this normal performance for rendering ~200 textures on android? Are there any rendering improvements that I can make to this setup? thanks.

You don’t have a performance problem, but you shouldn’t ever tackle optimization by guessing.
You need to measure performance with the tools at hand : Godot internal profiler and then a third party profiler, usually made by the CPU(family) maker to get more precise timings.
You need to instrument your code, do statistical relevant profiling runs, and then talk about performance :wink:
Keep up the hard work, have fun,
And while premature optimization is the root of all (most?) evil, measuring early and often is a good approach.
Cheers!

1 Like

I’m not running any code while this scene is running, its entirely Godot trying to render it every frame.

While I do fine with ~12ms frames, I have friends who’s device run much slower. On this board he gets ~3 fps while the game is idle.

Since the textures were large (each tile about 312x312 pixels), I attempted to resize them down to see if that would help performance.

While running the profiler, I noticed some intermittent improvements with this approach. ~5-12ms frames instead of ~8-13ms frames. But the averages were very similar. Testing on the lower end device still resulted in the same poor performance.

I could in theory render everything out to a render target, and re-render sections when a tile is dug. That seems like a lot of work and doesn’t help when I want to animate the whole board moving.

I will also try out MultiMesh2D and TileMap to see if I get any results. The tiles have border radius and a shader to color them. I will see if prebaking all the tiles to a tileset will help.

This sounds almost like Low Processor Mode in project settings.

What renderer are you using? Screenshot looks like Compatibility renderer would be enough. You can also make a low resolution mode using Window → stretch mode = Viewport and having a viewport resolution lower than the device screens resolution.

I am using the compatibility mode renderer.

I think my performance is due to using shaders to color the tiles and corner radius set on panel containers.

I am going to prebake all the tiles and use a spritesheet instead. I believe this will help.

Shader can be very heavy sometimes. Especially if there are if-statements there. For simple coloring you can use the modulate property instead of a shader. That’s not at all heavy. Spritesheet might be even faster :+1:

1 Like

On average the frame times have gone to ~3ms from ~12ms. So getting rid of the shaders and corner radius on tiles made it run about 75% faster

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.