Getting Bullet Tracers to Spawn Correctly

At the moment, I am using BodyMovers (BodyVelocity in particular) to move my instantiated bullet tracers in a straight line. In general, this works okay- but there is one prevalent issue which has always been present (even in my previous gun-scripts which used similar methods): the tracers starting ahead of where they should be whenever I fire my guns at a relatively fast fire-rate.
As a preface, these tracers are spawned purely locally.

I will start by demonstrating what it SHOULD appear like:

image

You can see that the bullet tracer emits directly from the barrel of the gun.

However, when I begin to fire quickly, the tracers after the first shot appear to be spawning with correct orientation and speed, but incorrect origin.

https://i.gyazo.com/b14bf6d0d543bf14e6031cfb7ab98ece.mp4

You can see that the bullet tracers do not appear to emit directly from the barrel of the gun, but some distance in front.

Here is the hierarchy of the bullet tracer that gets cloned:
image

Here is the code inside of the ‘Run’ ModuleScript which runs every time a tracer is instantiated:

local CFrameNew = CFrame.new
local InstanceNew = Instance.new
local Vector3New = Vector3.new
local MathHuge = math.huge
local TweenService = game:GetService('TweenService')

return function(Origin, Direction, Speed, Parent)
	Origin = Origin or CFrameNew(0, 0, 0)
	Direction = Direction or CFrameNew(0, 0, 0)
	Speed = Speed or 800
	Parent = Parent or workspace
	
	script.Parent.CFrame = CFrameNew(Origin, Direction)
	script.Parent.Name = "Tracer"
	
	local BodyVelocity = InstanceNew("BodyVelocity")
	BodyVelocity.MaxForce = Vector3New(MathHuge, MathHuge, MathHuge)
	BodyVelocity.Velocity = script.Parent.CFrame.LookVector * Speed
	BodyVelocity.Parent = script.Parent
	
	TweenService:Create(BodyVelocity, TweenInfo.new(.4), {
		Velocity = script.Parent.CFrame.LookVector * Speed/15
	}):Play()
	
	game.Debris:AddItem(script.Parent, 2)
	
	script.Parent.Parent = Parent
end

…and the arguments passed into it:

Run(Muzzle.CFrame.Position, position, Config.bullet_speed or 3200, TargetFilterFolder)

I’ve been stuck on this issue for quite a while, and I’m leaning towards believing that the issue lies in the behavior of BodyVelocity.

The only solution I have discovered is reducing the tracer’s speed, but at the point the tracer travels very slow.

If I missed out on any needed information, please let me know. Thanks.

4 Likes

It looks like the increase in fire rate is dropping your frame rate resulting in the bullets being initially rendered a touch later in their “physics lifetime”

You could microprofile the client to see if there’s anything in particular that’s bogging down framerate, then optimize it. Could be anything from your muzzle gas particles being too expensive to some inefficient bits of your code. I typically find most issues like this to be render related, but occasionally I’ll write code without considering runtime cost, so it’s too case specific to say for sure.

2 Likes

My honest best guess is that physics are being applied immediately, so the bullet truly does spawn where it is meant to, except that the velocity is acting quickly so the bullet appears to be spawning ahead of where it should be. Have you tried nullifying the velocity (or freezing the tracer) to see where the bullet spawns and confirming that it does indeed start at the intended origin?

1 Like

Yeah. It always spawns correctly on the barrel of the gun, which is why I think the problem lies in the BodyVelocity.

1 Like

I’ll optimize some things and report back.

1 Like

This is a result of the lowered fps. As the duration of time between the last frame’s physics step and the current frame increases, so will the magnitude of movement with a linear relationship assuming no acceleration is applied to the thing being moved.

Having increased the bullet’s travel distance per frame is what causes a visibly choppy movement where one would expect something smoother.

In this specific situation, the physics/render systems are taking the point in time where you instructed the bullet to exist with it’s forces applied and the current time to solve for the current time’s position of the part using the velocity and forces applied against the last frame. This becomes a problem when the current frame is also the very first frame where the part will be rendered, yet we instructed it to exist in physics on the previous frame. By rendering in this part in it’s current position for the first time, it appears as if it’s been created there; some distance off from where it was expected to spawn at.

At optimal frame rates the duration between frames will average around 0.016 seconds, which increases to 0.033 seconds when you are down to 30fps, even experiencing 0.066 seconds (15fps) between frames on client’s that probably should be running with the graphics setting a bit lower.

The part appears to be acting correctly when it’s anchored at the initial position and when firing slowly because no duration of time has passed or your framerate is still up at a visually acceptable speed, respectively. I’m still sticking with the suggestion for the first stop to be the microprofiler here because the only other real options are to slow down the bullet velocity so less travel time over any given duration occurs or lower your client’s graphic settings to the highest thing that maintains acceptable frame rate under load.

There’s no problem with BodyVelocity or a bug with how it was used; this is just an unavoidable downside to the way video game physics and render systems work. A slew of other problems come about due to this lowered framerate, such as the all too prevalent ‘rubber banding’ plaguing my xbox one from recent games shifting base targets to more powerful versions of the system.

The team at Roblox have done an outstanding job at making sure we had a system that mitigated a majority of the issues that run rampant in mainstream engines, but some of them just do not have a solution outside of increasing frame rate and unfortunately that’s the case here.

1 Like

I did some optimizations but the problem still occurred. However, I put a 0.01 delay timer on the BodyVelocity being instantiated, and it seems to have fixed the problem with the delay being indiscernible, so I can say that is is “solved.”

3 Likes