#Coloring By Number Game Lag Problem

1 messages · Page 1 of 1 (latest)

rain cypress
#

Hi,

I’m developing a coloring-by-number game. In this game, I have a grid system that I generate dynamically based on JSON data. Each image creates a grid with a different size, and each grid cell holds its own data (like TMP, image, etc.).

For smaller images (like 16x16), everything works fine and I can zoom in and out smoothly. However, for larger images (like 64x64), I experience significant lag when zooming in and out.

There are other games on Google Play that handle this system very well, even with large images, but I can’t figure out how they achieve that level of performance.

What would you recommend for building an optimized system that allows smooth zooming in and out, even with larger grids?

Also, I’d appreciate it if you could first watch the video and ask for any additional details you might need.

#

Coloring By Number Game Lag Problem

tight jewel
# rain cypress Hi, I’m developing a coloring-by-number game. In this game, I have a grid syste...

If each of those squares has their own TMP text element within, I'm not particularly surprised it performs poorly. Minimizing the amount of objects is the key. If you can get away with only one image object with a shader that draws those numbers when you get closer, that would be the optimal solution. I'm thinking one solution would be to use a RenderTexture to draw every possible number in a grid similar to texture atlases and then read the needed number texture from that RenderTexture in shader

rain cypress
#

Actually, earlier my code was using the old Text system instead of TMP, and I didn’t have much of a performance issue back then. However, the text appeared blurry, which is why I switched to TMP. Now I’m facing performance issues instead. I’d like you to know this.

#

What I’m actually curious about is the most professional solution possible, and the exact kind of logic that high-quality games on the market use for this system.

tight jewel
#

TMP might be bit slower in general. Regardless using separate UI elements for each cell is not a great idea in terms of performance

rain cypress
#

Yes, yes, I’m aware of that, but I still don’t understand how a coloring-by-number system can be built using a single texture. The grid-based system seemed like the best solution to me.

tight jewel
#

With shader approach, the number of pixels you can have suddenly becomes nearly unlimited. It doesn't really change the performance at all regardless of how many cells to color there are

rain cypress
#

So with the system you mentioned, would I be able to track which cells are painted or not, and still have control over things like pan and zoom?

tight jewel
#

Sure, you would need to give more details on the painting system to get more specific help but it likely requires using multiple textures (like one for the correct colors, one for masking which are already colored and one for the different number texts) and combining them in shader. The exact design will depend on many things like whether you wanna ever allow coloring in wrong colors

rain cypress
#

Alright, I’ll try to switch to the system you suggested with the help of Cursor. If I run into any issues, I’d like to ask for your help again. Thank you.

tight jewel
#

Feel free to ping me on this thread if you need more help

rain cypress
# tight jewel Feel free to ping me on this thread if you need more help

My friend, I applied the method you suggested and significantly reduced the lag issue. But this time the numbers/text inside the cells look really weird. Is there a way to make them look like they did in the previous version? Is the problem with the text happening because it’s shader-based now? What would you recommend? You can compare the previous video with the current one if you want.

dull verge
tight jewel
#

Clearly something wrong with the shader that renders the numbers

#

If there are't too many different numbers to render, I would have used the render texture to render all the numbers at the correct scale (as if they were in the scene like you had them earlier) including the two digit ones every frame to keep the spacing of the characters correct and to also make them look nice at any scale. Now they look quite pixelated when viewed up close

rain cypress
# dull verge How does this one work exactly "Shader-based" could mean a lot of different thin...

Yes, the phrase “shader-based” was missing — I apologize. I’m new to game development and trying to build things with the help of AI, so I’m not very familiar with many technical terms. However, I had the AI summarize what we are doing as follows:
Before (legacy path): Each grid cell was its own UI object: an Image plus a TextMeshProUGUI child, laid out with GridLayoutGroup. On large grids that means thousands of GameObjects, lots of layout work, many batches, and real text meshes per cell.

After (GPU grid path): The whole grid is drawn as one RawImage using a custom UI shader (PixelArt/ColoringGridUI). Cell state isn’t stored as per-cell widgets; it’s stored in a few low-resolution textures (base tint per cell, packed cell “number id,” paint layer, and a 0–9 digit atlas). The fragment shader figures out which logical cell a pixel belongs to, samples those textures, and composites borders, zoom whitening, selection highlight, and the digits.

It doesn’t “replace Unity’s renderer” in some magical way. It replaces thousands of UI draw/layout/text updates with: one draw (typically) + cheap per-pixel math that reads 2D data and a glyph atlas. Digits aren’t live TMP anymore; they’re sampled from a pre-baked atlas (TMP rendered once to a render texture, or a fallback bitmap). Two-digit numbers split the cell in UV space and sample two glyphs.

The gain is not “we used a shader.” The gain is removing O(cells) UI objects and TMP instances and replacing constant UI churn with updating a few textures / uniforms (e.g. zoom fades as material floats, paint as texture writes). That cuts draw calls, batch fragmentation, and text mesh cost—especially when zooming or scrolling.

rain cypress
dull verge
rain cypress
dull verge
#

I would not like that
AI generated code even if it works is likely to have negative educational value due to the nature of them being a patchwork of random snippets

rain cypress
# tight jewel If there are't too many different numbers to render, I would have used the rende...

Bro thanks,
I took inspiration from your suggestion and implemented a similar approach, though slightly different for mobile performance:

What we did:

Instead of baking per-frame, we pre-bake all numbers 0–99 into a single atlas texture once at startup using TMP at 64×64 per slot (total: 6400×64 texture).
Each number — including two-digit ones like "18" — is rendered as a single TMP text centered in its own slot, so there's no more cell-splitting or size mismatch between single and double digit numbers.
The shader now just reads: u = (n + cellUV.x) / 100 — one lookup, no splitting logic.
Atlas uses Bilinear filtering for smoother zoom scaling.
Difference from your suggestion:

You suggested rendering at the correct scale every frame (or per-zoom-change), which would make numbers perfectly sharp at any zoom level.
We bake once at a fixed resolution (64px slot). This means at very close zoom, numbers may still soften slightly — but it avoids the per-frame RT cost, which matters on mobile.
If the quality still isn't good enough at max zoom, the next step would be either a larger slot size or re-baking when zoom crosses a threshold — essentially your original idea but triggered lazily.

tight jewel