I’m trying to do full auto weapon, however can’t get the wait time accurate. If FireRate is set at like 10000 (10,000 bullets / second), I’m getting no where close to that number.
while MouseDown do
local CurrentTick = tick()
local WaitTime = 60 / EquippedWeapon.Config:GetAttribute("FireRate")
while tick() - CurrentTick < WaitTime do
RunService.Heartbeat:Wait()
end
end
I’ve also tried wrapping it in a Heartbeat function, but then it fires way too many, and I can’t get the right wait time.
You’ll have to queue multiple rounds every frame. This is a good practice even with lower round per minute weapons as low FPS can affect weapon fire rate.
Fire multiple bullets each frame. Keep track of when the last bullet was fired and loop till TimeLast+(1/10000*60)*i>TimeCurrent.
local timeLast = os.clock()
while Heartbeat:Wait() do
local timeCurr = os.clock()
while timeCurr-timeLast>=1/10000*60 do
--fire
timeLast+=1/10000*60
end
end
If you only fire one bullet per heartbeat then the maximum rate of fire you can achieve is limited by the rate at which heartbeat fires. Instead you should fire multiple bullets instead.
local FIRE_RATE = ...
function startFiring()
local startTime = os.clock()
local fired = 0
return RunService.Heartbeat:Connect(function (step)
local elapsedTime = os.clock() - startTime
local totalBullets = elapsedTime * FIRE_RATE
for i = 1, totalBullets - fired do
fire()
end
fired = totalBullets
end)
end
This method returns an RBXScriptConnection which you should disconnect when you want to stop firing.
Looks promising, I’ll have to try it out when I get home.
My only other concern is how could I keep this secure on the server too?? I can’t remember exactly what I’m doing, but I basically save their tick() when they shoot, if they shoot again I check their last tick() and make sure it’s been enough time (from the FireRate) for them to shoot again
You need to keep track of how many bullets the client has available and how many they have fired. Then just make sure over some period of time (such as a second) they don’t exceed the rate of fire (and if they do, it’s not by much).
Unsure if my implementation is a little off, but it seems to do like a burst, stop, burst, stop, etc.
Fire rate is set at just 1. If I do like 10, its way too many bullets then.
local startTime = os.clock()
local fired = 0
Heartbeat = RunService.Heartbeat:Connect(function(step)
if Player:GetAttribute("Sprinting") then return end -- Sprinting
if not MouseDown then return end
local elapsedTime = os.clock() - startTime
local totalBullets = elapsedTime * EquippedWeapon.Config:GetAttribute("FireRate")
for i = 1, totalBullets - fired do
if Player:GetAttribute("Sprinting") then break end -- Sprinting
if not MouseDown then break end
-- Raycast from the mouse to get position
local Mouse = UserInputService:GetMouseLocation() or Player:GetMouse()
local UnitRay = Camera:ScreenPointToRay(Mouse.X, Mouse.Y)
local MouseRaycast = workspace:Raycast(
UnitRay.Origin,
UnitRay.Direction * 1000,
CastParams
)
local MousePosition = MouseRaycast.Position
local FirePoint = Weapon.FirePoint.WorldPosition
Bullet.Fire(
Player, -- Player who fired
Character.Weapon, -- Weapon model
true, -- Fired
MousePosition, -- To
FirePoint -- From
)
Recoil() -- Create recoil effect
fired = totalBullets
end
end)
What I’m after is a constant flow of bullets, using the one loop type, but editable in their fire rate, so i should be able to have an automatic gun that fires 1000 rounds a minute, and another (with the same loop) firing say 100 rounds a minute
FIre rate set at 10 at the start of the video. Seems to be a lot more bullets than 10 a minute (obviously 10 a minute isn’t really auto, but when I set it to like 100 or even 1000 my studio crashed)
When I’m firing, I’m holding the house down the whole time. So when I set it to 1, and 0.5, my mouse is being beld down, but there’s a large gap between rounds.
btw I would recommend not using while loops, they just lag out a LOT. Also Heartbeat is limited, if it were 10,000 you would need like 10,000 fps I’m pretty sure. Anyways, it’s impossible to get that high basically unless you group bullets for instance shoot 1000 every 0.1 seconds, you won’t even see the difference though as 0.1 is basically to short, try to do 0.01 and 100 bullets though, it’ll be even less visible
This is because you never change the values of startTime and fired. These need to be reset every time the gun starts firing.
Keep in mind you don’t need to listen to heartbeat all the time, only while the user is holding the fire button. So you can move most of your logic for firing/stop firing out of the event handler entirely.
I’m unsure what you mean by never changing the values of startTime and fired?? I don’t know what they should be set to? With my code, they are being reset every time I start firing, even so, I can’t get it any different to the video in my previous response
The heartbeat is wrapped inside the inputBegan function, and I disconnect it on InputEnded
--// Input began
local function InputBegan(input, GPE)
if GPE then return end
if Humanoid.Health <= 0 then return end -- Dead
if input.UserInputType ~= Enum.UserInputType.MouseButton1 and input.UserInputType ~= Enum.UserInputType.Touch then return end
if Player:GetAttribute("Sprinting") then return end -- Sprinting
local Weapon = ViewModel:FindFirstChild("Weapon")
if not Weapon then return end
local EquippedWeapon = Weapons:FindFirstChild(PlayerData.Equipped.Value)
if not EquippedWeapon then return end
if not CanFire then return end -- Can't fire yet
MouseDown = true
local Auto = EquippedWeapon.Config:GetAttribute("Auto")
if Auto then -- Automatic fire
CanFire = false
local startTime = os.clock()
local fired = 0
Heartbeat = RunService.Heartbeat:Connect(function(step)
if Player:GetAttribute("Sprinting") then return end -- Sprinting
if not MouseDown then return end
local elapsedTime = os.clock() - startTime
local totalBullets = elapsedTime * EquippedWeapon.Config:GetAttribute("FireRate")
for i = 1, totalBullets - fired do
if Player:GetAttribute("Sprinting") then break end -- Sprinting
if not MouseDown then break end
-- Raycast from the mouse to get position
local Mouse = UserInputService:GetMouseLocation() or Player:GetMouse()
local UnitRay = Camera:ScreenPointToRay(Mouse.X, Mouse.Y)
local MouseRaycast = workspace:Raycast(
UnitRay.Origin,
UnitRay.Direction * 1000,
CastParams
)
local MousePosition = MouseRaycast.Position
local FirePoint = Weapon.FirePoint.WorldPosition
Bullet.Fire(
Player, -- Player who fired
Character.Weapon, -- Weapon model
true, -- Fired
MousePosition, -- To
FirePoint -- From
)
Recoil() -- Create recoil effect
fired = totalBullets
end
end)
end
end
Local dt = 0
While mouseDown do
fire()
while dt < fire rate do
dt += heartbeat:Wait()
end
dt = 0
end
This should work a bit better but is still frame rate influenced, what you should use instead is a time accumulator which is in fact frame rate independent.