I’m trying to do client-render for tower defense, but my only problem is that I have no idea how to make it move on server
I did one thing, but it doesn’t work well
1. The speed is based off distance (Well obviously why), which make it slow down as it comes nearby the waypoint
It stopping for a while when it reaches waypoint, then continues
On video:
Green part where it actually currently is
Gray part is where it will be for player
Problem Video Link: (If you cant watch, it is uploading or I did something wrong)
Code:
function class:Move(delta) -- Heartbeat loops gives delta!
local CurrentMobPath = self.TargetPath -- path name
CurrentMobPath = shared.Path.Paths[CurrentMobPath] -- path data
if not CurrentMobPath then
warn("Mob path not found!", self.TargetPath)
return
end
local TargetWaypointInstance = CurrentMobPath.Waypoints[self.TargetWaypoint] -- A part!
if not TargetWaypointInstance then return end
-- self.Position is a CFrame
local distance = (self.Position.Position - TargetWaypointInstance.Position).Magnitude
local Speed = self.Speed or 1
local relateSpeed = (distance / Speed) -- Nothing to do with this I think
local goalCFrame = self.Position:Lerp(TargetWaypointInstance.CFrame, math.min(1, self.Alpha))
self.Position = goalCFrame
if debugging then
local LookAt = CFrame.lookAt(self.Position.Position, TargetWaypointInstance.Position)
tweenservice:Create(self.DebugPart2, TweenInfo.new(0.2, Enum.EasingStyle.Sine), {CFrame = LookAt}):Play()
tweenservice:Create(self.DebugPart, TweenInfo.new(0.2, Enum.EasingStyle.Sine), {CFrame = LookAt}):Play()
self.DebugPart2.CFrame = LookAt
end
self.Alpha += (delta / relateSpeed)
if self.Alpha >= 1 then -- Surely problem in this for it stopping for a while, cuz if I change this, it stops for a less period of time
self.Alpha = 0
self.TargetWaypoint += 1
if self.TargetWaypoint > #CurrentMobPath.Waypoints then
self:Destroy()
return
end
end
if self.Health <= 0 then
self:Destroy()
return
end
end
If my hypothesis is correct, relateSpeedis the culprit. relateSpeed is the time it should take to travel a certain distance given a velocity (T=D/V). You’re interpolating the position of the enemy over this time, so the value should be constant. In your case, you’re shifting the goalpost of your alpha value as the enemy gets ever-closer to its target waypoint, and as the distance gets smaller, the relateSpeed value becomes even smaller. This leads to smaller and smaller adjustments to your alpha value, which can explain the decrease in speed as the enemy approaches the target waypoint
TL;DR: Calculate relateSpeed once per interpolation between waypoints
Did you not know? “Lerp” is short for “linear interpolation”. Interpolation is the process of deriving an unknown number between two known numbers. In terms of mathematical functions, it’s about travelling the domain and revealing the function’s range within that domain. To sum it up, recalculate relateSpeed each time you set a new target waypoint. To make this easier, make relateSpeed a property of your object (self). You should rename this property to “targetTime”
Yes. That is the problem. Your relateSpeed variable should only be calculated once each time a new waypoint is set. You’re recalculating this value each time the function is called
function class:GetTargetTime()
local CurrentMobPath = self.TargetPath -- path name
CurrentMobPath = shared.Path.Paths[CurrentMobPath] -- path data
if not CurrentMobPath then
warn("Mob path not found!", self.TargetPath)
return
end
local TargetWaypointInstance = CurrentMobPath.Waypoints[self.TargetWaypoint] -- A part!
if not TargetWaypointInstance then return end
local distance = (self.Position.Position - TargetWaypointInstance.Position).Magnitude
local Speed = self.Speed or 1
local relateSpeed = distance / Speed
self.targetTime = relateSpeed
self.lastWaypointTargetTime = self.TargetWaypoint
end
function class:Move(delta) -- Heartbeat loops gives delta!
local CurrentMobPath = self.TargetPath -- path name
CurrentMobPath = shared.Path.Paths[CurrentMobPath] -- path data
if not CurrentMobPath then
warn("Mob path not found!", self.TargetPath)
return
end
local TargetWaypointInstance = CurrentMobPath.Waypoints[self.TargetWaypoint] -- A part!
if not TargetWaypointInstance then return end
-- self.Position is a CFrame
local distance = (self.Position.Position - TargetWaypointInstance.Position).Magnitude
local Speed = self.Speed or 1
if not self.targetTime then
self:GetTargetTime()
else
if self.lastWaypointTargetTime ~= self.TargetWaypoint then
self:GetTargetTime()
print("Set new target time!")
end
end
local goalCFrame = self.Position:Lerp(TargetWaypointInstance.CFrame, math.min(1, self.Alpha))
self.Position = goalCFrame
if debugging then
local LookAt = CFrame.lookAt(self.Position.Position, TargetWaypointInstance.Position)
tweenservice:Create(self.DebugPart2, TweenInfo.new(0.2, Enum.EasingStyle.Sine), {CFrame = LookAt}):Play()
tweenservice:Create(self.DebugPart, TweenInfo.new(0.2, Enum.EasingStyle.Sine), {CFrame = LookAt}):Play()
self.DebugPart2.CFrame = LookAt
end
self.Alpha += (delta / self.targetTime)
if self.Alpha >= 0.1 then
self.TargetWaypoint += 1
self.Alpha = 0
print("Adjusted waypoint!")
if self.TargetWaypoint > #CurrentMobPath.Waypoints then
self:Destroy()
return
end
end
if self.Health <= 0 then
self:Destroy()
return
end
end
function class.start()
--local con1
--con1 = game:GetService("RunService").Heartbeat:Connect(function(delta)
-- for _, self in pairs(class.Collection) do
-- self:Move(delta)
-- end
--end)
local newMob = class.new("Mob1")
local new
new = game:GetService("RunService").Heartbeat:Connect(function(delta)
newMob:Move(delta)
end)
end
Ah. I think I’ve spotted the issue. Do not interpolate between the current position and the target position. Interpolate between the previous waypoint’s position and the target position