Sniper Script Review

This is a script for a sniper that detects headshots and I want to know if I can make it better, are there anything that’s irrelevant, or things I should remove or improve.

-- Local Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local SoundService = game:GetService("SoundService")

local Sniper = script.Parent
local SniperFiredFunction = script:WaitForChild("SniperFired")
local RaycastPart = Sniper:WaitForChild("Main")
local Flash = RaycastPart:WaitForChild("Flash")

local SniperGui = Sniper:WaitForChild("SniperGui")
local BulletText = SniperGui:WaitForChild("BackgroundFrame"):WaitForChild("BulletsLabel")
local Bullets = BulletText:WaitForChild("Bullets")

local ScopeGui = Sniper:WaitForChild("SniperAimGui")

local LowerBody = Sniper:WaitForChild("Lower Body")

local EquipSound = LowerBody:WaitForChild("EquipSound2")
local UnequipSound = LowerBody:WaitForChild("UnequipSound")
local ReloadSound = LowerBody:WaitForChild("ReloadSound")
local FireSound = LowerBody:WaitForChild("FireSound")

local LocalPlayer = game.Players.LocalPlayer
local PlayerCamera = game.Workspace.CurrentCamera
local Mouse = LocalPlayer:GetMouse()
local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")
local Humanoid = LocalPlayer.Character:WaitForChild("Humanoid")

local ShootingDebounce = false
local ReloadDebounce = false
local ScopeActivated = false
ScopeGui.Parent = PlayerGui
SniperGui.Parent = PlayerGui

local RegularFOV = 70
local AimingFOV = 10
local Equipped = false

local function UpdateBullets()
	while true do
		BulletText.Text = Bullets.Value
		task.wait()
	end
end

local function onEquipped()
	Equipped = true
	EquipSound:Play()
	SniperGui.Enabled = true
end

local function onUnequipped()
	Equipped = false
	UnequipSound:Play()
	ScopeActivated = false
	ScopeGui.Enabled = false
	SniperGui.Enabled = false
	LocalPlayer.CameraMode = Enum.CameraMode.Classic
	PlayerCamera.FieldOfView = RegularFOV
end

local function ReloadSniper()
	ReloadDebounce = true
	ScopeActivated = false
	ScopeGui.Enabled = false
	LocalPlayer.CameraMode = Enum.CameraMode.Classic
	PlayerCamera.FieldOfView = RegularFOV
	ReloadSound:Play()
	task.wait(2.5)
	Bullets.Value = 1
	ReloadDebounce = false
end

local function onReload(input, processed)
	if processed == true or ReloadDebounce == true then return end
	if input.KeyCode == Enum.KeyCode.R and Equipped == true then
		if Bullets.Value <= 0 then
			ScopeGui.Enabled = false
			LocalPlayer.CameraMode = Enum.CameraMode.Classic
			PlayerCamera.FieldOfView = RegularFOV
			ReloadSniper()
		else
			return
		end
	else
		return
	end
end

local function Fired()
	FireSound:Play()
	Bullets.Value -= 1
	Flash.Enabled = true
	task.wait(0.1)
	Flash.Enabled = false
end

local function onActivated()
	if ShootingDebounce == true or ReloadDebounce == true or Bullets.Value <= 0 then return end
	
	if ScopeActivated == false then
		ShootingDebounce = true
		task.spawn(Fired)
		
		local RayCastParameters = RaycastParams.new()
		RayCastParameters.FilterType = Enum.RaycastFilterType.Exclude
		RayCastParameters.IgnoreWater = true
		RayCastParameters.FilterDescendantsInstances = {script.Parent, LocalPlayer.Character}
		
		local Origin = RaycastPart.Position
		local Direction = (Mouse.Hit.Position - Origin).Unit * 5000
		
		local RayResults = game.Workspace:Raycast(Origin, Direction, RayCastParameters)
		
		if not RayResults then
			task.wait(3)
			ShootingDebounce = false
		else
			if RayResults.Instance.Parent:FindFirstChild("Humanoid") and not RayResults.Instance.Parent:FindFirstChild("ForceField") then
				SniperFiredFunction:InvokeServer(RayResults.Instance, RayResults.Instance.Parent:FindFirstChild("Humanoid"))
				task.wait(3)
				ShootingDebounce = false
			else
				task.wait(3)
				ShootingDebounce = false
			end
		end
	else
		ShootingDebounce = true
		task.spawn(Fired)
		
		local MouseTarget = Mouse.Target
		
		if not MouseTarget then
			task.wait(3)
			ShootingDebounce = false
		else
			if MouseTarget.Parent:FindFirstChild("Humanoid") and not MouseTarget.Parent:FindFirstChild("ForceField") then
				SniperFiredFunction:InvokeServer(MouseTarget, MouseTarget.Parent:FindFirstChild("Humanoid"))
				task.wait(3)
				ShootingDebounce = false
			else
				task.wait(3)
				ShootingDebounce = false
			end
		end
	end
end

local function ToggleAim(input, processed)
	if processed == true then return end
	if input.UserInputType == Enum.UserInputType.MouseButton2 and Equipped == true then
		if ScopeActivated == false then
			ScopeActivated = true
			ScopeGui.Enabled = true
			PlayerCamera.FieldOfView = AimingFOV
			LocalPlayer.CameraMode = Enum.CameraMode.LockFirstPerson
		else
			ScopeActivated = false
			ScopeGui.Enabled = false
			PlayerCamera.FieldOfView = RegularFOV
			LocalPlayer.CameraMode = Enum.CameraMode.Classic
		end
	end
end

Humanoid.Died:Connect(function()
	ScopeActivated = false
	PlayerCamera.FieldOfView = RegularFOV
end)

Sniper.Equipped:Connect(onEquipped)
Sniper.Unequipped:Connect(onUnequipped)
Sniper.Activated:Connect(onActivated)
UserInputService.InputBegan:Connect(ToggleAim)
UserInputService.InputBegan:Connect(onReload)

task.spawn(UpdateBullets)
--Server Script when sniper has been fired to detect if normal shot or head shot
script.Parent.OnServerInvoke = function(player, HitInstance, Humanoid)
	if HitInstance.Name == "Head" then
		Humanoid.Health -= 100
	else
		Humanoid.Health -= 25
	end
end
1 Like

Can anyone give me some feedback on this Sniper Code?

Taking a quick look over the code, I can’t see anything that needs changing; though there is a while true do loop, where you loop to update BulletText.Text every task.wait().

There’s a thread about avoiding wait() (which you’re not using) but also “busy waiting” in general that I have in mind. Though it admittedly isn’t very important in this case, you should probably just update BulletText.Text whenever Bullets.Changed fires.

ValueBases have a special version of the Changed event that only fires whenever Value is changed, while passing the new value to the callback function.

local function UpdateBullets()
	BulletText.Text = Bullets.Value
end

UpdateBullets() -- call it once to initialize it, cause the event might not immediately trigger

...

Bullets.Changed:Connect(UpdateBullets)

Ah okay, thanks for the feedback! :smiley:

1 Like