Function causes massive lag spikes on mobile

i made a function that creates and plays a sound when stepping on a part, but it has insane lag spikes on mobile and i cant figure out why

local function playSound(keycode: string, parent: Object, volume: number)
	if not keycode then return end

	local keyData = Keys[module.Sound][Enum.KeyCode[keycode]]
	if not keyData then return end
	
	local tpos = keyData[1] / 1000
	local duration = keyData[2] / 1000
	
	local sound = Sounds.Keys:FindFirstChild(module.Sound):Clone()
	if not sound then
		warn(module.Sound, "is not a valid sound.")
	end
	
	sound.Name = module.Sound .. os.time()
	sound.Parent = parent or workspace
	sound.TimePosition = tpos
	sound.Volume = volume or sound.Volume

	if not sound.IsLoaded then
		sound.Loaded:Wait()
	end
	
	sound:Play()
	Debris:AddItem(sound, duration + 0.1)
end

keycode is an attribute from the part that is being touched
module.Sound is the name of the sound
keydata is a table with multiple items of this format:

[Enum.Keycode.A] = {number, number}

if you have any idea what happens please let me know!!!

I’d say try this:

local ModuleSound = module.Sound
local KeySounds = Sound.Keys

local function playSound(keycode: string, parent: Object?, volume: number?): ()
	if not keycode then return end

	local keyData = Keys[ModuleSound][Enum.KeyCode[keycode]]
	if not keyData then return end

	local tpos = keyData[1] * 0.001
	local duration = keyData[2] * 0.001

	local sound = KeySounds:FindFirstChild(ModuleSound)
	if not sound then
		warn(ModuleSound, "is not a valid sound.")
        return
	end

	local clonedSound = sound:Clone()
	clonedSound.Parent = parent or workspace
	clonedSound.TimePosition = tpos
	clonedSound.Volume = volume or clonedSound.Volume
	
	clonedSound:Play()

	task.delay(duration, function()
		clonedSound:Destroy()
	end)
end

Hey there, I’m not an expert when it comes to performance, however, I would consider using sound pooling (if possible), since that will only load the sound once and make it reusable.
Operations like sound loading (sound.Loaded:Wait()), sound parenting are def expensive network operations, this can be felt even better on mobile devices. I would clone all required (or most likely required) sounds into the object where it’s used and use play() more times / reuse items. By reusing a fixed number of objects, you prevent the engine’s garbage collector from having to work as hard, which reduces intermittent lag spikes.

Little tip, if needed:
Using ContentProvider:PreloadAsync ensures the sound data is already downloaded before the game starts, eliminating the need for sound.Loaded:Wait().

I would be very surprised if that code is what is causing your lag spike (it could be that the function in question is being called thousands of times due to a bug)

What lead you to determine that that code is the culprit? If you have a micro profiler dump, could you share it?

chatgpt said this too but the sound is played every time you step on a part, and the floor is made of multiple parts, and you step on at least 2-3 at once so thats not really reliable

i call this when you step on a part, when i remove it the lag spikes dissapear

You should provide the code that calls the function. You can also check this youtube video, which shows how to use the micro profiler. The micro profiler imo is a must when doing performance optimization

i did use that but my pc is good and can handle it, and it doesnt show up on mobile for some reason

this is where i call the function, its the part.Touched event

function module:onTouch()
	self.TouchingParts += 1
	if self.TouchingParts > 1 or self.Touched then return end
	
	self.Touched = true
	local Part = self.Part
	local Keycode = self.Model:GetAttribute("Keycode")
	
	TweenService:Create(
		Part,
		TweenInfo.new(0.2, Enum.EasingStyle.Quart, Enum.EasingDirection.Out),
		{
			Position = self.Origin.Position + Vector3.new(0, -Part.Size.Y * 0.9, 0)
		}
	):Play()
	playSound(Keycode, Part, 1)
end

if i remove the playsound function the spikes dissapear so its not anything else in the code

thats the same thing

This text will be blurred

playSound() can cause lag is called hundreds of times, while the other code in the :onTouch() method is less costly, so it might still be something beforehand

Also, does the lag spike happen the first time you walk on the part? Or does it get increasingly bad? I had a bug once caused by a function getting connected more and more, without disconnecting, causing a function to get called hundreds of times

Is the :onTouch() method being called directly by a .Touched() connection on a basepart? But it’s a method so I’d assume there is a bit of code in between .Touched and the function, could I see what that code is?

If it isn’t coming from code you didn’t share, you’ll have to look into the micro profile

the whole thing overall is called like this in a local script

local Module = require(script.ModuleScript)
for _, model in workspace.Keys:GetChildren() do
	if model:IsA("Model") then
		Module.new(model)
	end
end

then the .new function is this:

function module.new(model: Model)
	local self = setmetatable({}, module)
	self.Model = model
	self.Part = model:WaitForChild("Part")
	self.MeshPart = model:WaitForChild("MeshPart")
	self.Origin = self.MeshPart:GetPivot()
	self.TouchingParts = 0
	self.Touched = false
	
	self:setupKeys()
	return self
end

and this is the setupkeys function:

function module:setupKeys()
	local Part = self.Part
	
	Part.Touched:Connect(function()
		self:onTouch()
	end)
	
	Part.TouchEnded:Connect(function()
		self:onTouchEnded()
	end)
end

the spikes happen as you step on the parts, basically when the sound is played

EDIT: this part is the one that causes lag spikes, its the keyData[1/2] (still cant figure out why though)

local tpos = keyData[1] / 1000
local duration = keyData[2] / 1000
1 Like

I’m willing to bet the touched event for this has no debounce, and as a result, is calling an excessive number of times. The function on it’s own shouldn’t be laggy, but doing it a bunch of times at once is. Add a debounce if you haven’t already.

no, its only called once when the player steps on it then it returns if it keeps detecting other touches, the sound doesnt play multiple times
also i found the issue but idk how to fix it (check my last reply)

Is keyData a metatable? If so, does it trigger something when you index it?

1 Like

no, its a module that returns this

return {
  Default = {
		[Enum.KeyCode.One] = {12946, 191},
		[Enum.KeyCode.Two] = {13470, 190}, etc
  }
}

then i do local Keys = require(module)
keyData = Keys[name][Enum.KeyCode[keycode]

This probably isn’t the culprit then. Run a benchmark on this alone and see what happens.

Well that definitely ain’t it, and I don’t see anything in the code that could cause the issue

I would really suggest you make a micro profiler dump, you can post it here and I can look at it. Make sure the lag spike is in the micro profiler dump

thats not possible, this only happens on mobile and the microprofiler doesnt work there

My guess would be at it also happens on desktop, but since desktops are usually much more powerful, it isn’t noticeable. But either way, here is how you can use the micro profiler from a mobile device: https://create.roblox.com/docs/en-us/performance-optimization/microprofiler#profile-mobile-devices