I would like to make weather for my game but because building is involved I would also like the rain textured particles stop and disappear when they hit objects. I thought of using acual objects that destroy themselves when they hit things but that can cause a lot of lag compared to using particles. the particles are also going to be server sided as they will be coming from clouds moving over the map.
I know that this doesn’t answer your question but why you creating the particles on the server and not simply rendering them on every client. You can easily render them on the client by using the FireAllClients event of a RemoteEvent.
You just adjust the lifetime of the particles, and find the sweet spot for them to disapear. I think this is an easy solution around just a bunch of other things.
that would be good if I knew were all objects would be but players have the freedom to build anywere on the map so for something like this I would need to constantly find the height and position required to make it appear that the particles are being blocked.
I think OP wants a solution where the particles do not go through ceilings, consider it as “dynamic” raindrops.
Adding on to what @mircostaff said, you could achieve this desired effect by rendering the particles on the client. Use raycasts to detect collisions, and temporarily disable that emitter for the client while they are indoors.
I know the basics on raycasting, but how do I rig it up with particleemitters?
Assuming you have a hierarchy similar to this:
Create a raycast at an interval of your choice from the base part. Do know that your interval will require experimentation. From there you can just draw a ray facing downwards towards the baseplate.
You can read more on rays on the developer wiki. Ray | Documentation - Roblox Creator Hub
I have a part with a ray casting downward, how can I adjust the emitters lifetime based on how far the part the ray hit is?
If you raycast to find the distance the particle has to travel, and you know the speed of the particle emitters, you can use the formula
speed = distance/time
and rearrange it to get
time = distance/speed
Simply use the distance and speed values, and set the ParticleEmittter’s lifetime accordingly.
this is what I put together:
while true do
wait(0.1)
local ray = Ray.new(script.Parent.Position, Vector3.new(0,-125,0))
local parts = workspace:FindPartOnRay(ray,script.Parent)
if parts ~= nil then
local PaEm = script.Parent.ParticleEmitter
local distancenumrange = ray:Distance(ray:ClosestPoint(parts.Position))
PaEm.Lifetime = NumberRange.new(distancenumrange / PaEm.Speed)
elseif parts == nil then
print("nil")
end
end
I get an error stating “attempting to perform arithmetic on “Speed” a userdata value” "
Ah, yes. That’s because a particle emitter has a minimum speed or maximum speed. Try PaEm.Speed.Min instead (assuming the min and max speed are the same)
so no errors after adding .min, and the lifetime is changing. but the particles wont stop right at the obstacle
this is some data when I ran the game:
emitter speed is 120
min/max lifetime for emitter is 248193744
the position of the emitters parent (a part) is 144.75, 112, 115.062
Are the min and max values of the particle emitters speed the same?
yes, both min and max for speed is 120
Okay, well since we’re using
time = distance/speed
And time is becoming massive, there are 2 options; either distance value is massive or speed is incredibly small. Try printing out the values for distance, speed, time and the part which the ray is hitting?
without anything but the baseplate in the way:
print(distancenumrange) = 32041408512
print(PaEm.Speed) = 120 120
print(parts.Name) = Baseplate
the particles dont stop at the baseplate but rather keep going down
heres a script that for the most part does change the lifetime to stop at an obstacle but I cant change the ray`s distance without the particles falling out of sync:
while true do
wait(0.1)
local ray = Ray.new(script.Parent.Position, Vector3.new(0,-50,0))
local parts = workspace:FindPartOnRay(ray,script.Parent)
if parts ~= nil then
local distancenumrange = NumberRange.new(ray:Distance(ray:ClosestPoint(parts.Position))) --get the ray distance--
local firstconvert = tostring(distancenumrange)--sub the number into (num,num)--
local secondconvert = string.sub(firstconvert,1,1)--get number to the left--
local thirdconvert = string.sub(firstconvert,3,3)--get number to the right--
local fourthconvert = secondconvert..thirdconvert --combine both numbers--
local finalconvert = "0."..fourthconvert --convert to a number a particle emitter`s lifetime can use--
script.Parent.ParticleEmitter.Lifetime = NumberRange.new(finalconvert)
elseif parts == nil then
print("nil")
end
end
changing the ray higher or lower than 50 causes the particles to stop too high or too low.
Basically have a bunch of particle emitter spawns above your character that you’re constantly CFraming, and do a raycast check for each part consistently.
If you detect a part directly under or over that specific particle emitter spawn, disable the particle emitter. This way, you can create the “effect” of rain directly around your character, which reduces lag overall and is more efficient overall.
i.e.
local model = game.ReplicatedStorage.Assets.RainModel:Clone()
game:GetService"RunService":BindToRenderStep("RainCheck", Enum.RenderPriority.Last.Value, function()
model:SetPrimaryPartCFrame(character.Head.Position + Vector3.new(0, 40, 0))
for _, part in next, model:GetChildren() do
local ray = Ray.new(part.Position + Vector3.new(0, 100, 0), Vector3.new(0, -1, 0)*120) -- raycast down to slightly above the floor
local hitPart = workspace:FindPartOnRayWithIgnoreList(ray, {model, character})
if hitPart then
part.RainParticle.Enabled = false
end
end
end)
This is very rough and it might not give you the exact desired behavior, but this is how I handle rain in games that I make.
Yeah, so distancenumrange is coming out absurdly high. I’ve never used these functions before:
ray:Distance(ray:ClosestPoint(parts.Position))
And I’m not really familiar with these functions. Could these be the issue that’s making the distance extremely big?
I feel like an easier way to get the distance between the 2 parts would be by using the next parameters of FindPartOnRay, and then using the 2 y values to find the difference. Here’s an example:
local hit, hitPosition = FindPartOnRay() -- findpartonray also returns the position
local myPosition = script.Parent.Position
local distance = myPosition.Y - hitPosition.Y -- find the difference in positions
interestingly if I change to speed along with the ray distance I can adjust it just right to have them syncronized.