RunService and Lerp problem

I have a script right here which basically moves a part to another parts position with Lerp. I basically want to gradually lerp parts.

Here’s a video of it

Here’s the code

local RunService = game:GetService("RunService")

local part = script.Parent
local bruh = workspace:WaitForChild("Bruh")

local runningTime = 0
local lerpTime = 10
local connection

connection = RunService.Heartbeat:Connect(function(deltaTime)
	
	runningTime += deltaTime -- deltaTime, the time (seconds) between each frame (different deltaTimes)
	
	-- runningTime will be the amount of time that has been running since the first Heartbeat
	
	-- if delta the runningTime value increases, the hearbeat will be fired more
	
	local alpha = runningTime/ lerpTime 
    
    print(alpha)
	
	part.CFrame = part.CFrame:Lerp(bruh.CFrame, alpha)
	
	if alpha >= 1 then
		connection:Disconnect()
		print("yes")
	elseif alpha >= 0.5 then
		part.BrickColor = BrickColor.random()
		part.CFrame *= CFrame.new(0, -30, 0)
        print("yes")

        connection:Disconnect()
	end
	
end)

However, I encounter issues such as the part doesn’t move to half of the “Lerp journey”. I mean the alpha parameter.

After the part moves to the targeted parts CFrame, after some time, it starts changing it’s color as well as its CFrame. It basically didn’t stop moving to the targeted parts CFrame even after it has reached its destination.

Everything is pretty much delayed, it still prints the alpha value even when the part has reached its destination.

Is there also some sort of a delay for RunService? (like task.wait() for loops) I checked the script performance for the script with the code above and it’s activity is like 1.9%. It will ruin the game performance. So what’s the benefit of it over loops?

I also don’t know if lerp is just as laggy as tweenservice when not tweened on the client. Is it the same as tweening?

7 Likes

delta time lacks accuracy, just use start tick and tick method.


local start = tick()
local max_time = 10
local connection = ...

function RenderStep()
      local progress = tick() - start
      local alpha = progress / max_time
      part.CFrame = part.CFrame:Lerp(bruh.CFrame, alpha)
	
	if alpha >= 1 then
		connection:Disconnect()
		print("yes")
	elseif alpha >= 0.5 then
		part.BrickColor = BrickColor.random()
		part.CFrame *= CFrame.new(0, -30, 0)
        print("yes")

        connection:Disconnect()
	end
	
end

I don't remember though if tick returns time in milliseconds or seconds so...
5 Likes

Try This Code:

local RunService = game:GetService("RunService")

local part = script.Parent
local bruh = workspace:WaitForChild("Bruh")

local runningTime = 0
local lerpTime = 10
local connection

connection = RunService.Heartbeat:Connect(function(deltaTime)
    runningTime = runningTime + deltaTime -- deltaTime, the time (seconds) between each frame (different deltaTimes)
	
    -- runningTime will be the amount of time that has been running since the first Heartbeat
	
    -- if the runningTime value increases, the heartbeat will be fired more
	
    local alpha = math.clamp(runningTime / lerpTime, 0, 1)
    
    print(alpha)
	
    part.CFrame = part.CFrame:Lerp(bruh.CFrame, alpha)
	
    if alpha >= 1 then
        connection:Disconnect()
        print("Reached destination")
    elseif alpha >= 0.5 then
        part.BrickColor = BrickColor.random()
        part.CFrame = part.CFrame * CFrame.new(0, -30, 0)
        print("Halfway there")
    end
end)
3 Likes

tick actually returns the time in seconds

2 Likes

Btw your code didn’t work, tried running it in a local script.

2 Likes

Your code also didn’t work, it does the exact same thing as above.

3 Likes

then remove part.CFrame *= CFrame part

3 Likes

No, the thing is your code did the same thing as my code above. Like it reaches the end first before executing the elseif statement.

2 Likes

It’s because you’re interpolating between the current part’s CFrame and its final destination - each frame, that distance will shorten, and your alpha will increase; thus, the time it takes to travel between the two will become exponentially smaller

You need to record the part’s initial CFrame, and interpolate between the start and goal positions, i.e.:

local RunService = game:GetService("RunService")

local part = script.Parent
local bruh = workspace:WaitForChild("Bruh")

local runningTime = 0
local lerpTime = 10

-- origin of the part
local origin = part.CFrame

local connection
connection = RunService.Heartbeat:Connect(function(deltaTime)

	runningTime += deltaTime -- deltaTime, the time (seconds) between each frame (different deltaTimes)

	-- runningTime will be the amount of time that has been running since the first Heartbeat

	-- if delta the runningTime value increases, the hearbeat will be fired more

	local alpha = runningTime / lerpTime 
	
	print(alpha)
	
	part.CFrame = origin:Lerp(bruh.CFrame, alpha) -- lerp between the initial position and the final position

	if alpha >= 1 then
		connection:Disconnect()
		print("yes")
	elseif alpha >= 0.5 then
		part.BrickColor = BrickColor.random()
		part.CFrame *= CFrame.new(0, -30, 0)
		print("yes")

		connection:Disconnect()
	end

end)
6 Likes

Oh, so what I did is not interpolating the original CFrame of the part, but the part’s current CFrame?

So it will basically keep on going. Do we actually use the current CFrame or the initial CFrame when lerping?

2 Likes

Also, is there a way to decrease the it’s activity?
Every time I use RunService and I check the script performance, it has a high activity, therefore ruining game performance.

3 Likes

I don’t understand I have this other script, but using a loop.

local part = script.Parent
local clickDetector = part:WaitForChild("ClickDetector")

local targets = workspace:WaitForChild("Targets")
local target1 = targets:WaitForChild("1")

local connection1

connection1 = clickDetector.MouseClick:Connect(function(plr)
	
	while true do
		
		if part.CFrame == target1.CFrame then
			print("yes")
			break
		end
		
		task.wait(0.001)
		part.CFrame = part.CFrame:Lerp(target1.CFrame, 0.1)
	end
	
	connection1:Disconnect()
	print(connection1.Connected)
end)

the :Lerp() function will only work if I use the part’s current CFrame and no the initial CFrame. Isn’t RunService the same as loops? The print statement never executes too even when a condition has met.

3 Likes

As you may or may not know, lerps only calculate the percentage of values, meaning if you want evenly spaced out positions, you must calculate every step before animating between them. Otherwise you will get exponential movement, as seen in your first post.

--non-tested example code of using lerps
local steps = 15
local StepsTable = {}

for i = 1, steps do
	local LerpedPosition = Vector3.new():Lerp(Vector3.new(), 1/steps)
	StepsTable[i] = LerpedPosition
end

local count = 1
while task.wait(3) do
	Part.Position = StepsTable[count]
	count += 1
end

or


local InitalPosition = Vector3.new()
local steps = 15

local count = 1
while task.wait(3) do
	local LerpedPosition = InitalPosition:Lerp(Vector3.new(), count/steps)
	count += 1
	
	if count == steps then
		break
	end
end

you can also lerp by a specific speed or time

--specific speed
local speed = 5 --assumed to be studs per SECOND
local distance = 15
loacl steps = distance/speed

while task.wait(1) do
   --use steps in lerp somewhere below
end

--==============
--==============

--specific time (to reach goal)
local time = 30
local steps = 15
local LoopWaitTime = time/steps

while task.wait(LoopWaitTime) do
   --lerp stuff here
end

If I mistyped something just let me know, and hope this helps! :grin:

4 Likes

How about using run service? is it not good?

2 Likes

unless you have a part that is going to be continously lerped, I wouldnt recomend it. It is possible though


local InitalPosition = Vector3.new()
local steps = 15

local count = 1
game:GetService("RunService").RenderedStepped:Connect(function())
	local LerpedPosition = InitalPosition:Lerp(Vector3.new(), count/steps)
	count += 1
	
	if count == steps then
		break
	end
end)

Generally, use runservice if you have a loop that going to be running for a long time, or something needs to happen before/after a camera/physics update

3 Likes

But won’t it affect game performance if being used for a long time?

2 Likes

I encounter issues such as the part doesn’t move to half of the “Lerp journey”

elseif alpha >= 0.5 then -- (basically alpha >= 0.5 and alpha < 1)
   part.BrickColor = BrickColor.random()
   part.CFrame *= CFrame.new(0, -30, 0)
   print("yes")

   connection:Disconnect() -- You disconnected the connection. it doesn't loop anymore
end

After the part moves to the targeted parts CFrame, after some time, it starts changing it’s color as well as its CFrame. It basically didn’t stop moving to the targeted parts CFrame even after it has reached its destination.

I don’t know if you removed the connection:Disconnect() line in the elseif alpha >= 0.5 statement but it seems very likely that this happened because the codeblock inside the elseif statement repeated

part.BrickColor = BrickColor.random()
part.CFrame *= CFrame.new(0, -30, 0) 
-- Equivalent to part.CFrame = part.CFrame * CFrame.new(0, -30, 0)
-- Therefore it keeps increasing even though it reached your destination

I also checked the video and didn’t find the problems you described in the video, it’d be nice to have a version where there’s an output bar as well.
Alternatively, you can also use TweenService, very easy, fast and convenient rather than lerping

2 Likes

My bad I didn’t notice this but

part.CFrame = part.CFrame:Lerp(bruh.CFrame, alpha)

Because you use part.CFrame as the origin, the lerp journey wouldn’t be consistent and instead it’d look like the part is decelerating the farther it goes. (it starts very fast and stops slowly)
To fix this you should make a variable to keep the original CFrame, and it should lerp linearly.

2 Likes

I just thought lerping would be useful, I still don’t know if it is though.

2 Likes

And this won’t work if I were to use a loop instead of run service.

2 Likes