How do I fix the gun positioning

Hello there, So im making a gun in RobloxStudio and I found a slight issue, The guns bullet’s wont stay in place and it looks like the bullets are coming out of nowhere.

Here is the video: https://streamable.com/cvha53

The bullets don’t look like there coming out from the gun and it looks like its randomly coming from the air not the Nozel of the gun.

Here is my server script:

local Tool = script.Parent

local FlashPart = Tool.FlashPart
local Nozel = Tool.Nozel

local Trigger = Tool:WaitForChild("Trigger")
local Ammo = script:WaitForChild("Ammo")

local EquipSound = script.Equip
local ReloadSound = script.Reload
local ShootSound = script.Shoot

local OnBulletShot = script:WaitForChild("OnShootEvent")
local OnReload = script:WaitForChild("OnReload")
local OnCursorChange = script:WaitForChild("OnCursorChange")

local IsReloading = false

local TweenService = game:GetService("TweenService")

local IdleAnim = script.Parent:WaitForChild("HoldingAnimation")
local IdleAnimTrack

local function PlaySound(Sound)
	Sound:Play()
end

local function Reload()
	if IsReloading or Ammo.Value == 10 then return end
	IsReloading = true
	
	OnCursorChange:FireClient(game.Players:GetPlayerFromCharacter(Tool.Parent), game.ServerStorage.CrosshairReloading.Texture)
	
	PlaySound(ReloadSound)
	
	Ammo.Value = 10
	
	IsReloading = false
	
	if game.Players:GetPlayerFromCharacter(Tool.Parent) then OnCursorChange:FireClient(game.Players:GetPlayerFromCharacter(Tool.Parent),game.ServerStorage.Crosshair.Texture) end
	
end


local function ShootFunc(Player, Hit, Target)
	
	if IsReloading then return end
	
	if Ammo.Value == 0 then
		Reload()
		
		return
	end
	
	local ray = Ray.new(Nozel.Position, (Hit.Position - Nozel.Position).unit * 100)
	
	local Part, Pos, GlobalVec = workspace:FindPartOnRay(ray, Tool.Parent, false, true)
	
	if Part then
		if Part.Parent:FindFirstChild("Humanoid") then Part.Parent.Humanoid:TakeDamage(30) end
	end
	
	local BulletRay = Instance.new("Part")
	BulletRay.CanCollide = false
	BulletRay.Anchored = true
	
	local size = (Hit.Position - Nozel.Position).Magnitude
	
	if size > 2048 then size = 2048 end
	
	BulletRay.CFrame = CFrame.new(Nozel.Position, Pos) * CFrame.new(0, 0, -size / 2)
	BulletRay.Size = Vector3.new(0.1, 0.1, size)
	
	BulletRay.Color = Color3.fromRGB(255, 223, 0)
	BulletRay.Material = "Neon"
	
	
	BulletRay.Parent = workspace
	
	
	local BulletHole = game.ServerStorage.BulletHole:Clone()
	
	BulletHole.CFrame = CFrame.new(Hit.Position, Hit.Position + GlobalVec)
	
	BulletHole.Parent = workspace
	
	game:GetService("Debris"):AddItem(BulletRay, 0.2)
	game:GetService("Debris"):AddItem(BulletHole, 5)
	
	PlaySound(ShootSound)
	
	Ammo.Value = Ammo.Value - 1
	
	
	for i, flasheffect in pairs(FlashPart:GetChildren()) do
		if flasheffect.Name == "FlashGui" then flasheffect.Enabled = false end
		if flasheffect.Name == "Light" then flasheffect.Enabled = false end
	end
end


Tool.Equipped:Connect(function()
	
	OnCursorChange:FireClient(game.Players:GetPlayerFromCharacter(Tool.Parent), game.ServerStorage.Crosshair.Texture)
	
	local AmmoGui = script.AmmoGUI:Clone()
	AmmoGui.Frame.TextLabel.Text = Ammo.Value .. "/250"
	
	AmmoGui.Parent = game.Players:GetPlayerFromCharacter(Tool.Parent).PlayerGui
	
	PlaySound(EquipSound)
	
	if not IdleAnimTrack then IdleAnimTrack = Tool.Parent.Humanoid:LoadAnimation(IdleAnim) end
	
	if not IdleAnimTrack.IsPlaying then IdleAnimTrack:Play() end
end)


Tool.Unequipped:Connect(function()
	OnCursorChange:FireClient(Tool.Parent.Parent, "")
	
	if Tool.Parent.Parent.PlayerGui:WaitForChild("AmmoGUI") then Tool.Parent.Parent.PlayerGui.AmmoGUI:Destroy() end
	
	PlaySound(EquipSound)
	
	if IdleAnimTrack and IdleAnimTrack.IsPlaying then IdleAnimTrack:Stop() end
end)


OnBulletShot.OnServerEvent:Connect(ShootFunc)
OnReload.OnServerEvent:Connect(Reload)


Ammo:GetPropertyChangedSignal("Value"):Connect(function()
	if game.Players:GetPlayerFromCharacter(Tool.Parent) then
		game.Players:GetPlayerFromCharacter(Tool.Parent).PlayerGui.AmmoGUI.Frame.TextLabel.Text = Ammo.Value .. "/250" 
	end
end)

LocalScript:

local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()

local UserInputService = game:GetService("UserInputService")

local OnShootEvent = script.Parent:WaitForChild("Server"):WaitForChild("OnShootEvent")
local OnReload = script.Parent.Server:WaitForChild("OnReload")
local OnCursorChange = script.Parent.Server:WaitForChild("OnCursorChange")

local IsDown = false

local TimePerBullet = 0.2
local IsCooldown = false


UserInputService.InputBegan:Connect(function(Input, Processed) 
	if script.Parent.Parent == Player.Character then
		if Input.KeyCode == Enum.KeyCode.R or Processed then return end
		
		OnReload:FireServer()
	end
end)


OnCursorChange.OnClientEvent:Connect(function(MouseIcon)
	Mouse.Icon = MouseIcon
end)

Mouse.Button1Down:Connect(function()
	IsDown = true
end)

Mouse.Button1Up:Connect(function()
	IsDown = false
end)


while wait() do
	if script.Parent.Parent == Player.Character and not IsCooldown then
		if IsDown then
			IsCooldown = true
			
			OnShootEvent:FireServer(Mouse.Hit, Mouse.Target)
			
			wait(TimePerBullet)
			
			IsCooldown = false
		end
	end
end

Any help is appreciated, Thanks!

1 Like

Make sure you un anchor all of your parts and also weld and position them at the proper place. I suggest you use the Weld editor plugin and the Tool grip editor plugin.

Ignore my other post if that is not the solution, I see you have Debris included in your gun beam, and because of that it will stay there for 0.2 seconds (because you assigned it that way) and after that it will be destroyed. So I suggest using something a little shorter, like 0.05 seconds. (Inside the server script)

Alright, I’ll try it now. Thanks!

Yeah here is the issue with this part of the script concerning positioning the ray

It might seem ok but since it’s on the server there will inevitably be lag with what the server sees as the tool’s nozel position and the client hence the gun positioning error. Check if you have replication lag set to an amount on your Roblox Studio.

The solution will be to trick the client of where the bullet is firing by creating the bullet ray instance on the client instead, then use a fireallclients remote event to replicate the bullet to the rest to make sure others can see it.

Check if I have replication lag set to an amount?, Could u please expand on that?

The solution will be to trick the client of where the bullet is firing by creating the bullet ray instance on the client instead, then use a fireallclients remote event to replicate the bullet to the rest to make sure others can see it.

I see where you’re going with this and I’ll definetly try that. Are you saying that by the time the remote already fires to the server and the server runs all the code the player would’ve already change positions?

Yep on point, there will be a delay in real games just as this post below explains:

For an in-depth example/tutorial you can look at this fps framework tutorial of how the replication is done.

Something came to my mind and that its automatic, If u see here:

local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()

local UserInputService = game:GetService("UserInputService")

local OnShootEvent = script.Parent:WaitForChild("Server"):WaitForChild("OnShootEvent")
local OnReload = script.Parent.Server:WaitForChild("OnReload")
local OnCursorChange = script.Parent.Server:WaitForChild("OnCursorChange")

local IsDown = false

local TimePerBullet = 0.2
local IsCooldown = false


UserInputService.InputBegan:Connect(function(Input, Processed) 
	if script.Parent.Parent == Player.Character then
		if Input.KeyCode == Enum.KeyCode.R or Processed then return end
		
		OnReload:FireServer()
	end
end)


OnCursorChange.OnClientEvent:Connect(function(MouseIcon)
	Mouse.Icon = MouseIcon
end)

Mouse.Button1Down:Connect(function()
	IsDown = true
end)

Mouse.Button1Up:Connect(function()
	IsDown = false
end)


while wait() do
	if script.Parent.Parent == Player.Character and not IsCooldown then
		if IsDown then
			IsCooldown = true
			
			OnShootEvent:FireServer(Mouse.Hit, Mouse.Target)
			
			wait(TimePerBullet)
			
			IsCooldown = false
		end
	end
end

When would I put the CreateBullet in the while true do loop?