How Might I optimize My Code To Perform Better?

Hi! I’m creating a storm system that has an “animation” effect by constantly updating the CFrame of some cloud meshes. And although I’m satisfied with the appearance, the performance, on the other hand, is horrid due to the amount of parts being created (which are also destroyed after a certain amount of time). Here’s my code (or at least a part of my code involving the “animate” local functions which are connected in parallel with RunService.Heartbeat):

local function cloudBaseAnimateDo(): nil -- GOOD
	for _, cloudBase in pairs(baseCloudFolder:GetChildren()) do
		local angleDistanceVal = cloudBase.angleDistanceVal;
		local rotationVal = cloudBase.rotationVal;
		if(angleDistanceVal.Value <= 0) then
			task.synchronize();
			cloudBase:Destroy(); -- For now just have it destroy
		else
			task.synchronize();
			cloudBase.CFrame = centerPart.CFrame 
				* CFrame.fromEulerAnglesXYZ(0, rotationVal.Value, 0) 
				* CFrame.new(0, 1000, angleDistanceVal.Value * someWeatherVal.Value);
			angleDistanceVal.Value -= 0.5; -- 0.5 for LP	
			rotationVal.Value += 0.0007; -- 0.0007 for LP
		end
		task.desynchronize();
	end
end

-- "Animates" the cumulonimbus clouds by giving them a rotation effect
local function cumulonimbusAnimateDo(): nil -- GOOD
	for _, cumulonimbusSubFolder in pairs(cumulonimbusFolder:GetChildren()) do
		local positionalVal = cumulonimbusSubFolder.positionalVal;
		local offsetVal = cumulonimbusSubFolder.offsetVal;
		--											VVVV Will need to change this later (just calculate the distance for that)
		if(positionalVal.Value.Y >= 25176) then
			task.synchronize();
			cumulonimbusSubFolder:Destroy() -- For now just have it destroy
			task.desynchronize();
		else
			task.synchronize();
			offsetVal.Value += Vector3.new(0, 1, -0.7);
			positionalVal.Value = ((centerPart.CFrame + Vector3.new(0, 300, 0))
				* CFrame.new(offsetVal.Value)).Position;
			task.desynchronize();
			
			for _, cumulonimbus in pairs(cumulonimbusSubFolder:GetChildren()) do
				if(cumulonimbus:IsA("Part")) then
					local rotationVal = cumulonimbus.rotationVal;
					local posVal = cumulonimbus.positionalVal;
					task.synchronize();
					rotationVal.Value += 0.0006;
					cumulonimbus.CFrame = CFrame.new(positionalVal.Value)
						* CFrame.fromEulerAnglesXYZ(0, rotationVal.Value, 0)
						* CFrame.new(posVal.Value.X, 0, posVal.Value.Z);
					task.desynchronize();
				end
			end
		end
	end
end

-- "Animates" the upper cumulonimbus clouds
local function upperCumulonimbusAnimateDo(): nil -- GOOD
	for _, cumulonimbus in pairs(upperCumulonimbusFolder:GetChildren()) do
		local positionalVal = cumulonimbus.positionalVal;
		if(positionalVal.Value.Z <= -42000) then
			task.synchronize();
			cumulonimbus:Destroy();
			task.desynchronize();
		else
			if((positionalVal.Value.Y >= 23000) and not cumulonimbus.isAnvil.Value) then
				task.synchronize();
				cumulonimbus.isAnvil.Value = true;
				tweenService:Create(cumulonimbus.cloudMesh,
					TweenInfo.new(65, Enum.EasingStyle.Linear),
					{Scale=Vector3.new(13000, 2000, 13000)}):Play();
				task.desynchronize();
			end
			task.synchronize();
			positionalVal.Value += Vector3.new(0, 
				((positionalVal.Value.Y <= 23000) and 1.5) or 0, -2);
			cumulonimbus.CFrame = centerPart.CFrame + positionalVal.Value;
			task.desynchronize();
		end
	end
end

-- A general function that updates the CFrame for instances of the storm
local function updateCFrameDo(): nil -- GOOD
	local function cframeAroundMain(instance: part): nil -- GOOD
		local positionalVal = instance.positionalVal;
		task.synchronize();
		instance.CFrame = CFrame.new(centerPart.Position.X + positionalVal.Value.X,
			positionalVal.Value.Y, centerPart.Position.Z + positionalVal.Value.Z);
		task.desynchronize();
	end
	
	for _, folder in pairs(toCFrameFolder:GetChildren()) do
		for _, object in pairs(folder:GetChildren()) do
			if(object:IsA("Folder")) then
				for _, instance in pairs(object:GetChildren()) do cframeAroundMain(instance); end
			else  cframeAroundMain(object);
			end
		end
	end
end

I tried having them connected in parallel to improve the performance but after a while, the performance reduces and the game drops a few frames. I checked the microprofile and am not sure if anything has changed. Anyone know how I can improve this code? Many thanks! : )

Consider using object pooling:

Essentially what it means is that, instead of repeatedly destroying and creating the objects, you store the object somewhere hidden away from view, and reuse it once it’s needed again. The drawback is that you won’t be able to randomly generate the appearance of the clouds if you’re currently doing so, but you can mitigate this issue by randomizing the position, rotation and color of the clouds to make them seem different :slight_smile::+1:

Interesting, I never thought about this! However, I’m sure that even with his approach the performance will remain as is since, within each frame, the functions (as shown above) each call GetChildren() on a corresponding folder and immediately iterate through said folder. I’m gonna first lower the rate at which I create the parts and if that doesn’t work I’ll try this method out. I appreciate the suggestion though! : )

1 Like