Only letting functions run if the player is near the object

Use a hit detector or a player hit zone detection likes zoneplus, it doesn’t need to constantly detect if player is within the object.

Reconnecting and disconnecting heartbeat whenever they leave or enter.

i’m not necessarily experienced with .Heartbeat so i wouldn’t know

but i do use if statements in my .Heartbeat connections and it doesn’t seem to kill the performance, although i do have an above-average pc so it could also be that

but your method could also work

It will because how would it know when the player leaves the zone.

This is what im stuck on

Im not sure at this point thanks for your help though

1 Like


zoneplus have those event

Except i dont use zone plus if i were to look into the code it would probably have a constant check and i dont need it. Detection isnt the problem

1 Like

I have an idea of this one.
The first one involving checking the center the object.

local _, onScreen = camera:WorldToViewportPoint(corner.Position)
				if onScreen then
					return true
				end

the second one just like first one but checking each corner of the object (assuming it a box)

canCameraSeeRegion = function(cam:Camera, region: Region3): boolean
			local camera = cam or workspace.CurrentCamera
			local regionSize = Vector3.new(math.abs(region.Size.X), math.abs(region.Size.Y), math.abs(region.Size.Z))
			local regionCFrame = region.CFrame
			local corners = {
				regionCFrame * CFrame.new(regionSize.X / 2, regionSize.Y / 2, regionSize.Z / 2),
				regionCFrame * CFrame.new(regionSize.X / 2, regionSize.Y / 2, -regionSize.Z / 2),
				regionCFrame * CFrame.new(-regionSize.X / 2, regionSize.Y / 2, -regionSize.Z / 2),
				regionCFrame * CFrame.new(-regionSize.X / 2, regionSize.Y / -2, -regionSize.Z / 2),
				regionCFrame * CFrame.new(-regionSize.X / 2, regionSize.Y / -2, regionSize.Z / 2),
				regionCFrame * CFrame.new(regionSize.X / 2, regionSize.Y / -2, regionSize.Z / 2),
				regionCFrame * CFrame.new(regionSize.X / 2, regionSize.Y / -2, -regionSize.Z / 2),
				regionCFrame * CFrame.new(-regionSize.X / 2, regionSize.Y / -2, -regionSize.Z / 2),
			}
			for _, corner in ipairs(corners) do
				local _, onScreen = camera:WorldToViewportPoint(corner.Position)
				if onScreen then
					return true
				end
			end
			table.clear(corners)
			return false
		end

It not great running it in loop, I use them via a scheduler following the player fps

2 Likes

This is useful the region arg in the function is just the object?

Sorry about the function I just fork it from my code you can convert an object into region via this.

		createRegion = function(cframe:CFrame, size:Vector3) : Region3
			return Region3.new(cframe.Position - (size / 2), cframe.Position + (size / 2))
		end

You can try canCameraSeeRegion with an object since it only needs a CFrame and Size

You can use PostSimulation to not cap at 60fps

You could just use RunService to check the magnitude, then run the function if that magnitude were to be less than 40.

And do you know how i can connect and disconnect the code after they left the 40 studs

Okay isnt region 3 decaprecated? Ill still use it if its my only option

There are a lot of ways you can do this depending, it just depends on what you’re trying to specifically do. Like @lnguyenhoang42 said, you technically don’t need to run every heartbeat to check if the script is close, you can just use a part, and when that part is touched, then activate the script. And to detect when player has left you can just use constantly check the player’s character magnitude to the part’s position. [Edit change the fact you don’t need workspace:GetPartsInBounds]

local part = script.Parent::Part
local currentChar

function e()
	while true do
		-- whatever you want to happen
		
		
		if (currentChar.PrimaryPart.Position - part.Position).Magnitude <= 40 then -- Turns script off if player is not 40 studs nearby
			currentChar = nil
			return --Turn off while loop
		end
		task.wait()--so it don't crash
	end
end

part.Touched:Connect(function(hit)
	if not currentChar then
		if hit.Parent:FindFirstChild("Humanoid") then
			currentChar = hit.Parent
			e()
		end
	end
end)

The above script should work, though only detects for a single player near the script.

Also here’s a video you might want to watch when detecting if player is looking at something.

Using workspace :GetPartsInBounfbwill still require a constant check thr gsme has no idea when the player will decide to leave and ghe heartbeat check on the client is just fine. Thanks for the video its something ive been looking for a while

Use Dot Products of Vectors.
The dot product of two unit vectors (length/magnitude = 1) will tell you how similar two vectors are (in terms of direction) i.e. -1 if they’re exactly opposite, 0 if they are perpendicular or 1 if they’re the exact same.

Some code:

local RaycastResult = workspace:Raycast(Origin, Direction, RayParams); --// Make sure `Direction` is a unit vector
if (RaycastResult) then
    if (RaycastResult.Instance) then
        local Hit = RaycastResult.Position;
        local DotProduct = Direction:Dot(Camera.CFrame.LookVector)
        
        if (DotProduct > 0) then
            --// 0 means perpendicular, so "> 0" means within less than 90 degrees (which means its within visible range)
        end;
    end;
end;

i literally never used raycasting for magnitude since its easier to do this

(EndPart.Position - StartPart.Position).Magnitude

It returns the direction into studs and it does the same thing except not using raycasts

You could detect when the player’s CFrame changes

Local Script:

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

local plr = game:GetService("Players").LocalPlayer
local char = plr.Character
local hrp : BasePart = char.HumanoidRootPart

local part = workspace.Part

local d

hrp:GetPropertyChangedSignal("CFrame"):Connect(function()
   if (hrp.Position - part.Position).Magnitude <= 40 then
      d = runService.RenderStepped:Connect(function()
         --code
      end)
   else
      if d then
        d:Disconnect()
      end
   end
end)

or you could use :GetPartBoundsInRadius()

Server Script:

local runService = game:GetService("RunService")

local part = workspace.Part

runService.Heartbeat:Connect(function()
   local inRadius = workspace:GetPartBoundsinRadius(part.Position, 40)

   if #inRadius > 0 then
      for _, v in pairs(inRadius) do
         if v:FindFirstChildOfClass("Humanoid") then
            ---script
         end
      end
   end
end)

Already figured knew this i was stuck on this:

1 Like

Only takeaway from my reply is the concept of dot products.
Whatever I provided was just an example and a use case of how dot products should be used to tell how similar two (unit) vectors are (in terms of direction).