Working on a Pixel/Sprite Engine for roblox

Hey guys i been working on a pixel based game engine for roblox for a while now and i’ve run into a few problems…
Does anyone know if there is a limit for ui objects?
As when i add too any ui object, frames buttons, images etc they being to flicker and vanish.
So if there is a limit what is it?
What type of ui object count towards it?
Does an object being invisible stop it counting towards the limit?
Is there any ways to increase the limit? (doubling it would be amazing.)
And linking me any other documentation regarding roblox’s UI system would be awesome! I’ve looked but i cant find much of the technical stuff.
Anyways hope your game is going well too… Screenshots of project below… Take it easy dudes.


Title Screen

Game is alot like super mario maker

So you can not only create custom courses but add custom sprites and animations too

so you can basically paint whatever you want! like a frog on the moon!

1 Like

I don’t think there is an actual limit, none of the documentation I’ve seen would suggest. Likely things are vanishing as the client is handling memory. A few things I could recommend though:

UI elements that are invisible remove it from the rendering pipeline, but best practice is to set their Disabled status to True when they are not needed. Benchmarking may be needed to see if there is a practical benefit.

UI elements that become “off-screen” will begin to disappear; if they are flickering, perhaps they’re right at that edge. You can see this if you scale a frame to something like (5,0,5,0) and start moving it off-screen, it will eventually disappear despite part of it being visible at that time. Whether they’re deemed off-screen or not is dependant on their AbsolutePosition as far as I am aware.

Is it right to assume every tile is its own UI element? You might look into reducing the number of instances the client has to handle by implementing some form of greedy tiling (I believe that’s the right word? Same theory as greedy meshing in voxel rendering).

1 Like

GuiObjects don’t have a ‘Disabled’ property, are you referring to their ‘Active’ property perhaps?

3 Likes

Hey dude thanks for the reply… Just to correct things - I’m not using StarterGui, sprites are places within the workspace on parts. Each part has a surface gui with 1-64 frames on it depending on the shape of the sprite. So I may have kinda mislead by talking about GUI without clarifying - dunno how much that changes things tho…

Although they do appear to count towards the same limit (memory or not) i can stop the flickering by deleting parts with surface GUI’s or by setting enabled = false on Starter Gui objects.

Does anyone know what section of the Debug console GUI memory info is kept?

The property that seems to effect it as far as i can make out is SurfaceGui.Enabled and Frame.Visible…
I think im going to have to code a benchmarking program
I dont wanna lose one of my parallax scrolling layers :frowning:

im not sure what you mean by greedy tiling but its def given me an idea - hope it the one you meant XD

Perhaps you should still use Greedy Meshing and implement textures instead of surfaceGuis, except where needed.

1 Like

Yes there is actually a limit. Or at least there was at one point, I’m not sure if there still is. The limit was put into place in order to stop bad actors (mainly exploiters during the FilteringDisabled days) from generating inappropriate images using hundreds or thousands of tiny frames acting as pixels (thereby generating an image bypassing decal moderation). It may still be enforced as it could still be used that way, however the responsibility would obviously be on the game developer at that point.

Additionally, Roblox’s UI isn’t very performant. They did mention in a prior RDC that they’d be working to completely overhaul and improve it though.

1 Like

Cool thanks for confirming…Although im still more of the understanding that this is an inbuilt memory limit for roblox rather than a purposeful moderation decision. as i can quite easily create pictures up to 600x600… plenty of room to create an inappropriate image…
I think if im super clever i should be able to work within the limit and keep performance up… I will have to implement a report content and quarantine system… thanks for reminding me of that.

Well it may be memory as their update was just making pixels white. This was definitely purposeful as it worked before, then stopped working (becoming white).

1 Like

Really great resource… already implementing something similar… I should be able to reduce the usage of frame by most blocks by about 50% so i think thats more than enough gain to keep it running and avoid the flicker… I will have a problem with animated textures as they could still overlead the system… but i think i’ll just allow that… Like your shouldnt need every block animated and you certainly wont need ever block on each of the layer animated…
So yeah thanks guys think you helped fix this.

oh cool… yeah i guess thye must have abandoned that… things are defintly flickering and dissapearing rather than whiting out…

woop thanks guys - this is what i came up with - it only makes greedy rows but it runs so fast i can run it on every block on every tik and it saves about 60% on assets. YAY!

function module.greedySpriteFromTable(holder,spriteTable,paletteDictionary,transparency)
	local holderTable = holder:GetChildren()
	holderTable = quickSort(holderTable)
	--go through sprite table if next item in same row is of same value then add to bundle
	local rNo = 8
	local cNo = 8
	local rPos = 1
	local cPos = 1
	local greedyBundle ={}
	
	repeat
		rPos = 1
		repeat
			local currentCol = columns[cPos]
			local currentPos =currentCol[rPos]
			local colorChar = spriteTable[currentPos] 
			local colour = paletteDictionary[colorChar]
			local length = 1

			if colorChar == "z" then -- if pixel invisible
				holderTable[currentPos].Visible = false
			elseif spriteTable[currentPos] == spriteTable[currentPos+length] then -- if next pixel is same colour
				while rPos + length <= rNo and spriteTable[currentPos] == spriteTable[currentPos+length] do -- break loop if  colour check fails.
					holderTable[currentPos+length].Visible = false
					length = length +1-- increment length to check pixel after next
				end	
				table.insert(greedyBundle,{length,rPos,cPos,colorChar})
				rPos=rPos +length-1 --skip neighbouring pixels detected to have matching colours
			else
				holderTable[currentPos].BackgroundColor3 = colour
				holderTable[currentPos].Visible = true
				holderTable[currentPos].Size = UDim2.new(0.125,0,0.125,0)
				holderTable[currentPos].Position = UDim2.new(0.125*(rPos-1),0,0.125*(cPos-1),0)
				if transparency then
					holderTable[currentPos].BackgroundTransparency = transparency
				end
			end
			rPos = rPos+1
		until rPos > rNo
		cPos = cPos +1
	until	cPos> cNo

	--apply greedyBundle Changes
	for i,v in ipairs(greedyBundle)do
		local currentCol = columns[v[3]]
		local currentPos =currentCol[v[2]]
		local colorChar = spriteTable[currentPos] 
		local colour = paletteDictionary[colorChar]
		holderTable[currentPos].Size = UDim2.new(0.125*(v[1]),0,0.125,0)
		holderTable[currentPos].Position = UDim2.new(0.125*((v[2]-1)),0,0.125*(v[3]-1),0)
		holderTable[currentPos].BackgroundColor3 = colour
		holderTable[currentPos].Visible = true
	end
end
2 Likes

Do you have videos of this game too? This looks like a super cool project and I’d like to see more!

Soz dude its in a super broken state at the mo - im having to re-do everything from the ground up… Its going super well tho its like 200 times faster… means i might be able to add like 5 more parralax layers XD or double the sprite size… But i’ll try and keep you guys updated!

1 Like