Need help calculating the trajectory of ParticleEmitters

I’m trying to create a splattering system where rays are casted in random directions within an area depending on the spread angle of a particle emitter

Example with 20 then 180 SpreadAngle:

This all works fine, the problem is that I’m trying to adjust the direction of the ray based off of the speed and acceleration properties of the ParticleEmitter to make the rays hit where the particles would actually hit when being affected by physics

Example:

I’ve made a lot of attempts at calculating it but most of them were just trying to divide/multiply the speed and acceleration in different ways because I couldn’t find a physics formula for such a specific scenario

My code:

local function splatter(inst, cframe_offset, spread, speed, amount)
	task.spawn(function() 

		local s_att = Instance.new("Attachment", inst) s_att.Name = "splatter_attachment"
		local s = splatter_effect:Clone() s.Name = "splatter_effect"
		s_att.CFrame *= cframe_offset
		s.Parent = s_att
		s.SpreadAngle = Vector2.new(spread, spread)
		s.Speed = speed 
		s.Enabled = true
		s:Emit(amount)
		
		task.delay(s.Lifetime.Max, function() s_att:Destroy() end)
		
		for _ = 1, amount, 1 do
			
			local stop_time = speed.Max / math.abs(s.Acceleration.Y)
			local distance = (speed.Max * stop_time + 0.5 * s.Acceleration.Y * stop_time ^ 2) / stop_time 
			local random_rotation = Vector3.new(math.random(-spread, spread), math.random(-spread, spread), math.random(-spread, spread))
			local direction = (s_att.WorldCFrame * CFrame.Angles(math.rad(random_rotation.X), math.rad(random_rotation.Y), math.rad(random_rotation.Z))).LookVector
			
			local ray = workspace:Raycast(s_att.WorldPosition, direction * distance, ray_params) 

			if ray then
				
				local vis = Instance.new("SphereHandleAdornment", workspace)
				vis.Adornee = workspace.Terrain
				vis.Color3 = Color3.new(1,0,0)
				vis.Radius = 0.15
				vis.CFrame = CFrame.new(ray.Position)
				
			end
		end
	end)	
end
2 Likes

I’m not sure- but this forum post might help: Understanding Roblox Physics and Their Conversions to Real Units

That doesn’t help much since I don’t know what numbers to convert in the first place, but thanks for trying

It is clear from a simple test (and from the ROBLOX documentation) that the speed of a particle is measured in studs per second.

This can be verified visually by placing an Attachment in a Part (to ensure the particle’s spawn position is consistent) and placing a ParticleEmitter in that Attachment. You will see that when the Speed of the ParticleEmitter is set to 1, the particle will travel exactly one stud.

It is also clear (and yes, the docs say this too) that acceleration is in studs/sec^2. This can also be easily verified visually by doing the same, but setting the acceleration of that ParticleEmitter to be one stud in the direction of travel. The particle will travel, per second, an additional extra stud, per second. This can be verified mathematically using the oh-so-popular distance with acceleration formula:

d = ut + 1/2 * at^2
where

  • d is distance traveled by the particles produced by a ParticleEmitter
  • u is the initial Speed of a ParticleEmitter
  • a is the Acceleration of a ParticleEmitter
  • t is the Lifetime of a ParticleEmitter

Substituting in values for a ParticleEmitter with an initial Speed of 1, a Lifetime of 3 and an Acceleration of 1 in the direction of travel, we expect that particle to travel a total of 7.5 studs, and indeed it does:

d = 1*3 + 1/2(1 * 3^2)
d = 7.5 studs

So, it is probably safe to assume that ParticleEmitters obey the physics engine like Parts do and that these generalize to 3D space. You just need to figure out what properties of the ParticleEmitter correlate to the Raycast and go from there. Since it seems like your particles are traveling in parabolic arcs, you could probably leverage formulas for calculating the trajectory of a projectile thrown in a parabolic arc and figure out where that particle would land (and thus, what direction the ray should cast in to intersect that point).

Recall that for projectile motion, the individual components of motion do not influence each other; that is, the Y-velocity of a particle has no bearing on its X-velocity or Z-velocity. Here is a good link that summarizes the relevant formulas

3 Likes

Sorry for the late response, Tysm that helped me out a lot, I ended up shooting the ray to the end position of the ParticleEmitter using:

local end_pos = attachment.WorldCFrame.LookVector * speed_average * lifetime.Max + 0.5 * particle_emitter.Acceleration * lifetime.Max^2

and it works pretty well, It gets incredibly inaccurate if the ParticleEmitter has a long lifetime, however for my use case it will do and I don’t think my sanity can take another 5-day long expedition to make it perfectly accurate.

1 Like