I am attempting to make a flare like projectile that runs on the client. Since it’s supposed to be an effect rather than a gameplay mechanic I am not using raycasts but I still want it to move smoothly.
I couldn’t find any other topics that gave me an answer towards exactly what I am looking for.
Here’s the code I am using:
local fire = nil
local flare = Instance.new('Part', game.Workspace)
flare.Anchored = true
local speedFor = 55
local floatiness = 8
local speedDown = game:GetService("Workspace").Gravity / 10 / floatiness
if game:GetService("Workspace").Gravity <= 0 then
speedDown = 0
end
fire = game:GetService("RunService").RenderStepped:Connect(function(dt)
local ford = (flare.CFrame.LookVector*speedFor)
local down = Vector3.new(0,1)
local poschange = (-ford+down) * dt
local lookchange = ((ford*2)+(down*2)) * dt
flare.CFrame = CFrame.new(flare.Position+poschange,flare.Position+lookchange)
end)
Either way, it keeps dropping too fast at high framerates.
You are using the wrong timing function for a projectile. Documentation specifically states: significant performance issues if RenderStepped is used inappropriately. To avoid this, only use RenderStepped for code that works with the camera or character. Otherwise, RunService.Heartbeat should be used.
So, use Heartbeat:
fire = game:GetService("RunService").Heartbeat:Connect(function(dt)
You might still need to tweak things a little, but it will help that variation you will get between high and low FPS devices.
I think the problem is with the CFrame.new “LookAt” component.
You are setting lookAt with flare.Position+lookchange. The issue with that is that it is taking flare.Position from the previous frame, and not the current frame. Which will be different, depending on the FPS.
I suggest adding poschange to the lookchange component, to make it idependent from the distance travelleds between 2 frames.
If this is gravity, then it is not being adjusted to match the frametime anywhere. So regardless of your FPS the projectile will move down the same amount every frame.
A proper projectile framework implementation should look something like this:
RunService.Heartbeat:Connect(function(dt: number)
--change in gravity
local dg: number = Vector3.yAxis * -workspace.Gravity * dt
--change in velocity
local dv: number = (VELOCITY + dg) * dt
--change in position
PROJECTILE.CFrame = CFrame.lookAlong(PROJECTILE.Position + dv, dv)
end)
fire = game:GetService("RunService").RenderStepped:Connect(function(dt)
local ford = (flare.CFrame.LookVector*speedFor)
local down = Vector3.new(0,1)
local poschange = (-ford+down) * dt -- Here
I also believe this is the problem, although I am unsure of a way to make it go in the direction in a perfect curve without going in a circle or a straight line.
Is this your biggest concern? If so, do one or both of:
Smooth the delta time - many different ways to do this, e.g. one example found here
Set the maximum rate at which the projectile is updated, e.g.
local UPDATE_FREQUENCY = 1 / 60 -- i.e. 60 fps
local delta = 0
game:GetService('RunService').Stepped:Connect(function (gt, dt)
delta += dt
if delta < UPDATE_FREQUENCY then
return
end
delta = math.fmod(delta, UPDATE_FREQUENCY)
-- do update using some deltaTime, computed from either:
-- - (a) a buffered delta time
-- - OR; (b) the elapsed time from the last frame
end)
I will try this out and get back to you, what I mean by “Move Smoothly” is that it doesn’t look choppy when moving each frame. Like for example moving using task.wait which I would never do.