Trap system sometimes spawns more than 1 trap when trap button is clicked, resulting in the amount of traps being a negative number

Hello. I have a trap system where if a player clicks a button or presses Ctrl on their keyboard, it places a trap. I noticed that players could spawn multiple traps next to each other, so I added a distance system. But this resulting in sometimes placing down more than 1 trap at a time (Usually 3). Any help would be appreciated!

Local Script:

local color = script.Parent.BackgroundColor3
local imageColor = script.Parent.ImageColor3

local player = game.Players.LocalPlayer
local trapCount = player:WaitForChild('Traps')
local trapText = script.Parent.Parent:WaitForChild('TrapText')
trapText.Text = trapCount.Value

local clicked = false

local inputService = game:GetService('UserInputService')

script.Parent.MouseButton1Click:Connect(function()
	if not clicked then
		clicked = true
		game.ReplicatedStorage.RemoteEvents.TrapEvent:FireServer(player)
		script.Parent.BackgroundColor3 = Color3.new(1, 0, 0)
		script.Parent.ImageColor3 = Color3.new(1, 1, 1)
		wait(3)
		script.Parent.BackgroundColor3 = color
		script.Parent.ImageColor3 = imageColor
		clicked = false
	end
end)

game.ReplicatedStorage.RemoteEvents.TrapEvent.OnClientEvent:Connect(function()
	script.Parent.Parent.WarnText.Visible = true
	wait(3)
	script.Parent.Parent.WarnText.Visible = false
end)

inputService.InputBegan:Connect(function(input, gameProcessed)
	if not gameProcessed then
		if input.UserInputType == Enum.UserInputType.Keyboard then
			local keycode = input.KeyCode
			if keycode == Enum.KeyCode.LeftControl then
				if not clicked then
					game.ReplicatedStorage.RemoteEvents.TrapEvent:FireServer(player)
					script.Parent.BackgroundColor3 = Color3.new(1, 0, 0)
					script.Parent.ImageColor3 = Color3.new(1, 1, 1)
					clicked = true
					wait(3)
					script.Parent.BackgroundColor3 = color
					script.Parent.ImageColor3 = imageColor
					clicked = false
				end
			end
		end
	end
end)

trapCount:GetPropertyChangedSignal('Value'):Connect(function()
	trapText.Text = trapCount.Value
end)

Server Script:

local events = game.ReplicatedStorage:WaitForChild('RemoteEvents')

events.TrapEvent.OnServerEvent:Connect(function(player)
	local isEnemy = player:FindFirstChild('IsEnemy')
	local traps = player:FindFirstChild('Traps')
	if isEnemy and isEnemy.Value == true and traps and traps.Value > 0 then
		if #game.Workspace.Map.Traps:GetChildren() > 0 then
			for _, otherTrap in pairs(game.Workspace.Map.Traps:GetChildren()) do
				local distance = (otherTrap.Hitbox.Position - player.Character.HumanoidRootPart.Position).Magnitude
				if distance > 7 then
					local trap = game.ServerStorage.TrapTypes.Trap:Clone()
					for i, v in pairs(trap:GetChildren()) do
						if v:IsA('BasePart') then
							v.Position = player.Character:FindFirstChild('HumanoidRootPart').Position - Vector3.new(0, 2.4, 0)
						end
					end
					trap.Parent = game.Workspace.Map.Traps
					trap.Hitbox.Place:Play()
					traps.Value = traps.Value - 1
				else
					events.TrapEvent:FireClient(player)
				end
			end
		elseif #game.Workspace.Map.Traps:GetChildren() == 0 and isEnemy and isEnemy.Value == true and traps and traps.Value > 0 then
			local trap = game.ServerStorage.TrapTypes.Trap:Clone()
			for i, v in pairs(trap:GetChildren()) do
				if v:IsA('BasePart') then
					v.Position = player.Character:FindFirstChild('HumanoidRootPart').Position - Vector3.new(0, 2.4, 0)
				end
			end
			trap.Parent = game.Workspace.Map.Traps
			trap.Hitbox.Place:Play()
			traps.Value = traps.Value - 1
		end
	end
end)
1 Like

Please someone help this is an annoying issue

It might have something to do with the fact you iterate through every placed trap and place the trap in the for loop itself, meaning that anytime the distance check passes the trap will be placed.
A possible fix would be something like this:

local canPlace = true
for _, otherTrap in pairs(game.Workspace.Map.Traps:GetChildren()) do
	local distance = (otherTrap.Hitbox.Position - player.Character.HumanoidRootPart.Position).Magnitude
	if distance < 7 then
		canPlace = false
	end
end
if canPlace then
	--place trap
end

Now the server script places down traps without the player clicking the trap button

What does the script look like now?

local events = game.ReplicatedStorage:WaitForChild('RemoteEvents')
local canPlace = true

events.TrapEvent.OnServerEvent:Connect(function(player)
	local isEnemy = player:FindFirstChild('IsEnemy')
	local traps = player:FindFirstChild('Traps')
	if isEnemy and isEnemy.Value == true and traps and traps.Value > 0 and canPlace then
		if #game.Workspace.Map.Traps:GetChildren() > 0 then
			for _, otherTrap in pairs(game.Workspace.Map.Traps:GetChildren()) do
				local distance = (otherTrap.Hitbox.Position - player.Character.HumanoidRootPart.Position).Magnitude
				if distance > 7 then
					canPlace = false
					local trap = game.ServerStorage.TrapTypes.Trap:Clone()
					for i, v in pairs(trap:GetChildren()) do
						if v:IsA('BasePart') then
							v.Position = player.Character:FindFirstChild('HumanoidRootPart').Position - Vector3.new(0, 2.4, 0)
						end
					end
					trap.Parent = game.Workspace.Map.Traps
					trap.Hitbox.Place:Play()
					traps.Value = traps.Value - 1
					wait(3)
					canPlace = true
					events.TrapEvent:FireClient(player)
				end
			end
		elseif #game.Workspace.Map.Traps:GetChildren() == 0 and isEnemy and isEnemy.Value == true and traps and traps.Value > 0 and canPlace then
			canPlace = false
			local trap = game.ServerStorage.TrapTypes.Trap:Clone()
			for i, v in pairs(trap:GetChildren()) do
				if v:IsA('BasePart') then
					v.Position = player.Character:FindFirstChild('HumanoidRootPart').Position - Vector3.new(0, 2.4, 0)
				end
			end
			trap.Parent = game.Workspace.Map.Traps
			trap.Hitbox.Place:Play()
			traps.Value = traps.Value - 1
			wait(3)
			canPlace = true
			events.TrapEvent:FireClient(player)
		end
	end
end)

local script

local color = script.Parent.BackgroundColor3
local imageColor = script.Parent.ImageColor3

local player = game.Players.LocalPlayer
local trapCount = player:WaitForChild('Traps')
local trapText = script.Parent.Parent:WaitForChild('TrapText')
trapText.Text = trapCount.Value

local clicked = false

local inputService = game:GetService('UserInputService')

script.Parent.MouseButton1Click:Connect(function()
	if #game.Workspace.Map.Traps:GetChildren() > 0 then
		for _, otherTrap in pairs(game.Workspace.Map.Traps:GetChildren()) do
			local distance = (otherTrap.Hitbox.Position - player.Character.HumanoidRootPart.Position).Magnitude
			if distance > 7 and not clicked then
				clicked = true
				game.ReplicatedStorage.RemoteEvents.TrapEvent:FireServer(player)
				script.Parent.BackgroundColor3 = Color3.new(1, 0, 0)
				script.Parent.ImageColor3 = Color3.new(1, 1, 1)
				game.ReplicatedStorage.RemoteEvents.TrapEvent.OnClientEvent:Wait()
				script.Parent.BackgroundColor3 = color
				script.Parent.ImageColor3 = imageColor
				if trapCount.Value > 0 then
					clicked = false
				end
			elseif distance <= 7 and not clicked then
				clicked = true
				script.Parent.Parent.WarnText.Visible = true
				script.Error:Play()
				wait(3)
				script.Parent.Parent.WarnText.Visible = false
				if trapCount.Value > 0 then
					clicked = false
				end
			end
		end
	elseif #game.Workspace.Map.Traps:GetChildren() == 0 and not clicked then
		clicked = true
		game.ReplicatedStorage.RemoteEvents.TrapEvent:FireServer(player)
		script.Parent.BackgroundColor3 = Color3.new(1, 0, 0)
		script.Parent.ImageColor3 = Color3.new(1, 1, 1)
		game.ReplicatedStorage.RemoteEvents.TrapEvent.OnClientEvent:Wait()
		script.Parent.BackgroundColor3 = color
		script.Parent.ImageColor3 = imageColor
		if trapCount.Value > 0 then
			clicked = false
		end
	end
end)

inputService.InputBegan:Connect(function(input, gameProcessed)
	if not gameProcessed then
		if input.UserInputType == Enum.UserInputType.Keyboard then
			local keycode = input.KeyCode
			if keycode == Enum.KeyCode.LeftControl then
				if #game.Workspace.Map.Traps:GetChildren() > 0 then
					for _, otherTrap in pairs(game.Workspace.Map.Traps:GetChildren()) do
						local distance = (otherTrap.Hitbox.Position - player.Character.HumanoidRootPart.Position).Magnitude
						if distance > 7 and not clicked then
							clicked = true
							game.ReplicatedStorage.RemoteEvents.TrapEvent:FireServer(player)
							script.Parent.BackgroundColor3 = Color3.new(1, 0, 0)
							script.Parent.ImageColor3 = Color3.new(1, 1, 1)
							game.ReplicatedStorage.RemoteEvents.TrapEvent.OnClientEvent:Wait()
							script.Parent.BackgroundColor3 = color
							script.Parent.ImageColor3 = imageColor
							if trapCount.Value > 0 then
								clicked = false
							end
						elseif distance <= 7 and not clicked then
							clicked = true
							script.Parent.Parent.WarnText.Visible = true
							script.Error:Play()
							wait(3)
							script.Parent.Parent.WarnText.Visible = false
							if trapCount.Value > 0 then
								clicked = false
							end
						end
					end
				elseif #game.Workspace.Map.Traps:GetChildren() == 0 and not clicked then
					clicked = true
					game.ReplicatedStorage.RemoteEvents.TrapEvent:FireServer(player)
					script.Parent.BackgroundColor3 = Color3.new(1, 0, 0)
					script.Parent.ImageColor3 = Color3.new(1, 1, 1)
					game.ReplicatedStorage.RemoteEvents.TrapEvent.OnClientEvent:Wait()
					script.Parent.BackgroundColor3 = color
					script.Parent.ImageColor3 = imageColor
					if trapCount.Value > 0 then
						clicked = false
					end
				end
			end
		end
	end
end)

trapCount:GetPropertyChangedSignal('Value'):Connect(function()
	trapText.Text = trapCount.Value
end)

You did the canPlace code wrong

I dont see any way I did it wrong

You’re still looping through every trap and placing a trap if the checks go through.