How to use mouse targetFilter twice with out bugging out

Right now im confused on why one script works while the other doesnt

heres a video

heres the script (btw both are same just using a different remote function)

local tool = script.Parent
local cooldown = false
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local animation = script:WaitForChild("Up")
local animater = humanoid:LoadAnimation(animation)
local mouse = player:GetMouse()
local toolequipped = false

local trackingPart = Instance.new("Part")
trackingPart.Size = Vector3.new(1.5, 1.5, 1.5)
trackingPart.Color = Color3.new(0.215686, 1, 0)
trackingPart.Transparency = 0.5
trackingPart.Shape = Enum.PartType.Ball
trackingPart.Material = Enum.Material.Neon
trackingPart.Anchored = true
trackingPart.CanCollide = false
trackingPart.Parent = workspace
mouse.TargetFilter = trackingPart

tool.Equipped:Connect(function()
	toolequipped = true
	while toolequipped do
		local hit = mouse.Hit
		if hit then
			local characterPosition = character.PrimaryPart.Position
			local hitPosition = hit.Position
			local distance = (hitPosition - characterPosition).magnitude
			local minDistance = 5

			if distance > minDistance then
				trackingPart.Position = hitPosition + Vector3.new(0, trackingPart.Size.Y / 2, 0)
			else
				local direction = (hitPosition - characterPosition).unit
				trackingPart.Position = characterPosition + direction * minDistance + Vector3.new(0, trackingPart.Size.Y / 2, 0)
			end
		end

		wait(0.01)
	end
end)

tool.Unequipped:Connect(function()
	toolequipped = false
	trackingPart.Position = Vector3.new(0, -1000, 0)
end)

tool.Activated:Connect(function()
	if not cooldown and toolequipped then
		local pos = trackingPart.CFrame
		cooldown = true
		animater:Play()
		game.ReplicatedStorage.RemoteTools.Blaster.Sans.BlastZone:FireServer(pos)
		trackingPart.Color = Color3.new(1, 0, 0.0156863)
		wait(9)
		cooldown = false
		trackingPart.Color = Color3.new(0.215686, 1, 0)
	end
end)
1 Like

(post deleted by author)

I would recommend using UserInputService rather than Mouse for new work, as it allows for more precise control for filtering.

You can get the mouse’s location on the screen with :GetMouseLocation() and raycast from the camera in order to find where it is in 3D space (with support for different filters at the same time).

The creator hub has some helpful resources if you’re still having trouble, such as this tutorial:
Hit detection with lasers | Documentation - Roblox Creator Hub

4 Likes

So this happens when your code runs:
Tool 1 localscript creates their part and sets mouse.Target filter to that part.

Tool 2 localscript is loaded and creates their part and sets mouse.Target filter to that part.

The target filter now equals to tool2’s part. When you use tool 2, it works fine. But using tool 1 it now breaks, because the target filter was overwritten.

So you can set the target filter of a part in tool.equipped and then it will work. But I suggest you create/destroy the tracking part in tool.equipped/unequipped instead to avoid memory leaks.

minimal solution:

--move this line in both tools' scripts
mouse.TargetFilter = trackingPart

--inside of tool.equipped:
tool.Equipped:Connect(function()
  mouse.TargetFilter = trackingPart
  --rest of code...
  --bonus:
  --toolequipped = true--remove this line
  --why? Because Activated can only fire if a tool is equipped 
  -- you don't need to check again.
  --use runservice to handle positioning instead of a while loop, it is cleaner
end)

Bonus:

It would be better to handle the lifetime of your part inside of equip/unequip though like so:

tool.Equipped:Connect(function()
  trackingPart = instance.new("Part")
  --customize
  mouse.TargetFilter = trackingPart
  --other code 
end)

tool.Unequipped:Connect(function()
  if trackingPart then 
    trackingPart:Destroy() 
    trackingPart = nil
  end
end)

Hope this helps!

one question, how will it detect the tracking part if the cloned part is in the tool.equipped section?

im still kinda confused on how raycast work

Non of your solution seems to fix the problem as it keeps giving errors like “Instance expected, got table”

so i did something kinda simillar you can correct me cus im kinda new to raycast but

it works, just that another part of the script which is suppost to keep making the part follow the mouse is making it float to my screen

tool.Equipped:Connect(function()
	toolequipped = true
	while toolequipped do
		local hit = mouse.Hit
		if hit then
			local characterPosition = character.PrimaryPart.Position
			local hitPosition = hit.Position
			local distance = (hitPosition - characterPosition).magnitude
			local minDistance = 5

			if distance > minDistance then
				trackingPart.Position = hitPosition + Vector3.new(0, trackingPart.Size.Y / 2, 0)
			else
				local direction = (hitPosition - characterPosition).unit
				trackingPart.Position = characterPosition + direction * minDistance + Vector3.new(0, trackingPart.Size.Y / 2, 0)
			end
		end

		wait(0.01)
	end
end)

here is the part i changed

local MAX_MOUSE_DISTANCE = 500
local mouselocation = input:GetMouseLocation()
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouselocation.X, mouselocation.Y)
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
trackingPart.Position = directionVector

You mean like how will you access the variable?
You define it globally at the top of your script:

local trackingPart = nil

And then you assign it a value in equipped/unequipped:

tool.Equipped:Connect(function()
    trackingPart = instance.new("Part")
    --customize
    mouse.TargetFilter = trackingPart
end)

This (& Runservice) will give you this script:

--services
local rs = game:GetService "RunService"

--plr related vars
local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local mouse = plr:GetMouse()

--other
local tool = script.Parent
local hum = char:FindFirstChildOfClass "Humanoid"
local track = hum:LoadAnimation(script:WaitForChild "Up")

--nil values
local part = nil
local connection = nil

--define constants up here:
local MIN_DISTANCE = 5

--text
tool.Equipped:Connect(function()
   part = instance.new "Part"
     part.Shape = Enum.PartType.Ball
     part.Transparency = 0.5
     part.CanCollide = false
     part.Anchored = true
     part.Size = Vector3.new(1.5, 1.5, 1.5)
     part.Material = Enum.Material.Neon
     part.Color = Color3.fromRGB(55, 255, 0)

   part.Parent = workspace
   mouse.TargetFilter = part
   connection = rs.Heartbeat:Connect(function()
       local hit = mouse.Hit.Position
       local charPos = char.PrimaryPart.Position

       local distance = (hit - charPos).Magnitude --player:DistanceFromCharacter(hit)
       if distance > MIN_DISTANCE then
           part.Position = hit + Vector3.new(0, part.Size.Y / 2, 0)
       else
           local direction = (hit - charPos).Unit
           part.Position = charPos + direction * MIN_DISTANCE + Vector3.new(0, part.Size.Y, 0)
       end
   end)
end)

--clean up resources here
tool.Unequipped:Connect(function()
   if part then 
      part:Destroy()
      part = nil
   end

   if connection then
      connection:Disconnect()
      connection = nil
   end
end)

Hope this helps!

1 Like

To get the result of a raycast you need to use workspace:Raycast().
It also seems like you’re still using mouse.Hit in your while loop.

We need to perform the raycast every time we want to get the mouse position.
I would recommend implementing something that looks like this:

local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local MAX_MOUSE_DISTANCE = 1000
local function getWorldMousePosition()
	local mouseLocation = UserInputService:GetMouseLocation()
	local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
	local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
	
	-- THIS IS WHAT FILTERS THE RAYCAST
	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude
	raycastParams.FilterDescendantsInstances = {} -- Parts to ignore go in this table
	-- There are some other raycast filter options as well
	
	local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector, raycastParams)

	return raycastResult
end

tool.Equipped:Connect(function()
	toolequipped = true
	while toolequipped do
		local mouseRaycast = getWorldMousePosition()
		if mouseRaycast then
			local characterPosition = character.PrimaryPart.Position
			local hitPosition = mouseRaycast.Position
			local distance = (hitPosition - characterPosition).magnitude
			local minDistance = 5

			if distance > minDistance then
				trackingPart.Position = hitPosition + Vector3.new(0, trackingPart.Size.Y / 2, 0)
			else
				local direction = (hitPosition - characterPosition).unit
				trackingPart.Position = characterPosition + direction * minDistance + Vector3.new(0, trackingPart.Size.Y / 2, 0)
			end
		end
		
		-- This line replaces wait(0.01), as using wait() can have longer delays than intended
		-- If you need to wait more than a single frame, use task.wait() instead
		RunService.Heartbeat:Wait()
	end
end)

You should be able to adapt this code into your current script; hopefully that made sense!
(Raycasting will replace the need for using mouse.TargetFilter as it has its own filtering options)

1 Like

Both of your script helped me i appreciate your help so much

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