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)
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.
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.
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
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.
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:
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.
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