How to tween CFrame without Instances with certain speed

I want to tween (Smoothly change) the CFrame with certain speed because I’m trying to do client-rendering for tower defense game and well game needs to run on server without any parts, and I don’t know how to tween CFrame

I have this but not sure if it fits since I haven’t tested it yet

local RunService = game:GetService("RunService")
local Model = workspace.Part
local Multi = 0
local GoalCFrame = workspace.Goal.CFrame
local Connection

local Speed = 10
Speed = Speed/10000

Connection = RunService.Heartbeat:Connect(function()
	Multi += Speed
	Model.CFrame = Model.CFrame:Lerp(GoalCFrame, Multi)
	if Multi >= 1 then 
		Connection:Disconnect()
	end
end)
1 Like

Your tweening approach using Lerp looks solid! Just make sure you’re setting Multi back to 0 after the tween completes so that it can be reused later if needed. Also, consider adjusting the Speed value to better match your desired tweening duration. Instead of dividing by 10000, try a higher denominator like 60 for a smoother transition over time. Lastly, ensure that the GoalCFrame is set correctly before starting the tweening to avoid any unexpected behavior.

2 Likes

The problem that I had with previous setup that was working correctly is speed limit which was caused by the Lerping itself and by a lot of nodes that I had

If I just use waypoints that are set at corners of path,
Enemy will have limit speed but it will be much higher than it was before, BUT they will slowly turn to wherever the waypoint is facing while moving to it

I can just give position, but they won’t turn and I don’t know how to make them turn

The problem is that even when it looks as if its fully there, it still going on
I can reduce the Multi check to like 0.8, but I dont know to be honest if it will be better

Yeah, to achieve smooth turning towards the waypoint while moving, you can use CFrame to create a look-at behavior. Before moving to the waypoint, calculate the direction to the waypoint and use CFrame.new to adjust the orientation. Here’s a basic example of how you might approach it:

This way, the enemy will smoothly turn towards the waypoint while moving. You can also use TweenService for a smoother transition if needed.

For the speed limit, using waypoints at corners can definitely help control movement speed. Just make sure to adjust the lerp factor or consider using a threshold distance to determine when the enemy should stop moving, ensuring they don’t overshoot the target.

1 Like

I will try your now

I tried using the CFrame.lookAt now and it worked, but since the CFrame I give without rotation, when it lerping, they smoothly turning backwards and instantly looking at waypoint (I do need smooth turning), I decided to use the cframe i got from cframe.lookat and this happened

I use this script that I found somewhere (I’ve changed it to cframe lookat, but normally its using goal only)

For some reason, it just teleports them to a pretty long distance when putting their cframe


image

Sounds like the CFrame might be set incorrectly, which can cause the unexpected teleportation. When updating the CFrame, ensure you’re only modifying the orientation without changing the position too drastically.

Try this approach, where you maintain the current position and only adjust the rotation:

local targetCFrame = CFrame.lookAt(enemy.Position, waypoint.Position)
enemy.CFrame = CFrame.new(enemy.Position) * targetCFrame.Rotation

If you’re still experiencing issues, double-check the values being used for position and ensure they’re being calculated correctly.

Let me know if this resolves the problem!

2 Likes

No hate (i know this isnt related to the topic) but you kind of type like an AI lol

2 Likes

Just tried your script
image

I need to know how I can combine Position and Look At CFrame (When I do they’re always facing same direction, so that means I don’t know how to)

Bruh I missclicekd and marked this post as solution :sob:

Anyway that what I do

I have the script which screenshot I sent somewhere above
The problem is, instead of looking wherever they have spawned (Which is 0 rotation I guess), they do this:
image

Script (if needed as text, tell me):

Ayyyyy Now that’s a compliment lol

2 Likes

you’re not properly applying the rotation from targetFrame. Instead, you should set the CFrame like this:

local targetFrame = CFrame.lookAt(self.Model.PrimaryPart.Position, Frame.Position)
self.Model.PrimaryPart.CFrame = CFrame.new(self.Model.PrimaryPart.Position) * targetFrame.Rotation

Make sure you’re also using CFrame instead of Frame in your code because this ensures you’re creating a proper look-at CFrame based on the position of your target. and Just remember to update this in your movement loop for continuous updates.

1 Like

Is it me or you just rewrite what was on screenshot
Also its not Frame, its cFrame

Ok I’m satisfied with currently what I have, No I haven’t found a fix,

but I decided to use the waypoint creation of node system I use, which makes the turning looks good enough (And speed limit is good too)

The Path Creation:


local Class = {
	["Paths"] = {}
}
Class.__index = Class

function Class.new(PathName: string, Colored: Color3)
	local self = setmetatable({}, Class)
	
	self.StepStuds = 2
	self.SubSteps = 100
	self.SubStepsStuds = self.StepStuds / self.SubSteps
	
	local PathFolder = workspace.Map.Paths:FindFirstChild(PathName)
	
	local TotalPaths = 0
	for i,v in pairs(self.Paths) do
		TotalPaths += 1
	end
	self.PathIndex = TotalPaths + 1
	self.BossExclusive = PathFolder:GetAttribute("BossExclusive")
	self.PathFolder = PathFolder
	self.ArrowsColor = Colored or Color3.fromRGB(0, 255, 150)

	self.Parts = PathFolder.Waypoints:GetChildren()
	table.sort(self.Parts, function(a, b)
		return a.Name < b.Name
	end)

	self.Positions = table.create(#self.Parts)
	for index, part in self.Parts do
		table.insert(self.Positions, part.Position)
	end

	local cframe = CFrame.lookAt(self.Positions[1], self.Positions[2])

	self.CFrames = {cframe}
	self.Waypoints = {}

	for index=2, #self.Positions do
		local TargetPos = self.Positions[index]
		local direction = TargetPos - cframe.Position
		while direction.Magnitude > self.SubStepsStuds do
			cframe = CFrame.lookAlong(cframe.Position + direction.Unit * self.SubStepsStuds, direction)
			table.insert(self.CFrames, cframe)
			
			if #self.CFrames % self.SubSteps == 0 then
				table.insert(self.Waypoints, cframe)
			end

			direction = TargetPos - cframe.Position
		end
	end
	
	for index, cFrame in self.Waypoints do
		local NewPart = Instance.new("Part")
		NewPart.Shape = Enum.PartType.Ball
		NewPart.Size = Vector3.one*0.5
		NewPart.Anchored = true
		NewPart.CanQuery = false
		NewPart.CanCollide = false
		NewPart.CanTouch = false
		NewPart.CFrame = cFrame
		NewPart.Color = Colored or Color3.new(0,0,0)
		NewPart.Parent = workspace
	end

	--for index, cFrame in self.CFrames do
	--	local NewPart = Instance.new("Part")
	--	NewPart.Shape = Enum.PartType.Ball
	--	NewPart.Size = Vector3.one*0.5
	--	NewPart.Anchored = true
	--	NewPart.CanQuery = false
	--	NewPart.CanCollide = false
	--	NewPart.CanTouch = false
	--	NewPart.CFrame = cFrame
	--	NewPart.Color = Colored or Color3.new(0,0,0)
	--	NewPart.Parent = workspace
	--end
	
	Class.Paths[PathFolder:GetAttribute("Index")] = self
	table.sort(Class.Paths, function(a, b)
		return a.PathIndex < b.PathIndex
	end)
	
	print(Class.Paths)
	
	return self
end

return Class

Script I use to move mobs:

function module.LerpMob(Mob, Goal)
	
	repeat
		local StartPos = Mob.Model.PrimaryPart.CFrame

		local dt = task.wait()
		
		local ScatterOffset = Mob.ScatteredOffset or Vector3.zero
		
		local distance = ((Goal.Position+ScatterOffset) - StartPos.Position).Magnitude
		local speed = Mob.Model:GetAttribute("Speed")*dt -- distance traveled between elapsed time
		local estimatedTime = speed /distance -- obtain a lerp fraction between distance traveled in a frame divided by the overall distance towards the goal
		local adjustedLerpAlpha = math.min(estimatedTime,1) -- prevent the lerp from going over 1 which is over the lerp goal
		
		--local lookAt = CFrame.lookAt(Mob.Model.PrimaryPart.Position, Goal.Position)
		--Mob.Model.PrimaryPart.CFrame = lookAt

		Mob.Model.PrimaryPart.CFrame = Mob.Model.PrimaryPart.CFrame:Lerp(Goal+ScatterOffset,adjustedLerpAlpha) -- lerps the position values at constant speed
	until ((Goal.Position+ScatterOffset) - StartPos.Position).Magnitude <= 0.5
end