Gun Firerate Slows Down With FPS Drops, I need solutions

So would this remove the need to use while loops (went with those since those didn’t seem to be tied to Framerate, but I was wrong) ?

I’m also assuming I would put the fire() function inside of the onRenderStepped() function.

I’m pretty certain while loops shouldn’t be tied to frame rate.

1 Like

They are for me for some reason. It could be really bad optimization on my part, but I’m not sure.

A while loop is a standard feature of Lua and is not specific to Roblox or to you. It has nothing to do with ‘frame rate’ unless you set it up so that each iteration yields until the next frame or something similar.

Regarding your original post: magnalite gave some helpful advice. The code that FracturedSoftware posted unfortunately will not work because they haven’t called the Connect method of the RenderStepped Event. What I imagine he is suggesting you do is use the parameter passed when the Event fires (time since last render frame) - this will help you follow magnalite’s advice:

7 Likes

to add to magnalite’s reply, also be aware of the difference between a variable time step as opposed to a fixed time step. RenderStepped’s step param is an example of a variable time step, because the user’s frame rate can change over time (i.e. each step is not exactly equal). Depending on what you’re doing (esp. physics calculations) this can introduce some subtle, hard-to-crack bugs; I learned this the hard way when I was attempting to create a deterministic billiard sim in Roblox Lua (TL;DR variable time step is neva eva deterministic)

to solve this problem, implementations typically use something called a time accumulator. Here’s a quick and dirty example:

local RenderStepped = game:GetService("RunService").RenderStepped
local GameRunning = true

spawn(function()
	local deltaT = 1/30 -- the fixed time step
	local currentTime = tick()
	local accumulator = 0
	while GameRunning do
		local newTime = tick()
		local frameTime = newTime - currentTime
		currentTime = newTime
		accumulator = accumulator + frameTime
		while accumulator >= deltaT do
			-- sim is ticked with the deltaT arg here
			accumulator = accumulator - deltaT
		end
		RenderStepped:Wait()
		-- interp can be done here
	end
end)

edit: something I forgot to mention - if you want to do interpolation, then the state of the last tick has to be cached (otherwise you have nothing to interpolate)

also, this example is not optimized - it can be by utilizing that step parameter from RenderStepped for frameTime instead of calculating it ourselves. Additionally, the above code will run VERY HOT, so you have to be extremely careful about what you’re doing in it

ANOTHER thing to consider (I know I’m making many edits :slight_smile: ) for more consistent performance: it may be a better idea to use RunService.Heartbeat rather than RunService.RenderStepped if what’s being done in this code is game logic (rather than visual effects), due to how the rendering pipeline works. @buildthomas provides a good overview of why here (I swear this is my last edit)

8 Likes

How fast does the gun shoot?

It doesn’t really matter if it’s 1.6 seconds (Pump Shotgun) or 0 seconds (Minigun.)

It just seems that the firing rate is tied to the framerate for some reason.

You mean 1.6 seconds per bullet for the pump shotgun and 0 seconds for Minigun? How does that work? You can’t have a 0 second wait, that’ll crash your game…

Doesn’t seem to crash for me, unless I have some kind of wait function in place already.

All I know is that the Minigun shoots as fast as it’s supposed to when the game’s not running badly. Which is about 10-20 bullets a second last I checked.

Lag is a problem that you need to attack by determining what you can make more efficient. Do this by following this procedure:
Are my users complaining about lag?
Is this affecting gameplay?
If you answer yes to any of those questions there is a problem, and your next step is determining what is causing all this lag you are facing.

You said that your pain screen lags… What is the current code for that ? There’s no reason for that to lag.

How many FPS are you users getting?

here’s a very simple “gun” script which will shoot 60 bullets per second completely independent of the user’s current frame rate:

local RenderStepped = game:GetService("RunService").RenderStepped
local Mouse = game.Players.LocalPlayer:GetMouse()
local Debris = game:GetService("Debris")
local shooting = false

local function shoot()
	
	local function spawnBullet()
		local bullet = Instance.new("Part")
		local bodyVelocity = Instance.new("BodyVelocity")
		bullet.Size = Vector3.new(1, 1, 1)
		bullet.CanCollide = false
		bullet.CFrame = game.Players.LocalPlayer.Character.Head.CFrame * CFrame.new(0, 0, -2)
		bullet.Parent = game.Workspace
		bodyVelocity.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
		bodyVelocity.Velocity = bullet.CFrame.LookVector.Unit * 500
		bodyVelocity.Parent = bullet
		Debris:AddItem(bullet, 10)
	end
	
	local deltaT = 1/60 -- fire rate
	local accumulator = 0
	local frameTime = 0
	
	shooting = true
	spawnBullet()
	while shooting do
		accumulator = accumulator + frameTime
		while accumulator >= deltaT do
			spawnBullet()
			accumulator = accumulator - deltaT
		end
		frameTime = RenderStepped:Wait()
	end
end

Mouse.Button1Down:connect(function()
	shoot()
end)

Mouse.Button1Up:connect(function()
	shooting = false
end)
8 Likes

Are the bullets being deleted after a while?

1 Like

Yes.
I’ve noticed recently that I get increasingly more lag every 10 seconds.

I’m wanting to say it has to do with the projectile weapons, but they’re removed after 30 seconds.

Here’s the game if anyone’s interested in seeing what the problem is. I don’t know if you guys will experience it to the extent I am.

Last question, are the bullets being ceased to exist? (Meaning they dissapear from the map entirerly)
If so it’s probally the script overcharge that the game has, probally the other scripts are lagging the other one because that one is charging while the other ones are charging.
If not, it may be the splashing amount of accumulated bullets from the world, if it’s a pump shutgon, it makes 6-8 bullets per 2 seconds (If spamming click) if you do the maths, that will be 4 bullets maximum stored.

1 Like

Also, when you first join a map, the Console is spammed with remote event errors, saying that a RemoteEvent is exhausted.

I might have a separate event to handle sending said projectiles to the clients, instead of relying on a single one to receive the single and send it to the rest of the players.

Fixed the errors mentioned.

My game looks like this occasionally.
Is there anyway to reduce the lag caused by these without nerfing the Plasma Rifle?

1 Like

Actually, I think the problem is my method of handling my custom explosions.

Can anyone send me in the direction of figuring out raycast explosions so I don’t have to rely on GetDescendants?

I’m planning on using Region3s, but you apparently can do Raycast explosions too.

Seems like an entirely different topic. Would you create a new topic, to make this more searchable for future people looking for the same answers?

Apologies for the long “accept.”

Recently ran into this issue again after thinking I had fixed it, came across this thread, and implemented your system above into my game and it works flawlessly.

Thank you!! :slight_smile:

Massive necropost but this code is very easily broken by clicking your mouse faster than the firerate

This is how I went about fixing it:

local Heartbeat = game:GetService("RunService").Heartbeat
local UIS = game:GetService("UserInputService")
local Debris = game:GetService("Debris")
local shooting = false
local wishShooting = false

local function shoot()

	local function spawnBullet()
		local bullet = Instance.new("Part")
		local bodyVelocity = Instance.new("BodyVelocity")
		bullet.Size = Vector3.new(1, 1, 1)
		bullet.CanCollide = false
		bullet.CFrame = game.Players.LocalPlayer.Character.Head.CFrame * CFrame.new(0, 0, -2)
		bullet.Parent = game.Workspace
		bodyVelocity.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
		bodyVelocity.Velocity = bullet.CFrame.LookVector.Unit * 500
		bodyVelocity.Parent = bullet
		Debris:AddItem(bullet, 10)
	end

	local deltaT = 60 / 600 -- fire rate
	local accumulator = 0
	local frameTime = 0

	shooting = true
	spawnBullet()
	while shooting do
		accumulator = accumulator + frameTime
		while accumulator >= deltaT do
			if wishShooting == false then
				shooting = false
			else
				spawnBullet()
			end
			accumulator = accumulator - deltaT
		end
		frameTime = Heartbeat:Wait()
	end
end

UIS.InputBegan:Connect(function(inputObject)
	if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
		wishShooting = true
		if shooting == false then
			shoot()
		end
	end
end)

UIS.InputEnded:Connect(function(inputObject)
	if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
		wishShooting = false
	end
end)