How do I make a raycast that detects other character's HMRP and not mine?

I’ve been trying to find a system that can detect other character’s humanoidrootpart and not my own for a power system that im working on, but it’s been detecting my character even though I made it so it should ignore my character, and it hasn’t been detecting other character’s HMRP.

Similiar to this system, but detecting the enemies HMRP instead:

Local Script:


-- Import our services
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")


-- Identify our target for use in the function below



-- Variables
local players = game:GetService("Players")
local playersTable = players:GetPlayers()
local plr = players.LocalPlayer
local Character = plr.Character or plr.CharacterAdded:Wait()
local MyHumanoidRootPart = Character:WaitForChild("HumanoidRootPart")

for i,player in pairs(playersTable) do
	if player.Name ~= plr.Name and player.Character.Name ~= plr.Character.Name then continue end
	table.remove(playersTable,i)
	local EnemyCharacter = player.Character
	local EnemyCharacterRootPart = EnemyCharacter.HumanoidRootPart
	
	local RaycastParameters = RaycastParams.new()
	RaycastParameters.FilterDescendantsInstances = {Character}

	local Camera = workspace.CurrentCamera
	local TargetOnScreen = false
	local TargetVisible = false

	-- Primary function
	local function checkIfPartIsOnScreen(EnemyHMRP)
		-- Use :WorldToViewportPoint
		local _, IsOnScreen = Camera:WorldToViewportPoint(EnemyHMRP.Position)

		-- Check if our target is on screen, and update our variable informing us if it is.
		if IsOnScreen and (not TargetOnScreen) then
			TargetOnScreen = true
			print("The target is now in our FOV!")
			print(EnemyHMRP.Parent.Name)
			-- Do the same, but in reverse
		elseif (not IsOnScreen) and TargetOnScreen then
			TargetOnScreen = false
			-- If the target is off screen, then the target must also not be visible.
			TargetVisible = false
			print("The target is no longer in our FOV.")
		end

		-- We don't need to perform a raycast check if the target is out of our FOV
		if TargetOnScreen then

			-- This may be confusing, but it is Vector3 math. It is getting the direction between our Camera and the part.
			local Direction = (EnemyCharacterRootPart.Position - Camera.CFrame.Position).Unit

			-- This 200 could be customized to set a specific range that you are checking for the player in, though performing
			-- a separate magnitude check beforehand will likely be more optimized.
			local RaycastResult = workspace:Raycast(Camera.CFrame.Position, Direction * 200, RaycastParameters)

			-- Check if our part was not hit by our Raycast check!
			if (not RaycastResult) or RaycastResult.Instance ~= EnemyCharacterRootPart then
				-- Now that we know that the target is obscured, we need to check if we need to output!
				if TargetVisible then
					TargetVisible = false
					print("The target is now obscured.")
				end
			else
				-- If the above is not true, we can see the target.
				if (not TargetVisible) then
					TargetVisible = true
					print("The target is visible.")
				end
			end
		end
	end

	-- Run our check every frame, you may want to not do this depending on how much you are running with this check.
	RunService.RenderStepped:Connect(function()
		checkIfPartIsOnScreen(EnemyCharacterRootPart)
	end)
	break
end

--Making sure MyPlayer Is excluded from the rest

-- This is not technically needed, but it is likely preferable as we do not want to our player model obscuring the part
-- to count as an obstruction.


2 Likes

On your raycastparameters line add this:

RaycastParameters.FilterType = Enum.RaycastFilterType.Blacklist
1 Like

Probably because of the if statement you have: “if the player is not the local player, then continue.” This just continues until it finds the local player, meaning all of the process that you have only works for the local player. Maybe changing it to “player is equal to local player” then continue, so it always ignores the local player.

if player == plr then
	continue
end

Also your raycast parameters only accepts the localCharacter. Instead use the enemyCharacter or the enemy’s HumanoidRootPart:

RaycastParameters.FilterDescendantsInstances = { EnemyCharacter }

I also noticed the break after you connected to RenderStepped; was this intentional?

2 Likes

Hmm I will check each of these problems tomorrow in my code.

Okay i fixed the script up a little and It seems to work. I do have a couple of issues though. So I tried it out with two players and player 2 detected player 1 on his output but player 1 couldn’t detect player 2 in his output for some reason… Why is this? Could it be because of the loop?

Video:

In game Video:


-- Import our services
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")


-- Identify our target for use in the function below



-- Variables
local players = game:GetService("Players")
local playersTable = players:GetPlayers()
local plr = players.LocalPlayer
local Character = plr.Character or plr.CharacterAdded:Wait()
local MyHumanoidRootPart = Character:WaitForChild("HumanoidRootPart")

for i,player in pairs(playersTable) do
	if player.Name == plr.Name and player.Character.Name == plr.Character.Name then continue end
	table.remove(playersTable,i)
	local EnemyCharacter = player.Character
	local EnemyCharacterRootPart = EnemyCharacter.HumanoidRootPart
	
	local RaycastParameters = RaycastParams.new()
	RaycastParameters.FilterDescendantsInstances = {EnemyCharacterRootPart}

	local Camera = workspace.CurrentCamera
	local TargetOnScreen = false
	local TargetVisible = false

	-- Primary function
	local function checkIfPartIsOnScreen(EnemyHMRP)
		-- Use :WorldToViewportPoint
		local _, IsOnScreen = Camera:WorldToViewportPoint(EnemyHMRP.Position)

		-- Check if our target is on screen, and update our variable informing us if it is.
		if IsOnScreen and (not TargetOnScreen) then
			TargetOnScreen = true
			print("The target is now in our FOV!")
			print(EnemyHMRP.Parent.Name)
			-- Do the same, but in reverse
		elseif (not IsOnScreen) and TargetOnScreen then
			TargetOnScreen = false
			-- If the target is off screen, then the target must also not be visible.
			TargetVisible = false
			print("The target is no longer in our FOV.")
		end

		-- We don't need to perform a raycast check if the target is out of our FOV
		if TargetOnScreen then

			-- This may be confusing, but it is Vector3 math. It is getting the direction between our Camera and the part.
			local Direction = (EnemyCharacterRootPart.Position - Camera.CFrame.Position).Unit

			-- This 200 could be customized to set a specific range that you are checking for the player in, though performing
			-- a separate magnitude check beforehand will likely be more optimized.
			local RaycastResult = workspace:Raycast(Camera.CFrame.Position, Direction * 200, RaycastParameters)

			-- Check if our part was not hit by our Raycast check!
			if (not RaycastResult) or RaycastResult.Instance ~= EnemyCharacterRootPart then
				-- Now that we know that the target is obscured, we need to check if we need to output!
				if TargetVisible then
					TargetVisible = false
					print("The target is now obscured.")
				end
			else
				-- If the above is not true, we can see the target.
				if (not TargetVisible) then
					TargetVisible = true
					print("The target is visible.")
				end
			end
		end
	end

	-- Run our check every frame, you may want to not do this depending on how much you are running with this check.
	RunService.RenderStepped:Connect(function()
		checkIfPartIsOnScreen(EnemyCharacterRootPart)
	end)
end

--Making sure MyPlayer Is excluded from the rest

-- This is not technically needed, but it is likely preferable as we do not want to our player model obscuring the part
-- to count as an obstruction.


That’s because player 1 was the first to join, and the players’ table only had one item, which was player 1. You should also connect it to the player joining, and I’m pretty sure that if the player dies, the entire function is pointless. Your code is very messy and you even have two Players Service.

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

local localPlayer = Players.LocalPlayer
local camera = workspace.CurrentCamera

local function TrackCharacter(character: Model)
	local humanoidRootPart: Part = character:WaitForChild("HumanoidRootPart")
	local humanoid: Humanoid = character:WaitForChild("Humanoid")
	local connection: RBXScriptConnection

	local characterOnScreen = false
	local characterVisible = false

	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = { character }

	connection = RunService.RenderStepped:Connect(function()
		local _, isOnScreen = camera:WorldToViewportPoint(humanoidRootPart.Position)

		if isOnScreen and not characterOnScreen then
			characterOnScreen = true

			print(character.Name .. " is in our FOV")
		elseif not isOnScreen and characterOnScreen then
			characterOnScreen = false
			characterVisible = false

			print(character.Name .. " is no longer on our FOV")
		end

		if characterOnScreen then
			local direction = (humanoidRootPart.Position - camera.CFrame.Position).Unit
			local ray = workspace:Raycast(camera.CFrame.Position, direction * 200, raycastParams)

			if not ray or not (ray.Instance == humanoidRootPart) then
				if characterVisible then
					characterVisible = false

					print(character.Name .. " is now obscured")
				end
			else
				if not characterVisible then
					characterVisible = true

					print(character.Name .. " is visible")
				end
			end
		end
	end)

	humanoid.Died:Connect(function()
		connection:Disconnect()
	end)
end

local function PlayerAdded(player: Player)
	TrackCharacter(player.Character or player.CharacterAdded:Wait())

	player.CharacterAdded:Connect(TrackCharacter)
end

do
	local currentPlayers = Players:GetPlayers()
	table.remove(currentPlayers, table.find(currentPlayers, localPlayer))

	for _, player in ipairs(currentPlayers) do
		coroutine.wrap(TrackCharacter)(player.Character or player.CharacterAdded:Wait())
	end
end

Players.PlayerAdded:Connect(PlayerAdded)
1 Like

Wow it worked! How were you able to get the local player and all of the players in a variable? I’m gonna read this script and try to learn it.

1 Like

This part does not really work, I just copied the code you had, I do have a solution to this, but you should try to fix it on your own, if not just ask on the #help-and-feedback:scripting-support .

It works for me though which is strange, it seems to detect other characters which is what i wanted

1 Like

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