Ray detecting if a part is (or isn't) above player isn't working

I have this simple script, that detects if a part is 20 studs or less above a player’s head. It doesn’t work - it does not detect when a part is over the player’s head.

while true do
	for _,p in pairs(game.Players:GetPlayers()) do
		local char = p.Character or p.CharacterAdded:Wait()
		local MyRayCast = Ray.new(char.Head.CFrame.p, char.Head.CFrame.UpVector)
		local part = workspace:FindPartOnRay(MyRayCast)
		local hit, position = game.Workspace:FindPartOnRayWithIgnoreList(MyRayCast,{char})
		if hit then
			print('ray hit a part!')
		else
			print('no part found')
		end
	end
	task.wait(1)
end

this should work

local Players = game:GetService("Players")

task.spawn(function()
	while true and task.wait(1) do 
		for i,v in pairs(Players:GetChildren()) do 
			if (v.Character) and (v.Character:FindFirstChild("Head")) then 
				local Char = v.Character 
				
				local Result = workspace:Raycast(Char.Head.Position, (Char.Head.Position+Vector3.new(0, 20, 0)))

				if (Result) and (Result.Instance) then 
					print("Found part for "..v.Name)
				else 
					print("No part found for "..v.Name)
				end
			end
		end
	end
end)

server script in serverscriptservice

1 Like

Ok, I ran into another problem.

Sometimes it detects correctly that there is nothing above the humanoid, and other times, it detects that there is something there where there isn’t.

you can check if the properties of the part that the raycast hit match the acid parts, for example you can name the acid parts AcidPart and in the script check if Result.Instance.Name == "AcidPart"

The way this acid rain is supposed to work, is it is supposed to detect if a player is inside a building or not, by having a raycast go about 20 studs above their head to see if there is a building roof above them, aka, they are inside a building.

If they are not inside a building, every second, they are supposed to lose 15 or so health.

The issue that is being seen, is the script you provided now seems to be detecting parts that are WAY out of the 20 stud range of the character’s head that was mentioned in the previous post, as seen in this video that includes output.

if your detecting if it’s within a certain distance then raycasting is pointless just get the distance between the acid part and the player’s HumanoidRootPart like so:

while true do
	for _,p in pairs(game.Players:GetPlayers()) do
		local char = p.Character or p.CharacterAdded:Wait()
	        local hrp = char:WaitForChild("HumanoidRootPart")
                local dist = (hrp.Position - acidPart.Position).Magnitude -- might need to switch these around
                
               -- I typed this in dev forum so the local's have a weird layout thing
		if dist <= minimumDistance then
			print('hit a part!')
		else
			print('no part found')
		end
	end
	task.wait(1)
end

See my most recent post before this one. The Acid Parts are just for visual show, they are not functional.

you have to have some kind of position for them? so just use that instead of acidPart.Position

No, the acid parts are not supposed to do anything but be a visual effect. The acid parts themselves have their CanTouch, CanCollide, and CanQuery properties set to false, so the rays will have no interaction with them.

The way players are damaged, is if they are not inside a building during the acid rain event, which is determined by the ray shooting out of the top of their heads and seeing if it hits a part, and if it does, see if that part is 20 or less studs away.

I think this script is going by the front of their heads, and not the top of their heads.

1 Like

I think this is what you wanted.

task.wait(.5)

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

local checkingOffset = CFrame.new(0, 80, 0)
local checkingDistance = 100

local function checkRay(rayInstance, toFind)
	for i,v in pairs(toFind:GetDescendants()) do
		if v == rayInstance or i == rayInstance then
			return true
		end
	end
	
	return false
end

run.RenderStepped:Connect(function(dt)
	for _, plr in pairs(players:GetPlayers()) do
		local char = plr.Character or plr.CharacterAdded:Wait()
		local hrp = char:WaitForChild("HumanoidRootPart")
		
		local acidCFrame = hrp.CFrame * checkingOffset
		
		local acidRaycast = workspace:Raycast(acidCFrame.p, (hrp.Position - acidCFrame.p))
		
		if acidRaycast and checkRay(acidRaycast.Instance, char) then
			print("got player")
			
			-- send data to server 
		else
			print("player is hiding")	
		end
	end
end)

also I just now realized after I made this that doing the for loop on the players was pointless for this since my version is local lol.

the issue might be the raycast is hitting the players accessories and counting it as being below a roof

				local Params = RaycastParams.new()
				Params.FilterType = Enum.RaycastFilterType.Exclude
				Params.FilterDescendantsInstances = {Char}
				local Result = workspace:Raycast(Char.Head.Position, (Char.Head.Position+Vector3.new(0, 20, 0)), Params)

1 Like

This also wouldn’t work because now your stopping the ray from hitting the players, so instead of erroring because it’s hitting the accessories it’s because it can’t hit the player at all.

I’ve already filtered out the character’s descendants, and it was showing that regular game parts were hitting, not accessories.

1 Like

The checking distance (which does not get used in your code) and checking offset variables seem to be way off for the 20 stud distance I am looking for. Will this also spawn the ray cast in the up direction?

1 Like

Will something like this work?

local Player_Character = --The player's character here
local Player_Head = --The player's head here

local Ray_Params = RaycastParams.new()
Ray_Params.FilterType = Enum.RaycastFilterType.Exclude
Ray_Params.FilterDescendantsInstances = {Player_Character}

local Upwards_Limit = 9e9

local RayResult = workspace:Raycast(Player_Head.Position, Vector3.new(0, Upwards_Limit, 0), Ray_Params)

if RayResult then
    --code here
end

(If the limit value is negative it raycasts downwards, if its positive it raycasts upwards)

Lol, I’m dull I didn’t even realize I referenced checkingDistance. You don’t need checking distance, let me explain, when doing (hrp.Position - acidCFrame.p) it’s not only getting the direction but also the distance between them so when I set the direction of the raycast to (hrp.Position - acidCFrame.p), it is just setting the distance to however long the distance between the two positions are. However if you want I think you can just do this in the direction part of the raycast (hrp.Position - acidCFrame.p) * checkingDistance.

And to answer your question yes this pushes the ray up to whatever you set the checkingOffset to, including on the x and z axis not just the y.

1 Like

This ended up working just the way I wanted to. Thank you!

1 Like

Certainly, although I wouldn’t recommend it personally, the delay between the players real position and where the server thinks the player is can be quite big depending on the players ping, sometimes even different enough that the raycast wont hit, which is why I would recommend doing it on the client and if it hits send the player that it hit to the server with a RemoteEvent. Here’s an example of how this would look:

– CLIENT –

-- game > StarterPlayer > StarterCharacterScripts --

task.wait(.5)

local hitEvent = game.ReplicatedStorage.hitEvent

local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()

local humanoidRootPart = character:WaitForChild("HumanoidRootPart")

local run = game:GetService("RunService")

local checkingOffset = CFrame.new(0, 80, 0)
local checkingDistance = 100

local function checkRay(rayInstance, toFind)
	for i,v in pairs(toFind:GetDescendants()) do
		if v == rayInstance or i == rayInstance then
			return true
		end
	end
	
	return false
end

run.RenderStepped:Connect(function(dt)
	local acidCFrame = humanoidRootPart.CFrame * checkingOffset
	
	local acidRaycast = workspace:Raycast(acidCFrame.p, (humanoidRootPart.Position - acidCFrame.p))
	
	if acidRaycast and checkRay(acidRaycast.Instance, character) then
		print("got player")
		
		hitEvent:FireServer()
	else
		print("player is hiding")	
	end
end)

– SERVER –

-- game > ServerScriptService --

local hitEvent = game.ReplicatedStorage.hitEvent

local function onHit(player:Player)
	local character = player.Character or player.CharacterAdded:Wait()
	local humanoid = character:WaitForChild("Humanoid")
	
	humanoid:TakeDamage(10)
end

hitEvent.OnServerEvent:Connect(onHit)

1 Like

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