Lag spikes whenever gun is shot

Hi developers,

I recently inserted a map into my gun system testing place and i began to notice lag spikes every time i shot a gun. Looking at the micro profiler, the graph goes straight up whenever you shoot a gun. This also results in a framerate drop of about ~10 fps.

After looking into i found that this lag spike is caused by changing the size and position of a part (to look like a laser coming out of the barrel of the gun).

This is the offending code, which again is called every time a gun is shot, so multiple times per second:


function utils.visualiseRaycast(origin: Vector3, dir: Vector3?, range: number?, bullet: Part)

	bullet.Size = Vector3.new(bullet.Size.X, bullet.Size.Y, range)
	bullet.CFrame = CFrame.new(origin, origin + (dir * range)) * CFrame.new(0, 0, -range / 2)

end

task.spawn(function()
		
		local laserPart: Part = bulletCache:GetPart()
		laserPart.Color = bulletColour

		utils.visualiseRaycast(origin, dir, length or gunInfo.stats.range, laserPart)
		
		task.wait(duration)

		bulletCache:ReturnPart(laserPart)

	end)

(partcache is a module that caches parts to be used multiple times, see: PartCache, for all your quick part-creation needs)

So if the issue is changing the size and position of a part, how can i optimise this so the there is no lag or the lag is negligible?

Also, the lag gets more noticeable the more parts are in the game (i.e a high detail map makes the gun system lag heaps).

You can see for yourself here (make sure to turn on the micro profiler): TPS - Roblox

Thanks,

- snake_case

1 Like

Maybe instead of creating the bullet every time you shoot you clone a model in server storage instead.

It doesn’t create a part each time, instead it gets an existing part from a pool of parts. Thats what the PartCache:GetPart() function does.

Then uh. Sorry, I don’t know much.

after doing some more research, it seems that changing the size of the part is whats causing the lag, not changing the position, which makes sense, because manipulating CFrames is cheap (and rightly so), but changing the size is changing the geometry of the instance, which would be more expensive that setting the CFrame. So now the question is, how do i optimise changing the size of parts multiple times per second?

The issue is probably something else unrelated to changing the size of the part, what other operations are you doing in your code when shooting the gun?

A raycast, as well as setting the position of another PartCache’d part to the barrel of the gun and enabling a light and playing a sound on that.

This is the shooting function (also this is on the client):

function utils.standardFire(self, gunInfo, gunModel, fireAnim: AnimationTrack, ammo, fxHandler: () -> nil, fireInputString: string, serverInputParams: {any}, inputResultHandler: ({any}) -> nil)

	task.wait()

	if tick() - self.lastShot <= gunInfo.stats.firerate / (60 * 60) and self.lastShot ~= 0 then 
		return
	end

	self.lastShot = tick()

	ammo:decrement()

	task.spawn(function()

		fireAnim:Play()

		-- sound and light fx
		fxHandler()

		local result = table.pack(remotes.inputFunction:InvokeServer(fireInputString, unpack(serverInputParams)))

		inputResultHandler(result)

	end)

	self.lastShot = tick()
	return true

end

and this is what that fxHandler function is calling:

function utils.standardFx(gunModel: Model, gunInfo: {}, origin: Vector3, dir: Vector3, length: number, fxCache: {}, bulletCache: {}, lightName: string, soundName: string, duration: number, bulletColour: Color3)

	task.spawn(function()
		local fxPart: Part = fxCache:GetPart()
		fxPart.Position = gunModel.PrimaryPart.Position

		local soundDone, lightDone = false, false

		local partLight: PointLight = fxPart[lightName]
		partLight.Enabled = true

		local partSound: Sound = fxPart[soundName]
		partSound:Play()

		partSound.Ended:Once(function()
			soundDone = true
		end)

		task.wait(duration)

		partLight.Enabled = false
		lightDone = true

		repeat task.wait() until soundDone and lightDone

		fxCache:ReturnPart(fxPart)

	end)


	-- show laser
	task.spawn(function()
		
		local laserPart: Part = bulletCache:GetPart()
		laserPart.Color = bulletColour

		--[[local rayParams = RaycastParams.new()
		rayParams.FilterType = Enum.RaycastFilterType.Blacklist
		rayParams.FilterDescendantsInstances = {workspace.FxContainer, game.Players.LocalPlayer.Character}

		local clientRaycast = workspace:Raycast(origin, dir * gunInfo.stats.range, rayParams)]]

		utils.visualiseRaycast(origin, dir, length or gunInfo.stats.range, laserPart)
		
		task.wait(duration)

		bulletCache:ReturnPart(laserPart)

	end)

end

The reason i think the issue is changing the size of these parts is because when i comment out the line that changes the size of the part the lag spikes disappear.

I ended up replacing the parts with a beam. The lag spikes have stopped.

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