Raycast gun: bullet visual spawned client-side doesn't work

I’m trying to create a basic raycast weapon system and I want to generate a bullet client-side for visuals. The bullet spawns properly, with the right position and rotation, but it just stays there floating in the air without moving or disappearing, which is what a LocalScript in the bullet itself is meant for.

This is the bit of code that spawns the bullet from a LocalScript, which again, seems to be working fine:

	-- perform client-side visuals
	local hit = raycast.CalculateRay(client, tool, hitPos)
	local bullet = RepStorage:WaitForChild("Weapons"):WaitForChild("Bullets"):WaitForChild("Bullet"):Clone()

	bullet.CFrame = CFrame.lookAt(shootPart.Position, hitPos)
	bullet.Parent = workspace

And here’s the LocalScript that’s parented to the bullet:

local bullet = script.Parent
local speed = 50
local deleteTime = 2

local Run = game:GetService("RunService")

local timer = 0

Run.RenderStepped:Connect(function(delta)

	bullet.Position = bullet.Position + (bullet.CFrame.LookVector * speed * delta)

	timer = timer + delta
	if timer > deleteTime then
		bullet:Destroy()
	end
end)

What’s strange to me is that the game seems to simply ignore the RenderStepped event; I also tried doing a while loop to see if it was an issue with RunService, but that didn’t help. It’s as if the script didn’t exist at all. Is there a different way I should be approaching this?

You could just use velocity and debris instead of a whole RenderStepped something like this:

bullet.Velocity = (bullet.CFrame.LookVector * speed * delta)
game:GetService(“Debris”):AddItem(bullet, 2 --The time it will take to destroy–)

1 Like

Thanks, this code does seem way better than what I had, although it still doesn’t execute when I spawn the bullet itself. It just looks like the LocalScript doesn’t initialize for some reason.

if it is a playerscript just add a wait() before all the stuff

  1. .Velocity is deprecated.
  2. Relying on the physics engine means the bullet can physically slow down due to throttling, causing it to desync.
  3. Using the Debris service means that the bullets are immutable; once they’re set to be deleted, there’s nothing you can do to cancel that. Their original method of accumulating a number is a better solution.

realism using the velocity, it still works also I don’t think he wants to cancel the bullet destruction

CFraming a bullet constantly with math is just as realistic. Physics throttling the bullet due to laggy performance is definitely not realistic.

also basic cframing wont take gravity into consideration

Is the local script parented to workspace? If so, the local script won’t run.

1 Like

???

Use math like I said?

This is from my own bullet handler module:
(it’s quite old, but it’s proof that it’s possible)

t.v += t.gv * dt --add gravity (t.gv) to the current velocity
local ch = t.v * dt --the change in position of the bullet
local nx = t.p.CFrame + ch
t.p.CFrame = CFrame.lookAt(nx.Position, (nx + ch).Position) --position and orientate the bullet

Well, it’s parented to the bullet itself, which I guess does count :sweat_smile:

I got it working by changing the velocity of the bullet from the LocalScript in the weapon, but I’m not too happy with it since the bullet falls too fast; however, I don’t want to change the game’s gravity just for this one purpose, so I need to find a way to use the CFrame method that’s being talked about instead.

Refer to what I posted.
Basically, you have a velocity value attributed to each bullet that can change independently. Gravity (a Vector3) gets added to the velocity on every frame. Then the velocity is applied to the position of the bullet itself. You’ll have to use the deltatime of the RenderStepped event for the math.

Here’s a pseudocode in case you didn’t understand the first sample I posted:

--this is a constant. It should be updated when the workspace gravity itself updates.
local gravityVector = Vector3.new(0, -workspace.Gravity, 0) --note the negative sign!

--[inside the RenderStepped loop]--

--bulletVelocity is a Vector3 in worldspace, just like the actual .Velocity property of parts.
--multiply the gravity vector3 by the deltatime and add it to the velocity.
bulletVelocity += gravityVector * deltatime

--Distance is just speed multiplied by time. This would be the change-in-position of the bullet.
local displacement = bulletVelocity * deltatime

--add the displacement to the bullet's position to move it by a single frame.
bulletPosition += displacement

--now would be the time to use Raycast for hit registration. The "displacement" variable can be reused here as the direction component.

--rinse and repeat for each bullet on each RenderStepped.
2 Likes

Thanks for the explanation, works flawlessly!