Best way to move particles along ray

I have tested numerous ways of doing this, and I feel like it’s always either choppy or perhaps just not as beautiful as I want it to be,

I currently have a part with particles in it, this part cannot change in size and it needs to move along a ray. How could I go about doing this?

I will be firing all of the clients in order to register this, so it will be done on the client.


I believe games like phantom’s forces and those who remain have a particle system that uses ScreenGuis that are manipulated to look like they are in 3d space.

Not quite sure as to the specifics though


@Amitean It is a single ray, but if I’m not mistaken that will just make one large laser beam. I’m currently attempting to use particles to make a “lazer bullet” move through the air.

I’m doing TweenService now, however the problem at hand is that when a user shoots in the far distance the tween goes faster. Is it possible to make a part move at a constant rate of speed no matter how far its go to location is?

1 Like

It is set to linear, further out the hit point the faster the bullet moves. That’s how Tweening works with UI’s as well. The task will always be completed within the time specified… any way to avoid this?

function GenerateBullet(Player, Start, HitLocation)
	local ray =, (HitLocation - Start).unit * 4.6)
	local hit,pos = Workspace:FindPartOnRayWithIgnoreList(ray, {Player.Character, workspace:FindFirstChild("Rays")})
	local angleShot = script:WaitForChild("bullet"):Clone()
	angleShot.Parent = game:GetService("Workspace")
	local distance = (Start - pos).magnitude
	angleShot.Size =, 0.1, distance)
	angleShot.CFrame =, pos) *, 0, -distance / 2)
	return angleShot

GunInvoke.OnClientInvoke = function(plr, Start, End, Location)
	local Bullet = GenerateBullet(plr, Start, End)
	local tweenInfo =
		0.1, -- Time
		Enum.EasingStyle.Linear, -- EasingStyle
		Enum.EasingDirection.Out, -- EasingDirection
		0, -- RepeatCount (when less than zero the tween will loop indefinitely)
		false, -- Reverses (tween will reverse once reaching it's goal)
		0 -- DelayTime
	local tween = TweenService:Create(Bullet, tweenInfo, {Position = Location})
1 Like

Instead, just lerp your projectile at a constant linear speed that is unchanged by distance.
You only need to have a CFrame endgoal and an increment you want the object to move to that goal by.

You can bind it to Heartbeat so that it is really smooth looking as well!
Heres a code example:

GunInvoke.OnClientInvoke = function(plr, Start, End, Location)
	local Bullet = GenerateBullet(plr, Start, End)
	for i = 1,1000 --some duration amount, can be whatever you want
        Bullet.CFrame = Bullet.CFrame:Lerp(, 0.1) --move it by 0.1 studs to its end goal each iteration, will maintain a linear and constant speed regardless of distance

The nice thing about lerping is that it doesn’t have to reach its endgoal by some time limit like Tweening does

1 Like

Exactly what @Amitean said, you can’t detect when it hits an object.

As well as you get this rather strange effect.

An easy way to get around that is to either base the amount of iterations on distance (which still wouldn’t affect speed) or checking the distance to the endpoint to see whether to break the loop or not.

Like I said in the code comments, the number of iterations can easily be edited and changed.

It doesn’t look like you are implementing lerp in a linear fashion in that video. Regardless, one method for hit detection with CFramed Projectiles is to cast a ray each iteration of your loop to see if the projectile is hitting something. This gives you full hit detection as well as being able to hit things that have suddenly moved into your bullet’s path (since the ray is drawn each time).

Here is a place I made that has a CFramed projectile launcher which uses this method.
its open source

(The RPG is the one that uses the method)