How to turn on/off tweens and particle emitters based on player proximity?

I have an open world, and it is quite large.

There are tweens and particle emitters all across the map (there are over 1000).

Obviously this has a large effect on CPU, so my plan is to only turn on these effects when the player is near them.

What is the best way to do that in Roblox?

I know that I can use magnitude to see how far any part is away from the player.

local distance = (HumanoidRootPart.Position - OtherPart.Position).magnitude

What I’m not sure about is how to check 1000’s of parts in an optimal way every few seconds.

My best guess (and I haven’t tried this yet) is to create a table that has a reference to all tweens and particle emitters, and then every 5 seconds scan the table to switch off effects outside of X distance and switch on effects near the player.

I guess I could dynamically build that table when the player joins the game by looping through all parts in the workspace adding a reference to the part in the table if it is a tween or a particle emitter.

Is that the right way? Or is there something better already built in to Roblox?

Thanks in advance for your thoughts!

1 Like

disable them by default, then use workspace:FindPartsInRegion3WithWhiteList() in a loop

Yess! That is awesome!

I know I can probably work this out but just in case you feel like sharing how would I pass the current player and the radius to check into that function?

No worries if you don’t have time - and thanks so much this is already a huge help.

1 Like

Just found this. I think it might be part of the answer?

local function CreateRegion3FromLocAndSize(Position, Size)
	local SizeOffset = Size/2
	local Point1 = Position - SizeOffset
	local Point2 = Position + SizeOffset
	return Region3.new(Point1, Point2)
end

I guess you pass in Workspace as the whitelist?

no worries!
try something like this:

– in local script

local folderContainingAllObjects = workspace.ParticleEmitterFolder
local radius = 10

while wait(1) do
     for _, v in pairs(folderContainingAllObjects:GetDescendants()) do
          if v:IsA("ParticleEmitter") then
               v.Enabled = false
          end
     end
     local anchorCF = localPlayer.Character.HumanoidRootPart.CFrame
     local r1 = anchorCF * CFrame.new(radius, radius, radius)
     local r2 = anchorCF * CFrame.new(radius, radius, radius):Inverse()
     local region = Region3.new(
          Vector3.new(math.min(r1.X, r2.X), math.min(r1.Y, r2.Y), math.min(r1.Z, r2.Z),
          Vector3.new(math.max(r1.X, r2.X), math.max(r1.Y, r2.Y), math.max(r1.Z, r2.Z)
     )
     local parts = workspace:FindPartsInRegion3WithWhiteList(region, {folderContainingAllObjects})
     for _, aPartInThisRadius in pairs(parts) do
          local particleEmitter = aPartInThisRadius.ParticleEmitter -- you will have to change this to how you need it
          particleEmitter.Enabled = true
     end
end

the reason i did the Region3 like that was because it usually wants it given from corner to corner.
Good luck on your project!

1 Like

So is this not as good then?

local folderContainingAllObjects = workspace.ParticleEmitterFolder
local radius = 50

while wait(1) do
     for _, v in pairs(folderContainingAllObjects:GetDescendants()) do
          if v:IsA("ParticleEmitter") then
               v.Enabled = false
          end
          local distance = (localPlayer.Character.HumanoidRootPart.Position - v.Position).magnitude
          if distance < radius then
                v.Enabled = true
          end
     end
end

Just trying to wrap my head around what workspace:FindPartsInRegion3WithWhiteList brings to the party?

Oops it didnt see this reply lol
This will work perfect, but the only problem is that using .Magnitude is really expensive and uses a lot of computing power in Roblox, that’s why I was suggesting using Region3, but this should work just fine.

Oh in that case I’m not even going to try my version!

One thing, I am tagging parts rather than using a folder. How can I pass the tagged parts into the workspace:FindPartsInRegion3WithWhiteList function

local collectionService = game:GetService("CollectionService")
local taggedParts = collectionService:GetTagged("Effects")

That is how I get the tagged parts ^^^. Right now I get the error `Unable to cast value to Object.

Thanks in advance :slight_smile:

Nevermind, I just needed to pass it in without the {} but now no parts are ever showing up. Running some more tests will get back.

I wasn’t able to get the region3 version to work so I went with my noob version. It doesn’t seem to be having an impact on the CPU but I’ll circle back to the better way when I have more time.

What was happening with Region3 was some kind of CPU spike and Roblox studio froze. I guess it’s something to do with me using a tags plugin collection rather than a folder.

I’ll probably circle back to this when there are a 2000+ effects in the game. The noob version is working pretty well for the moment though.

if it works and you dont notice any lag, then just go with that :ok_hand:

1 Like