So I’ve been working on an fps framework for my game, and I’m in the process of handling the firing of the weapon. However, when the user spam clicks the mouse, eventually the gun just breaks and stops shooting. How can I prevent this?
Scripts:
Handling firing
function module:fire(tofire)
if tofire == self.firing then return end
local check = replicatedStorage.events.isEquipped:InvokeServer()
if not check then return end
self.firing = tofire
while self.firing and not self.cooling do
local barrelPos
if not self.attachments[self.curwep] or not self.attachments[self.curwep].barrel then
barrelPos = self.viewmodel:FindFirstChild(self.curwep).nodes.barrel.muzzle.WorldCFrame
else
barrelPos = self.viewmodel:FindFirstChild(self.curwep):FindFirstChild(self.attachments[self.curwep].barrel.name).PrimaryPart.muzzle.WorldCFrame
end
local projectile = bullet.new(barrelPos, 10)
projectile:fire()
self.cooling = true
task.wait(self.settings.firerate)
self.cooling = false
end
end
bullet is a module (I’m mainly worried about the while loop)
Input handling
local function fire(name, state)
if state == Enum.UserInputState.Begin and not cooling then
user:fire(true)
elseif state == Enum.UserInputState.End then
user:fire(false)
end
end
Yeah, thats the code. However, when you spam click, I guess it’s experiencing input delay, and you cant fire anymore because it gets stopped at this argument:
Alright so i tried it with both spawn and coroutines, and it does seem to stop the weapon from breaking. However, you cant fire the weapon full auto anymore
task.spawn(function()
if not self.cooling then
self.cooling = true
task.wait(self.settings.firerate)
self.cooling = false
end
end)
task.wait(self.settings.firerate) -- or just task.wait()
I’m guessing I messed up since now there is no wait in the thread of the actual while loop, which causes the studio to crash or give u some runtime error.
Yeah realized after I posted it. Saw that the while loop stops if its cooling. As a desperate measure try removing the check
while self.firing do
local barrelPos
if not self.attachments[self.curwep] or not self.attachments[self.curwep].barrel then
barrelPos = self.viewmodel:FindFirstChild(self.curwep).nodes.barrel.muzzle.WorldCFrame
else
barrelPos = self.viewmodel:FindFirstChild(self.curwep):FindFirstChild(self.attachments[self.curwep].barrel.name).PrimaryPart.muzzle.WorldCFrame
end
local projectile = bullet.new(barrelPos, 10)
projectile:fire()
self.cooling = true
task.wait(self.settings.firerate)
self.cooling = false
end
The issue with this is that they can now spam click and get infinite firerate, thats the reason i added the check in the first place. Spam clicking in this scenario would cause a runtime error from all the while loops
Nah, that cooling check was a desperate measure, but in theory i could try implementing the check in the input script. But now thats a local script, meaning any hacker can access it and just remove the check…
local firing = false
local function fire(name, state)
if state == Enum.UserInputState.Begin then
firing = true
while firing do
user:fire()
task.wait(firerate)
end
elseif state == Enum.UserInputState.End then
firing = false
end
end
Module script:
function module:fire()
local check = replicatedStorage.events.isEquipped:InvokeServer()
if not check then return end
if self.firing and not self.cooling then
local barrelPos
if not self.attachments[self.curwep] or not self.attachments[self.curwep].barrel then
barrelPos = self.viewmodel:FindFirstChild(self.curwep).nodes.barrel.muzzle.WorldCFrame
else
barrelPos = self.viewmodel:FindFirstChild(self.curwep):FindFirstChild(self.attachments[self.curwep].barrel.name).PrimaryPart.muzzle.WorldCFrame
end
local projectile = bullet.new(barrelPos, 10)
projectile:fire()
task.spawn(function()
self.cooling = true
task.wait(self.settings.firerate)
self.cooling = false
end)
end
end
Though this might decrease performance since you’re firing the event every shot instead of toggling shooting (I think this is how it’s done in the roblox fps themplate but they need the player mouse position so its understandable, and you seem to be just shooting 10 studs forward or something like that)
Idea 2
Maybe we can check beforehand:
function module:fire(tofire)
if tofire == self.firing or self.cooling then return end
local check = replicatedStorage.events.isEquipped:InvokeServer()
if not check then return end
self.firing = tofire
while self.firing do
local barrelPos
if not self.attachments[self.curwep] or not self.attachments[self.curwep].barrel then
barrelPos = self.viewmodel:FindFirstChild(self.curwep).nodes.barrel.muzzle.WorldCFrame
else
barrelPos = self.viewmodel:FindFirstChild(self.curwep):FindFirstChild(self.attachments[self.curwep].barrel.name).PrimaryPart.muzzle.WorldCFrame
end
local projectile = bullet.new(barrelPos, 10)
projectile:fire()
self.cooling = true
task.wait(self.settings.firerate)
self.cooling = false
end
end
This would work, but I want to avoid implementing the loop in the input handler if I can. If there are no more solutions, I guess this is the best one.