How do i create an alpha based on a user's framerate?

Hi there,

I’m making a cutscene system, using beziercurves. I find them really interesting but the last time I used them, I ran into some issues. One of them is some players experiencing lag during the cutscenes. I think this happens because my formula for the curve uses a for loop that goes up to 10.000 or so. I think that it’s calculating too many frames inbetween the rendering, and want to calculate an alpha that’s based on the framerate, that I can pass in the function as an x var.

Thanks in advance!

Most if not all RunService render-based events pass the amount of time it took to render the frame as the first param to the connected function, task.wait() returns this number as well (it’s nearly if not exactly the same as runService.Heartbeat:Wait()), so you could use that. Can you show what you have so far?

I see, the problem with this stuff is that if I were to use it, the cutscene would basically last very long.

I haven’t gotten anything done yet, I’m just trying to figure out the best approach based on past experience.

Ah okay.

You will need to first need to figure out how long you want the cutscene to last, let’s say we want to move the camera along a bezier curve and we want the whole movement to take 10 seconds. In that case, we need to first make a variable that tells us how much time has passed, then just add to it every time a frame has passed. For example:

local goalTime = 10

local timePassed = 0
runService.RenderStepped:Connect(function(dt)
    timePassed += dt
end)

Since dt is the amount of time that has passed between the previous and current frame, we can use this to get our time to pass to the bezier function. Doing this is pretty easy, it’s just timePassed / goalTime. This will typically give a number between 0 and 1. If you want to be super precise you can clamp it but it really isn’t necessary as it’s typically not noticeable. It might actually look better if you don’t clamp it as interpolation functions can accept numbers <0 and >1.

Suppose lerp is a function that returns some data type linearly interpolated between p1 and p2, at time. It can be simplified if you’re just working with numbers but given the fact that you’re working with cutscenes, I would assume you’d be working with CFrames or vectors, in that case you could just do p1:Lerp(p2, time) in place of lerp(p1, p2, time).

But I digress, let’s continue.

local function quadraticBezier(p1, p2, p3, time) -- returns the point along the curve at 'time'
    return lerp(lerp(p1, p2, time), lerp(p2, p3, time), time)
end

local goalTime = 10

local timePassed = 0
runService.RenderStepped:Connect(function(dt)
    timePassed += dt
    local percentageComplete = timePassed / goalTime
    -- finally,
    camera.CFrame = quadraticBezier(p1, p2, p3, percentageComplete)
end)

What’s cool is that you can also use the percentageComplete to get easing styles by passing it to TweenService:GetValue()

Anyway, sorry for my rambling but that should hopefully help get you started.

Wow! Amazing reply! Gonna get this tested out right now and I’ll let you know.

1 Like

Hi, so I’ve been trying to figure it out but I don’t understand your quadraticBezier formula. Mine looks like this and I’m not sure on how to combine them.

local function cubicBezier(t, p0, p1, p2, p3)
	return (1 - t)^3*p0 + 3*(1 - t)^2*t*p1 + 3*(1 - t)*t^2*p2 + t^3*p3
end

They’re the same, a basic linear interpolation function is just a + (b - a) * x, with a cubic bezier you’re just interpolating between 4 points which when simplified gives you the formula you posted.

Yes, i figured. Thanks.

It’s somewhat working but I haven’t found the desired result yet:

function Cutscene:lerp(a, b, t)
    return a:lerp(b, t)
end

function Cutscene:quadraticBezier(p0, p1, p2, t)
    return self:lerp(self:lerp(p0, p1, t), self:lerp(p1, p2, t), t)
end

function Cutscene:start()
    if self.enabled then
        if self.runConnection then self.runConnection:Disconnect() end
        
        self.timePassed = 0
        self.runConnection = RunService.RenderStepped:Connect(function(deltaTime)
            self.timePassed += deltaTime
            local percentageComplete = self.timePassed / self.cutsceneTime

            Camera.CFrame = CFrame.new(self:quadraticBezier(self.p0, self.p1, self.p2, percentageComplete))
        end)
    end
end

As you can see, the cutscene doesn’t stop. That seems quite reasonable to me, since there is no limit on the %.

But then also, the curve seems to be inverted? Basically on the moving to the right instead of to the left?

What do you think would be the best approach to fix these issues?

Correction: my bad, the inverted curve is because I wrongly named the parts lol.

You’d have to disconnect the connection once your camera reaches its destination (if self.TimePassed >= goalTime then self.runConnection:Disconnect())

You could also use :BindToRenderStep if you don’t want to have the burden of managing references, then :UnbindFromRenderStep when you need to stop moving the camera.

Or you could use a while loop (while self.timePassed <= goalTime do), but I’m not sure it would be the best option if you’re looking for something modular and easily stoppable

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.