You could use the UserInputService to detect if the mouse button is pressed.
something like:
local uis = game:GetService("UserInputService")
tool.Activated:Connect(function()
repeat
--shooting code
wait(0.1) --shooting cooldown
if not uis:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) then break end
until
not uis:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) --this line will check if the given mouse button, MouseButton1, is being held or not.
end)
I have used a similar system before, and it has worked for me.
Looping outside of the functions.
Creating a new loop for everytime you fire the gun will just cause lag.
local IsShooting = false; -- to determine whether you can fire or not
Tool.Activated:Connect(function() -- fire when the weapon is activated
IsShooting = true;
end)
Tool.Deactivated:Connect(function() -- fire when the weapon is deactivated
-- this will not fire until you let go of your button
IsShooting = false;
end)
while true do
if IsShooting then
-- fire if you are shooting
else
-- stops shooting
end
task.wait(Firerate) -- yield time for each activation
end
I believe there is more efficient way to doing this, so you dont have to create a loop for every weapon, however I still need to figure that out.
Spawn a separate thread that handles the firing when the tool is activated and cancel the thread when deactivated.
local fireThread = nil
local function CanFire()
-- Returns true if we can shoot right now, e.g. we have enough ammo
end
mouse.Button1Down:Connect(function()
fireThread = task.spawn(function()
while task.wait(FIRERATE) do
if not CanFire() then
-- Skip this fire attempt and wait for the next one
continue
end
-- Fire server, reduce ammo, etc.
end
end)
end)
mouse.Button1Up:Connect(function()
if fireThread then -- Check if we're firing
task.cancel(fireThread) -- Stops the while loop
fireThread = nil
end
end)
Here’s some code I use in my FPS Projects structured for your reference.
Try dropping it directly into an empty tool and mess around with it before putting it to use.
-- // Services
local RunService = game:GetService("RunService")
-- // References
local Tool = script.Parent
-- // Settings
local mag_ammo, reserve_ammo = (30), (30 * 100)
local fire_rate = 800 -- RPM (Rounds Per Minute)
-- // Variables
local trigger_down = false
local next_fire_time = 0
local fire_delay = 1 / (fire_rate / 60)
local fire_mode = "FULL_AUTO"
-- // Functions
local function Fire()
mag_ammo -= 1
print("Pew!")
print(mag_ammo.." / "..reserve_ammo)
end
local function OnToolActivated()
trigger_down = true
end
local function OnToolDeactivated()
trigger_down = false
end
local function OnCameraUpdate()
-- // Shoot Code
if (trigger_down and mag_ammo > 0 and time() > next_fire_time) then
next_fire_time = time() + fire_delay
if (fire_mode == "SEMI_AUTO") then
Fire()
trigger_down = false
elseif (fire_mode == "FULL_AUTO") then
Fire()
elseif (fire_mode == "BURST_AUTO") then
next_fire_time = time() + fire_delay + .3
for i = 1, 3, 1 do
if (mag_ammo < 1) then break end
Fire()
task.wait(fire_delay)
end
trigger_down = false
end
end
----------------
end
-- // Events
Tool.Activated:Connect(OnToolActivated)
Tool.Deactivated:Connect(OnToolDeactivated)
RunService:BindToRenderStep("camera_update", Enum.RenderPriority.Camera.Value, OnCameraUpdate)
It Supports SEMI, FULL, and BURST. Hope this helps!