I got some help on making my TD Game enemy System but now I am confused about how will I make the enemies move smoothly, right now they keep teleporting and doing the turning sequence, and thats all I tried tween service but it went horribly wrong any help?
Server Sided Script:
local enemy = {}
local replicated = game:GetService("ReplicatedStorage")
local runService = game:GetService("RunService")
local modules = replicated.Modules
local Waves = require(modules.Waves)
local mobInfoDB = require(modules.mobInfoDataBase)
_G.EnemyDB = {}
local background = require(script.Background)
local events = replicated:WaitForChild("Events")
local enemySyncer = events:WaitForChild("EnemySyncer")
local map = game.Workspace["Crash Test Zone"]
local Nodes = map.Waypoints
local spawnCFrame = Nodes[1].CFrame
local function enemyDead(enemy)
_G.EnemyDB[enemy.EnemyHash] = "dead"
end
local function addEnemyToDB(name)
local Table = {}
for itemName, item in pairs(mobInfoDB[name]) do
Table[itemName] = item
if itemName == "CFrame" then
Table["CFrame"] = spawnCFrame
end
Table["RealName"] = name
Table["EnemyHash"] = #_G.EnemyDB + 1
end
table.insert(_G.EnemyDB, Table)
end
local function IntitiateTurningSequence(enemyData)
if enemyData.Node + 1 >= #Nodes:GetChildren() then
enemyDead(enemyData)
return
end
enemyData.Turning = true
task.wait(((Nodes[enemyData.Node].Position - Nodes[enemyData.Node].Mid.Position).Magnitude / enemyData.Speed) - enemyData.TurnerHelper)
enemyData.CFrame = Nodes[enemyData["Node"]].Mid.CFrame
task.wait((Nodes[enemyData.Node].Mid.Position - Nodes[enemyData.Node].End.Position).Magnitude / enemyData.Speed)
enemyData.Turning = false
enemyData.CFrame = Nodes[enemyData["Node"]].End.CFrame
enemyData.Node += 1
end
local function WaveSequence()
task.wait(5)
for waveCount, waveData in pairs(Waves) do
for EnemyCount, enemyData in pairs(waveData.Enemies) do
task.wait(enemyData.startDelay)
for count = 1, enemyData.Amount do
addEnemyToDB(enemyData.EnemyName)
task.wait(enemyData.Interval)
end
end
end
end
local count = 0
local overallDeltaTime = 0
runService.Heartbeat:Connect(function(deltaTime)
count += 1
overallDeltaTime += deltaTime
for enemyID, enemyData in pairs(_G.EnemyDB) do
if enemyData.Turning == false and enemyData ~= "dead" then
enemyData.CFrame = Nodes[enemyData["Node"]].CFrame:ToWorldSpace(CFrame.new(0, 0, (enemyData.CFrame.Position - Nodes[enemyData["Node"]].Position).Magnitude - (enemyData.Speed * overallDeltaTime)))
local clientEnemyInfo = {
["RealName"] = enemyData.RealName,
["EnemyHash"] = enemyID,
["CFrame"] = enemyData.CFrame,
["Health"] = enemyData.Health,
["Node"] = enemyData.Node,
["Speed"] = enemyData.Speed,
["TurnerHelper"] = 0,
["CornerStatus"] = 0,
["XOffset"] = enemyData.XOffset,
["YOffset"] = enemyData.YOffset
}
enemySyncer:FireAllClients(clientEnemyInfo)
if Nodes[enemyData["Node"]].CFrame:ToWorldSpace():ToObjectSpace(enemyData.CFrame).Position.Z <= 0 then
enemyData.TurnerHelper = (Nodes[enemyData["Node"]].CFrame:ToWorldSpace():ToObjectSpace(enemyData.CFrame).Position.Z * -1) / enemyData.Speed
enemyData.CFrame = Nodes[enemyData["Node"]].CFrame
coroutine.wrap(IntitiateTurningSequence)(enemyData)
end
end
end
end)
coroutine.wrap(WaveSequence)()
return enemy
Client Sided Script:
local replicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local UIS = game:GetService("UserInputService")
local ts = game:GetService("TweenService")
local modules = replicatedStorage:WaitForChild("Modules")
local Events = replicatedStorage:WaitForChild("Events")
local enemyModels = replicatedStorage:WaitForChild("Enemies")
local Waves = require(modules:WaitForChild("Waves"))
_G.EnemyDB = {}
EnemyInfoDB = require(modules:WaitForChild("mobInfoDataBase"))
mobAbilities = require(modules:WaitForChild("mobAbilities"))
local enemySyncer = Events:WaitForChild("EnemySyncer")
local PlayerModels = {}
local Player = Players.LocalPlayer
local playerUI = Player:WaitForChild("PlayerGui")
local healthGUI = playerUI:WaitForChild("HealthUI")
local MainFrame = healthGUI:WaitForChild("Main")
local Name = MainFrame:WaitForChild("Name"):WaitForChild("Name")
local Health = MainFrame:WaitForChild("Bar"):WaitForChild("Health")
local MaxHealth = MainFrame:WaitForChild("Bar"):WaitForChild("MaxHealth")
local HealthText = MainFrame:WaitForChild("Bar"):WaitForChild("HealthText")
local map = game.Workspace["Crash Test Zone"]
local Nodes = map.Waypoints
local rayCast = nil
local barTween = nil
local Camera = workspace.CurrentCamera
local spawnCFrame = Nodes[1].CFrame + Vector3.new(0, 3, 0)
local function enemyDead(enemy)
workspace.Enemies.Active[enemy.EnemyHash].Parent = workspace.Enemies.Dead
workspace.Enemies.Dead[enemy.EnemyHash]:Destroy()
_G.EnemyDB[enemy.EnemyHash] = "dead"
end
local function Lerp(a, b, t)
return a + (b - a) * t
end
local function QuadraticBezier(t, p0, p1, p2)
local l1 = Lerp(p0, p1, t)
local l2 = Lerp(p1, p2, t)
local quad = Lerp(l1, l2, t)
return quad
end
local function mouseRayCast(blackList)
local mousePos = UIS:GetMouseLocation()
local mouserRay = Camera:ViewportPointToRay(mousePos.X, mousePos.Y)
local rayCastParams = RaycastParams.new()
rayCastParams.FilterType = Enum.RaycastFilterType.Exclude
rayCastParams.FilterDescendantsInstances = blackList
local mouseRayCastResult = workspace:Raycast(mouserRay.Origin, mouserRay.Direction * 5000, rayCastParams)
return mouseRayCastResult
end
local function IntitiateDBTurningSequence(enemyData)
if enemyData.Node >= #Nodes:GetChildren() then
enemyDead(enemyData)
return
end
enemyData.Turning = true
task.wait(((Nodes[enemyData.Node].Position - Nodes[enemyData.Node].Mid.Position).Magnitude / enemyData.Speed) - enemyData.TurnerHelper)
enemyData.CFrame = Nodes[enemyData["Node"]].Mid.CFrame
task.wait((Nodes[enemyData.Node].Mid.Position - Nodes[enemyData.Node].End.Position).Magnitude / enemyData.Speed)
enemyData.Turning = false
enemyData.CFrame = Nodes[enemyData["Node"]].End.CFrame
enemyData.Node += 1
end
local function InitiateGraphicalTurningSequenceLoop(deltaTime, enemyId, enemyData, Time, Distance, Position, EndCFrame, lookPos, Node0, Node1, Node2)
if _G.EnemyDB[enemyId] == "dead" then
RunService:UnbindFromRenderStep("CornerTurn"..enemyId)
return
end
enemyData.CornerStatus += deltaTime
Time = enemyData.CornerStatus / Distance
if Time > 1 then
workspace.Enemies.Active:WaitForChild(enemyId).PrimaryPart.CFrame = EndCFrame
enemyData.CornerStatus = 0
RunService:UnbindFromRenderStep("CornerTurn"..enemyId)
else
Position = QuadraticBezier(Time, Node0, Node1, Node2)
lookPos = QuadraticBezier(Time + 0.001, Node0, Node1, Node2)
if workspace.Enemies.Active:FindFirstChild(enemyId) then
workspace.Enemies.Active:FindFirstChild(enemyId).PrimaryPart.CFrame = CFrame.lookAt(Position, lookPos)
end
end
end
local function InitiateGraphicalTurningSequence(enemyId, enemyData)
if _G.EnemyDB[enemyId] == "dead" then return end
workspace.Enemies.Active:FindFirstChild(enemyId).PrimaryPart.CFrame = enemyData.CFrame
local distance = ((Nodes[enemyData["Node"]].Position - Nodes[enemyData["Node"]].Mid.Position).Magnitude / enemyData["Speed"]) - enemyData.TurnerHelper + (Nodes[enemyData["Node"]].Mid.Position - Nodes[enemyData["Node"]].End.Position).Magnitude / enemyData["Speed"]
local Time = 0
local pos = 0
local lookPos = 0
local Node = enemyData["Node"]
local Node0 = Nodes[Node].Position + (workspace.Enemies.Active[enemyId].PrimaryPart.CFrame:ToWorldSpace(CFrame.new(enemyData.XOffset, enemyData.YOffset, 0)).Position - workspace.Enemies.Active[enemyId].PrimaryPart.Position)
local Node1 = Nodes[Node].Mid.Position + (workspace.Enemies.Active[enemyId].PrimaryPart.CFrame:ToWorldSpace(CFrame.new(enemyData.XOffset, enemyData.YOffset, enemyData.XOffset)).Position - workspace.Enemies.Active[enemyId].PrimaryPart.Position)
local Node2 = Nodes[Node].End.Position + (workspace.Enemies.Active[enemyId].PrimaryPart.CFrame:ToWorldSpace(CFrame.new(0, enemyData.YOffset, enemyData.XOffset)).Position - workspace.Enemies.Active[enemyId].PrimaryPart.Position)
local EndCFrame = Nodes[Node].End.CFrame + (workspace.Enemies.Active[enemyId].PrimaryPart.CFrame:ToWorldSpace(CFrame.new(0, enemyData.YOffset, enemyData.XOffset)).Position - workspace.Enemies.Active[enemyId].PrimaryPart.Position)
RunService:BindToRenderStep("CornerTurn".. enemyId, 0, function(DeltaTime)
InitiateGraphicalTurningSequenceLoop(DeltaTime, enemyId, enemyData, Time, distance, pos, EndCFrame, lookPos, Node0, Node1, Node2)
end)
end
local gui = playerUI.MainUI
local tweenService = game:GetService("TweenService")
local function displayEndScreen(status)
local screen = gui.Endscreen
if status == "Game Over" then
screen.Content.Title.TextColor3 = Color3.new(255,0,0)
screen.Content.SubTitle.Text = "Better Luck Next Time"
elseif status == "Victory" then
screen.Content.Title.TextColor3 = Color3.new(0.0627451, 0.427451, 0.00784314)
screen.Content.SubTitle.Text = "Congratulations, You Won!"
end
screen.Content.Title.Text = status
screen.Stats.Money.Text = "Money: "..game.ReplicatedStorage.GameStats.Wave.Value * 10 + 10
screen.Stats.Exp.Text = "Exp: "..game.ReplicatedStorage.GameStats.Wave.Value * 5
screen.Size = UDim2.new(0,0,0,0)
gui.Endscreen.Visible = true
local tweenStyle = TweenInfo.new(0.5, Enum.EasingStyle.Back, Enum.EasingDirection.Out, 0, false, 0)
local zoomTween = tweenService:Create(screen, tweenStyle, {Size = UDim2.new(1,0,1,0)})
zoomTween:Play()
local exitEvent = game.ReplicatedStorage.Events:WaitForChild("Exit")
screen.Teleport.Activated:Connect(function()
screen.Visible = false
exitEvent:FireServer(game.ReplicatedStorage.GameStats.Wave.Value * 10 + 10)
end)
end
local function DoNeededThings(enemy)
local Animation = enemy:WaitForChild("Walk")
local track = enemy:WaitForChild("Humanoid"):WaitForChild("Animator"):LoadAnimation(Animation)
track:Play()
end
local function intitatePlayerScan()
for i,v in pairs(Players:GetPlayers()) do
if v.Character or v.CharacterAdded:Wait() then
table.insert(PlayerModels, v.Character)
end
end
end
Players.PlayerAdded:Connect(function(v)
if v.Character or v.CharacterAdded:Wait() then
table.insert(PlayerModels, v.Character)
end
end)
Players.PlayerRemoving:Connect(function(v)
PlayerModels[v.Character] = nil
end)
--[[local function rayCastLoop()
rayCast = mouseRayCast({PlayerModels})
if replicatedStorage.GameStats.BaseHealth.Value <= 0 then
RunService:UnbindFromRenderStep("RayCastLoop")
end
if rayCast then
if rayCast.Instance:IsDescendantOf(workspace.Enemies.Active) then
MainFrame.Position = UDim2.fromOffset(UIS:GetMouseLocation().X, UIS:GetMouseLocation().Y)
if healthGUI.Values.Hash.Value == _G.EnemyDB[tonumber(rayCast.Instance:FindFirstAncestorWhichIsA("Model").Name)].EnemyHash and healthGUI.Values.Health.Value == _G.EnemyDB[tonumber(rayCast.Instance:FindFirstAncestorWhichIsA("Model").Name)].Health then
barTween = ts:Create(
Health,
TweenInfo.new(
.4,
Enum.EasingStyle.Quad
),
{Size = UDim2.new(_G.EnemyDB[tonumber(rayCast.Instance:FindFirstAncestorWhichIsA("Model").Name)].Health / _G.EnemyDB[tonumber(rayCast.Instance:FindFirstAncestorWhichIsA("Model").Name)].MaxHealth, 0, 1, 0)}
)
barTween:Play()
else
if barTween then
barTween:Cancel()
barTween = nil
end
Health.Size = UDim2.new(_G.EnemyDB[tonumber(rayCast.Instance:FindFirstAncestorWhichIsA("Model").Name)].Health / _G.EnemyDB[tonumber(rayCast.Instance:FindFirstAncestorWhichIsA("Model").Name)].MaxHealth, 0, 1, 0)
end
HealthText.Text = _G.EnemyDB[tonumber(rayCast.Instance:FindFirstAncestorWhichIsA("Model").Name)].Health.."/".._G.EnemyDB[tonumber(rayCast.Instance:FindFirstAncestorWhichIsA("Model").Name)].MaxHealth
healthGUI.Values.Health.Value = _G.EnemyDB[tonumber(rayCast.Instance:FindFirstAncestorWhichIsA("Model").Name)].Health
healthGUI.Values.Hash.Value = _G.EnemyDB[tonumber(rayCast.Instance:FindFirstAncestorWhichIsA("Model").Name)].EnemyHash
Name.Text = _G.EnemyDB[tonumber(rayCast.Instance:FindFirstAncestorWhichIsA("Model").Name)].RealName
healthGUI.Enabled = true
else
healthGUI.Enabled = false
end
else
healthGUI.Enabled = false
end
end-]]
local function timer(data)
task.wait(data.Timer)
return true
end
enemySyncer.OnClientEvent:Connect(function(clientInfo, overallDeltaTime)
if not workspace.Enemies.Active:FindFirstChild(clientInfo["EnemyHash"]) then
local new = replicatedStorage.Enemies:FindFirstChild(clientInfo["RealName"]):Clone()
new.Parent = workspace.Enemies.Active
new.HumanoidRootPart.CFrame = spawnCFrame
new.Name = clientInfo["EnemyHash"]
else
local new = workspace.Enemies.Active:FindFirstChild(clientInfo["EnemyHash"])
clientInfo.CFrame = Nodes[clientInfo["Node"]].CFrame:ToWorldSpace(CFrame.new(0, 0, (clientInfo.CFrame.Position - Nodes[clientInfo["Node"]].Position).Magnitude - (clientInfo.Speed * overallDeltaTime)))
if Nodes[clientInfo["Node"]].CFrame:ToWorldSpace():ToObjectSpace(clientInfo.CFrame).Position.Z <= 0 then
clientInfo.TurnerHelper = (Nodes[clientInfo["Node"]].CFrame:ToWorldSpace():ToObjectSpace(clientInfo.CFrame).Position.Z * -1) / clientInfo.Speed
clientInfo.CFrame = Nodes[clientInfo["Node"]].CFrame
coroutine.wrap(IntitiateDBTurningSequence)(clientInfo)
coroutine.wrap(InitiateGraphicalTurningSequence)(clientInfo["EnemyHash"], clientInfo)
end
new.HumanoidRootPart.CFrame = clientInfo.CFrame + (workspace.Enemies.Active[clientInfo["EnemyHash"]].PrimaryPart.CFrame:ToWorldSpace(CFrame.new(clientInfo.XOffset, clientInfo.YOffset, 0)).Position - workspace.Enemies.Active[clientInfo["EnemyHash"]].PrimaryPart.Position)
end
end)
intitatePlayerScan()