Similar guns using same raycast positions

Got a weird problem with my guns. As you can see, the pistol makes the shotgun fire aswell even when it isnt equipped

shotgun script courtesy of chatgpt (serverscript inside of shotgun):

local ammo = 8
local RayAttachment = script.Parent.Handle.ShootAttachment
local numPellets = 4 -- Number of pellets per shot
local spreadAngle = 15 -- Maximum spread angle in degrees
local gunRange = 40 -- Range of the raycast

local shootSound = script.Parent.Handle.Shoot
local pumpSound = script.Parent.Handle.Pump
local blankSound = script.Parent.Handle.Empty

local Players = game:GetService("Players")
local RS = game:GetService("ReplicatedStorage")
local getMouseEV = RS:WaitForChild("GetMouse")

local holdAnim = script.Hold
local shootAnim = script.Shoot
local pumpAnim = script.Pump
local holdTrack = nil
local shootTrack = nil
local pumpTrack = nil

local hum = nil

local db = false

-- Function to create a ray with a spread
local function firePellet(origin, direction, hitHumanoids)
	local spreadX = math.rad(math.random(-spreadAngle, spreadAngle)) -- Randomize spread in X axis
	local spreadY = math.rad(math.random(-spreadAngle, spreadAngle)) -- Randomize spread in Y axis

	local spreadCFrame = CFrame.Angles(spreadX, spreadY, 0) -- Create random spread CFrame
	local finalDirection = (spreadCFrame * CFrame.new(direction)).Position.Unit * gunRange

	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = {script.Parent.Parent} -- Ignore the player's character
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude

	local raycastResult = workspace:Raycast(origin, finalDirection, raycastParams)

	-- If something is hit by the ray
	if raycastResult then
		local hitPosition = raycastResult.Position
		
		RayAttachment.Light.Enabled = true

		-- Visualize the ray (optional)
		local pelletRay = Instance.new("Part")
		pelletRay.Size = Vector3.new(0.1, 0.1, (hitPosition - origin).Magnitude)
		pelletRay.CFrame = CFrame.lookAt(origin, hitPosition) * CFrame.new(0, 0, -(pelletRay.Size.Z / 2))
		pelletRay.Anchored = true
		pelletRay.CanCollide = false
		pelletRay.Color = Color3.fromRGB(255, 217, 0)
		pelletRay.Parent = workspace
		game:GetService("Debris"):AddItem(pelletRay, 0.1) -- Automatically remove after 0.1 seconds
		
		task.delay(0.1, function()
			RayAttachment.Light.Enabled = false
		end)

		local hitHum = raycastResult.Instance.Parent:FindFirstChildOfClass("Humanoid")

		-- Ensure we only damage each humanoid once per shot
		if hitHum and not hitHumanoids[hitHum] and not Players:GetPlayerFromCharacter(raycastResult.Instance.Parent) then
			hitHum:TakeDamage(20)
			hitHumanoids[hitHum] = true -- Mark the humanoid as hit
		end
	end
end

-- Function to handle shooting
local function shoot(player, mousePos)
	if ammo > 0 then
		shootSound:Play()

		if hum then
			shootTrack = hum:LoadAnimation(shootAnim)
			shootTrack:Play()

			task.spawn(function()
				shootTrack.Ended:Wait()
				shootTrack:Destroy()
			end)
		end

		ammo = ammo - 1

		local origin = RayAttachment.WorldPosition
		local hitHumanoids = {} -- Table to track hit humanoids in this shot

		if mousePos then
			local direction = (mousePos - origin).Unit

			-- Fire multiple pellets
			for i = 1, numPellets do
				firePellet(origin, direction, hitHumanoids)
			end
			

			task.wait(1)
			pumpSound:Play()

			if hum then
				pumpTrack = hum:LoadAnimation(pumpAnim)
				pumpTrack:Play()

				pumpTrack.Ended:Wait()
				pumpTrack:Destroy()
			end

			db = false
		end
	else
		print("Out of ammo!")
		blankSound:Play()
		
		task.wait(0.5)
		db = false
	end
end

-- Connect the client event once
getMouseEV.OnServerEvent:Connect(function(player, mousePos)
	-- Call the shoot function with player and mousePos
	shoot(player, mousePos)
end)

script.Parent.Equipped:Connect(function()
	hum = script.Parent.Parent:FindFirstChild("Humanoid")

	if hum then
		holdTrack = hum:LoadAnimation(holdAnim)
		holdTrack:Play()

		pumpSound:Play()
	end
end)

script.Parent.Unequipped:Connect(function()
	if hum and holdTrack then
		holdTrack:Stop()
		holdTrack:Destroy()
	end
end)

-- Connect the tool activation to shooting
script.Parent.Activated:Connect(function()
	-- Request the mouse position from the client
	local player = Players:GetPlayerFromCharacter(script.Parent.Parent)

	if player and db == false then
		db = true
		getMouseEV:FireClient(player)
	end
end)

pistol script (shotgun script with one ray and diff animations, serverscript inside of pistol):

local ammo = 10
local RayAttachment = script.Parent.Handle.ShootAttachment
local gunRange = 60 -- Range of the raycast

local shootSound = script.Parent.Handle.Shoot
local pumpSound = script.Parent.Handle.Pump
local blankSound = script.Parent.Handle.Empty

local Players = game:GetService("Players")
local RS = game:GetService("ReplicatedStorage")
local getMouseEV = RS:WaitForChild("GetMouse")

local holdAnim = script.Hold
local shootAnim = script.Shoot
local pumpAnim = script.Pump
local holdTrack = nil
local shootTrack = nil
local pumpTrack = nil

local hum = nil

local db = false

-- Function to create a ray for the pellet
local function firePellet(origin, direction, hitHumanoids)
	local finalDirection = direction.Unit * gunRange

	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = {script.Parent.Parent} -- Ignore the player's character
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude

	local raycastResult = workspace:Raycast(origin, finalDirection, raycastParams)

	-- If something is hit by the ray
	if raycastResult then
		local hitPosition = raycastResult.Position

		-- Visualize the ray (optional)
		local pelletRay = Instance.new("Part")
		pelletRay.Size = Vector3.new(0.1, 0.1, (hitPosition - origin).Magnitude)
		pelletRay.CFrame = CFrame.lookAt(origin, hitPosition) * CFrame.new(0, 0, -(pelletRay.Size.Z / 2))
		pelletRay.Anchored = true
		pelletRay.CanCollide = false
		pelletRay.Color = Color3.fromRGB(255, 217, 0)
		pelletRay.Parent = workspace
		game:GetService("Debris"):AddItem(pelletRay, 0.1) -- Automatically remove after 0.1 seconds

		local hitHum = raycastResult.Instance.Parent:FindFirstChildOfClass("Humanoid")

		-- Ensure we only damage each humanoid once per shot
		if hitHum and not hitHumanoids[hitHum] and not Players:GetPlayerFromCharacter(raycastResult.Instance.Parent) then
			hitHum:TakeDamage(20)
			hitHumanoids[hitHum] = true -- Mark the humanoid as hit
		end
	end
end

-- Function to handle shooting
local function shoot(player, mousePos)
	if ammo > 0 then
		shootSound:Play()

		if hum then
			shootTrack = hum:LoadAnimation(shootAnim)
			shootTrack:Play()

			task.spawn(function()
				shootTrack.Ended:Wait()
				shootTrack:Destroy()
			end)
		end

		ammo = ammo - 1

		local origin = RayAttachment.WorldPosition
		local hitHumanoids = {} -- Table to track hit humanoids in this shot

		if mousePos then
			local direction = (mousePos - origin).Unit

			-- Fire a single pellet
			firePellet(origin, direction, hitHumanoids)

			task.wait(1)
			pumpSound:Play()

			if hum then
				pumpTrack = hum:LoadAnimation(pumpAnim)
				pumpTrack:Play()

				pumpTrack.Ended:Wait()
				pumpTrack:Destroy()
			end

			db = false
		end
	else
		print("Out of ammo!")
		blankSound:Play()

		task.wait(0.5)
		db = false
	end
end

-- Connect the client event once
getMouseEV.OnServerEvent:Connect(function(player, mousePos)
	-- Call the shoot function with player and mousePos
	shoot(player, mousePos)
end)

script.Parent.Equipped:Connect(function()
	hum = script.Parent.Parent:FindFirstChild("Humanoid")

	if hum then
		holdTrack = hum:LoadAnimation(holdAnim)
		holdTrack:Play()

		pumpSound:Play()
	end
end)

script.Parent.Unequipped:Connect(function()
	if hum and holdTrack then
		holdTrack:Stop()
		holdTrack:Destroy()
	end
end)

-- Connect the tool activation to shooting
script.Parent.Activated:Connect(function()
	-- Request the mouse position from the client
	local player = Players:GetPlayerFromCharacter(script.Parent.Parent)

	if player and db == false then
		db = true
		getMouseEV:FireClient(player)
	end
end)

mouse position giver (localscript inside of starterplayerscripts):

local RS = game:GetService("ReplicatedStorage")
local getMouseEV = RS:WaitForChild("GetMouse")

-- When the server requests the mouse position
getMouseEV.OnClientEvent:Connect(function()
	local player = game.Players.LocalPlayer
	local mouse = player:GetMouse()

	-- Send the mouse position to the server
	getMouseEV:FireServer(mouse.Hit.Position)
end)

help is really appreciated, im kinda stuck here. new to raycasting and shtick

I think the issue is that you are using the same remote event, which is fired in both cases of pistol and shotgun. Use a different remote event or pass some argument to tell which gun should be fired.

1 Like

You’re using the same getMouseEV for both guns.

When the guns appear in your inventory, both run the server script and bind to the same RemoteEvent.

  1. You spawn in with pistol & shotgun, both scripts have already ran a
  2. You hold out pistol
  3. You activate the pistol tool
  4. It FireClient your player
  5. Your localscript fetches the mouse position and :FireServer()s
  6. Your pistol AND your shotgun receives the .OnServerEvent because they’re connected to the same RemoteEvent
  7. both execute their shoot() function

You can fix either by:

  • using different remote events for each gun
    OR
  • check if script.Parent.Parent == player.Character before calling shoot(), basically if the tool is equipped
2 Likes

Thanks! I thought it might have something to do with the RemoteEvent, but i couldn’t see why it would be.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.