Hey there! I’m trying to detect when humanoids are detected! My hope is that the humanoids are tallied up when within the ray, and removed when they are no longer detected. This is what I’ve got so far, but it doesn’t seem to be detecting the humanoids correctly. Any help would be appreciated!
local Tool = Clip.Parent
local Mode = Tool.Values.Mode
local Detected = Clip.Detected
local Light = Clip.Light
local CheckScan = false
function Scan (start)
local params = RaycastParams.new()
params.FilterDescendantsInstances = {start}
params.FilterType = Enum.RaycastFilterType.Blacklist
local vector = start.CFrame.LookVector
local ray = workspace:Raycast(start.Position, vector * Light.Attachment.SpotLight.Range, params)
if ray and ray.Instance:FindFirstAncestorOfClass("Model") then
local Humanoid = ray.Instance:FindFirstChildOfClass("Humanoid", true)
if Humanoid then
print('Found')
return
end
end
end
Clip.Scanning.Changed:Connect(function()
if (not Clip.Scanning.Value) == true then
return
end
while Clip.Scanning.Value == true do
wait(0.05)
print('Scanning')
local part = Scan(Clip.Light.Scan)
if part then
print('Found Humanoid!')
Detected = Detected.Value + 1
end
CheckScan = false
end
end)
It’s for a multipurpose tool, in this particular case the script is meant to detect all humanoids infront of the tool and change a text label to match the number of humanoids it detects
Because Raycasts take the first item it hits, you will need to update the blacklist each time it finds a humanoid.
You can do this by calling the Scan function recursively, adding on the found character to the blacklist each time until nothing is found.
Here’s some pseudocode to explain what I mean:
Scan(blacklist, hit)
hit = hit or 0
target = Raycast(pos, dir, blacklist)
humanoid = target.Parent:FindFirstChild("Humanoid") or target.Parent.Parent:FindFirstChild("Humanoid")
if humanoid then
hit = hit + 1
addCharacter to blacklist
Scan(blacklist, hit)
else
return hit
end
end
That would totally work! I’m kind of unfamiliar with adding and removing things to a blacklist for raycasting, would it be with arrays or with the parameters tidbit?
@devauros The linear algebra method would look something like this:
--Checks the angle
local function _clampToAngle(inProximityResult : Array<BasePart>, originCFrame : CFrame) : Array<BasePart>
local directionToPlayer : Vector3
local angleQueryResult : Array<BasePart> = {}
for _ : number, entity : BasePart in inProximityResult do
directionToPlayer = (entity.Position - originCFrame.Position).Unit
if originCFrame.LookVector:Dot(directionToPlayer) > 0.5 then
table.insert(angleQueryResult, entity)
end
end
return angleQueryResult
end
--Checks the radius
local function _radiusCheck(originCFrame : CFrame, radius : number, queryTable : Array<BasePart>) : Array<BasePart>
local inProximityResult : Array<BasePart> = {}
--First checks if the player is in proximity
for _ : number, entity : BasePart in queryTable do
if (entity.Position - originCFrame.Position).Magnitude <= radius then
table.insert(inProximityResult, entity)
end
end
--Checks angle. 0.5 = 45 degrees infront of the player
local angleQueryResult : Array<BasePart> = _clampToAngle(inProximityResult, originCFrame)
return angleQueryResult
end
--START THE FUNCTION FROM HERE
local queryTable : Array<BasePart> = {}
for _ : number, entity : Model in workspace.Entities:GetChildren() do
if character == entity then --Skips over yourself
continue
end
--Insert all the parts you want to check against in the table
table.insert(queryTable, entity.HumanoidRootPart)
end
local queryResult : Array<BasePart> = _radiusCheck(character:GetPivot(), 10, queryTable)
if #queryResult > 1 then
print("something is infront of the player")
else
print("nothing detected")
end
So, I’ve basically, copy and pasted it into the script here.
Does the variable character need to be pointed to the player’s character, or a particular part inside their character?
On local queryResult : Array<BasePart> = _radiusCheck(character:GetPivot(), 10, queryTable),
the variable character in character:GetPivot() is pointing to the player’s character. Then :GetPivot() is an easy way to return the CFrame of a models primary part without having to index it.
So basically: character:GetPivot() == character.PrimaryPart.CFrame
But it can be any CFrame
local Tool = Clip.Parent
local Mode = Tool.Values.Mode
local Detected = Clip.Detected
local Light = Clip.Light
local player = script:FindFirstAncestorWhichIsA"Player" or game:GetService"Players":GetPlayerFromCharacter(script.Parent.Parent)
local CheckScan = false
function Scan()
--Checks the angle
local function _clampToAngle(inProximityResult : Array<BasePart>, originCFrame : CFrame) : Array<BasePart>
local directionToPlayer : Vector3
local angleQueryResult : Array<BasePart> = {}
for _ : number, entity : BasePart in inProximityResult do
directionToPlayer = (entity.Position - originCFrame.Position).Unit
if originCFrame.LookVector:Dot(directionToPlayer) > 0.5 then
table.insert(angleQueryResult, entity)
end
end
return angleQueryResult
end
--Checks the radius
local function _radiusCheck(originCFrame : CFrame, radius : number, queryTable : Array<BasePart>) : Array<BasePart>
local inProximityResult : Array<BasePart> = {}
--First checks if the player is in proximity
for _ : number, entity : BasePart in queryTable do
if (entity.Position - originCFrame.Position).Magnitude <= radius then
table.insert(inProximityResult, entity)
end
end
--Checks angle. 0.5 = 45 degrees infront of the player
local angleQueryResult : Array<BasePart> = _clampToAngle(inProximityResult, originCFrame)
return angleQueryResult
end
--START THE FUNCTION FROM HERE
local queryTable : Array<BasePart> = {}
for _ : number, entity : Model in workspace.Entities:GetChildren() do
if player.Character == entity then --Skips over yourself
continue
end
--Insert all the parts you want to check against in the table
table.insert(queryTable, entity.HumanoidRootPart)
end
local queryResult : Array<BasePart> = _radiusCheck(player.Character:GetPivot(), 10, queryTable)
if #queryResult > 1 then
print("something is infront of the player")
else
print("nothing detected")
end
end
Clip.Scanning.Changed:Connect(function()
if (not Clip.Scanning.Value) == true then
return
end
while Clip.Scanning.Value == true do
wait(0.05)
Scan()
end
CheckScan = false
end)
It doesn’t appear to be. I noticed you had entities as workspace.Entities:GetChildren(), so I made a folder and included a dummy with a humanoid. Was this the intended setup?
Yes, In my game when a player joins their character is added to a folder in workspace called “Entities”. And from there I can easily loop through the folder to get everyone
Clip.Scanning.Changed:Connect(function()
if (not Clip.Scanning.Value) == true then
return
end
while Clip.Scanning.Value == true do
wait(0.05)
Scan()
end
CheckScan = false
end)
I’m assuming Clip.Scanning.Changed is fired every time the player activates the tool?