Checking a player inside a region every second, and do damage if they aren't in there

Is there any way to efficiently check a player inside a region(a cube or rectangle) every second? I tried Get:TouchingParts, but the touch system is very unreliable on roblox(sometimes doesn’t get picked up). Any help will be appreicated!

while true do
wait()
	
local Radius = 50	
local Pillar = game.Workspace:WaitForChild("Pillar")
	
local children = workspace:GetChildren()
for i = 1, #children do
	local humanoid = children[i]:FindFirstChild("Humanoid")		
	local root = children[i]:FindFirstChild("HumanoidRootPart")
	if root ~= nil and humanoid ~= nil and humanoid.Health > 0 then	
	local Distance = (root.Position - Pillar.Position).magnitude		
	print(Distance)		
				
	if Distance <= Radius then		
	local character	= game.Workspace:FindFirstChild(children[i].Name)		
	    if character then			
	    local InsideValue = character:FindFirstChild("InsideValue")			
	        if InsideValue then		
	           InsideValue.Value = true
	        end				
	    end				
				
	else			
	local character	= game.Workspace:FindFirstChild(children[i].Name)		
	    if character then			
	    local InsideValue = character:FindFirstChild("InsideValue")			
	        if InsideValue then		
	           InsideValue.Value = false
	        end				
	    end						
	end			
	end
		
end		
end
1 Like

You can look into the function, FindPartsInRegion3, which is much more reliable than GetTouchingParts.

Thanks for the effort in the help, but .magnitude Is for sphere shapes lol. It starts to become an issue if the player lets say climbs to a large height in the y direction, but is still in the radius gets damages(which is why cube or rectangle is kind of better).

I looked into regions, but haven’t a way to properly incorporate it into the function that I need lol. It’s tough work.

You can run the FindPartsInRegion3 in a while loop, and then check if the parent of that part is a character model and script your code from there

If you want to see if a player is inside a rectangle of a specific shape and orientation you can use an invisible part with this function:

1 Like

Error

I printed v3 when I tested, and it gave me a Vector3 value, so this is pretty weird lol

It looks like you just have some of the variables mixed up.

local players = game:GetService("Players")

local part = script.Parent
local size = part.Size
local partCFrame = part.CFrame

local function inside(playerPosition)
	local v3 = partCFrame:PointToObjectSpace(playerPosition)
	return (math.abs(v3.X) <= size.X / 2) and (math.abs(v3.Y) <= size.Y / 2) and (math.abs(v3.Z) <= size.Z / 2)
end

wait(7)
for i = 60, 0, -1 do
	for _, player in ipairs(players:GetPlayers()) do
		local hum = player.Character and player.Character:FindFirstChild("Humanoid")
		local hrp = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
		if (hum and hrp and inside(hrp.Position) then
			hum:TakeDamage(10)
		end
	end
end

thanks for the effort in the help, but I copied the exact script, and it still didn’t work aaaa lol even after fixing the parenthesis for (hum and hrp and inside(hrp.Position) ) <–added thisrobloxapp-20201102-1945090.wmv (1013.2 KB)

Are there any errors? A video doesn’t really help with this.

There are 0 errors, but that said the script didn’t do anything.

Oops, I just noticed I forgot to include the wait(1) in the loop, so the whole thing was finishing before you had a chance to test it.

local players = game:GetService("Players")

local part = script.Parent
local size = part.Size
local partCFrame = part.CFrame

local function inside(playerPosition)
	local v3 = partCFrame:PointToObjectSpace(playerPosition)
	return (math.abs(v3.X) <= size.X / 2) and (math.abs(v3.Y) <= size.Y / 2) and (math.abs(v3.Z) <= size.Z / 2)
end

wait(7)
for i = 60, 0, -1 do
	for _, player in ipairs(players:GetPlayers()) do
		local hum = player.Character and player.Character:FindFirstChild("Humanoid")
		local hrp = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
		if (hum and hrp and inside(hrp.Position)) then
			hum:TakeDamage(10)
		end
	end
	wait(1)
end

Still doesn’t work my guy lol.

Alternatively you can use a RunService event to make the players take damage continuously instead of hits every second:

local players = game:GetService("Players")

local damageRate = 10 -- HP/second

local part = script.Parent
local size = part.Size
local partCFrame = part.CFrame

local function inside(playerPosition)
	local v3 = partCFrame:PointToObjectSpace(playerPosition)
	return (math.abs(v3.X) <= size.X / 2) and (math.abs(v3.Y) <= size.Y / 2) and (math.abs(v3.Z) <= size.Z / 2)
end

wait(7)
local timer = 0
local loop
loop = game:GetService("RunService").Stepped:Connect(function(_, dt)
	for _, player in ipairs(players:GetPlayers()) do
		local hum = player.Character and player.Character:FindFirstChild("Humanoid")
		local hrp = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
		if (hum and hrp and not inside(hrp.Position)) then
			hum:TakeDamage(damageRate * dt)
		end
	end
	if (timer >= 60) then
		loop:Disconnect()
	else
		timer = timer + dt
	end
end)
1 Like

modified ur script a little, and finally got the result that I wanted(runservice is a little quick)! I still have no idea why your previous scripts didn’t work though as are literally the same. Thank you for all your dude I appreciate it! Here’s the final:
local players = game:GetService(“Players”)

local damageRate = 10 – HP/second

local part = script.Parent
local size = part.Size
local partCFrame = part.CFrame

local function inside(playerPosition)
local v3 = partCFrame:PointToObjectSpace(playerPosition)
return (math.abs(v3.X) <= size.X / 2) and (math.abs(v3.Y) <= size.Y / 2) and (math.abs(v3.Z) <= size.Z / 2)
end

wait(7)
local timer = 0
local loop
for i = 60, 0 , -1 do
for _, player in ipairs(players:GetPlayers()) do
local hum = player.Character and player.Character:FindFirstChild(“Humanoid”)
local hrp = player.Character and player.Character:FindFirstChild(“HumanoidRootPart”)
if (hum and hrp and not inside(hrp.Position)) then
hum:TakeDamage(damageRate)
end
end
if (timer >= 60) then
loop:Disconnect()
else
wait(1)
timer = timer + 1
end
end

If you have the time can you explain what :PointToObjectSpace() does? I really like understanding scripts, and not just freeloading them. If not that’s fine as well. Thanks for everything! Your method was genius(especially with that math.abs(), and size/2 method. I would never think of that.

CFrame:PointToObjectSpace(Vector3) gives you Vector3’s position relative to CFrame. That way if the resulting vector is inside the bounds of the part defined by the part’s size, then we know that the position is inside the part.

3 Likes