- What do you want to achieve?
I’m making a automatic weapon (submachine gun), but I’m not sure how to handle rapid-firing. So far, I have it so it fires once every time the user clicks their mouse, but I need to do it in a loop
- What is the issue?
- I’m not sure how I should do it.
Doing a loop on the client controlled by mouse state means constantly firing a remote function, which could create latency problems and be potentially exploitable
Doing a loop on the server seems impossible since I can’t grab mouse position from the client, and setting a Vector3Value wouldn’t work since those changes won’t replicate to the server
I’m not even sure if I’m overthinking this and should just go with a solution and figure out the problems later
- What solutions have you tried so far?
I found a single devforum post that somewhat matched my problem, but it didn’t gain much attention
client-side localscript
local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer
local CurrentCamera = workspace.CurrentCamera
local Mouse = LocalPlayer:GetMouse()
local Tool = script.Parent
local Equipped = false
Tool.Equipped:Connect(function()
Equipped = true
end)
Tool.Unequipped:Connect(function()
Equipped = false
end)
Mouse.Button1Down:Connect(function()
local Hit = Mouse.Hit.Position
local _, IsVisible = CurrentCamera:WorldToScreenPoint(Hit)
if Equipped and IsVisible then
local DidHit = Tool.Fire:InvokeServer(Hit)
print(DidHit)
end
end)
task.wait()
script.Parent = LocalPlayer.PlayerScripts
Server-side OOP code
local SMG = {}
SMG.__index = SMG
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local t = require(ReplicatedStorage.t)
local GunUtil = require(script.Parent.Parent.GunUtil)
local FireValidator = t.tuple(t.instanceIsA("Player"), t.Vector3)
local Damage = 5
local FireRate = 0.1
function SMG.new(plr:Player)
local self = setmetatable({}, SMG)
self.Tool = script.SMG:Clone()
self.Player = plr
self.Tool.Parent = plr.Backpack
self.Params = RaycastParams.new()
self.Params.IgnoreWater = true
self.Tool.Fire.OnServerInvoke = function(Player, Hit)
if Player == plr and FireValidator(Player, Hit) then
return self:Fire(Hit)
end
end
local CharacterAddedConnection = plr.CharacterAdded:Connect(function(Char)
self:SetActive(ServerScriptService.TimeSystem.CurrentGameState.Value == "Fighting")
local Humanoid = Char:FindFirstChildWhichIsA("Humanoid")
Humanoid.Died:Once(function()
self:SetActive(false)
end)
end)
local Humanoid = plr.Character:FindFirstChildWhichIsA("Humanoid")
Humanoid.Died:Once(function()
self:SetActive(false)
end)
local PlayerRemovingConnection = Players.PlayerRemoving:Connect(function(x)
if x == self.Player then
self:Destroy()
end
end)
self.Connections = {
CharacterAddedConnection,
PlayerRemovingConnection
}
--self:SetActive(ServerScriptService.TimeSystem.CurrentGameState.Value == "Fighting")
end
function SMG:Destroy()
for k, v in pairs(self.Connections) do
v:Disconnect()
end
end
function SMG:SetActive(Active)
if not Active then
self.Tool.Parent = ServerStorage.CombinedInventory
else
self.Tool.Parent = self.Player.Backpack
end
end
function SMG:Fire(Hit:Vector3)
local Origin = self.Tool.SMG.SMG.TipAttachment.WorldPosition
self.Params.FilterDescendantsInstances = {self.Player.Character}
local Result = GunUtil:Raycast(Origin, Hit, self.Params)
if not Result then
return false
end
GunUtil:CreateNonProjectileBeam(Origin, Result.Position)
self.Tool.SMG.SMG.Fired:Play()
local Humanoid = Result.Instance.Parent:FindFirstChild("Humanoid") or Result.Instance.Parent.Parent:FindFirstChild("Humanoid")
local DoesExist = Humanoid ~= nil
local IsDead
if DoesExist then
IsDead = Humanoid.Health == 0
if IsDead then
return false
else
Humanoid:TakeDamage(Damage)
end
end
return false
end
return SMG
Also feel free to critque any unrelated code I included, I do like trying to improve and learn new things and ways to accomplish tasks