I’m going to add an attribute called CFrame
on the model which represents the actual CFrame so your other scripts can reference it.
Server code:
--!native
--!strict
local module = {}
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local BezierPath = require(ReplicatedStorage.Packages.BezierPath)
local paths = {}
local Enemies = ReplicatedStorage.Enemies
local refresh_rate = 0.5
module.createnavpath = function(nodefolder, index)
local nodePositions = {nodefolder.enemyspawn.Position}
for i = 1, #nodefolder:GetChildren() - 2 do
table.insert(nodePositions, nodefolder[i].Position)
end
table.insert(nodePositions, nodefolder.exit.Position)
paths[index] = BezierPath.new(nodePositions, 3)
end
module.spawn = function(name:string, nodefolderindex:number, exit, spawns:CFrame, boss:BoolValue)
local newPath = paths[nodefolderindex]
local offset = math.random(-1,1)
local actualModel = Enemies[name]
local model = Instance.new("Part")
model.Name = name
model.CFrame = spawns
model.Size = Vector3.one
model.Anchored = true
model.Transparency = 1
model.CanCollide = false
for i, child in actualModel:GetChildren() do
if child:IsA("ValueBase") then
child:Clone().Parent = model
end
end
print("spawningenemy")
if boss then
ReplicatedStorage.AddHealthBar:FireAllClients(name,model.Health.Value,model.Health.Value)
end
model.Parent = workspace[ReplicatedStorage.Map.Value].enemies
local modelTask = task.spawn(function()
local speed:IntValue = model.speed
local _, size = actualModel:GetBoundingBox()
local PreviousTime = os.clock()
local t = 0
while t < 1 do
t += (os.clock() - PreviousTime) * speed.Value / newPath:GetPathLength()
PreviousTime = os.clock()
model:SetAttribute("CFrame", newPath:CalculateUniformCFrame(t) * CFrame.new(offset, size.Y / 2, 0))
task.wait(refresh_rate)
end
ReplicatedStorage.BaseHealth.Value -= model.Health.Value
model:Destroy()
end)
local health:IntValue = model.Health
health.Changed:Connect(function(newHealth)
if newHealth <= 0 then
task.cancel(modelTask)
model:Destroy()
end
end)
end
return module
Client code:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Map = ReplicatedStorage:WaitForChild("Map")
local Enemies = ReplicatedStorage:WaitForChild("Enemies")
local Connections = {}
local function OnEnemyAdded(enemy)
local model = Enemies[enemy.Name]:Clone()
model.Name = "Model"
model:PivotTo(enemy.CFrame)
model.Parent = enemy
local weldConstraint = Instance.new("WeldConstraint")
weldConstraint.Part0 = model.PrimaryPart
weldConstraint.Part1 = enemy
weldConstraint.Parent = enemy
model.PrimaryPart.Anchored = false
end
local function OnMapAdded(mapName)
for i, connection in Connections do
connection:Disconnect()
end
table.clear(Connections)
local map = workspace:FindFirstChild(mapName)
if not map then
return
end
local enemyFolder = map:WaitForChild("enemies")
local enemyData = {}
table.insert(Connections, enemyFolder.ChildAdded:Connect(function(child)
OnEnemyAdded(child)
child:GetAttributeChangedSignal("CFrame"):Connect(function()
enemyData[child] = child:GetAttribute("CFrame")
end)
end))
table.insert(Connections, enemyFolder.ChildRemoved:Connect(function(child)
enemyData[child] = nil
end))
table.insert(Connections, RunService.Heartbeat:Connect(function(deltaTime)
local i = 1
local parts = {}
local cframes = {}
for part, goalCFrame in enemyData do
parts[i] = part
cframes[i] = part.CFrame:Lerp(goalCFrame, deltaTime * 3)
i += 1
end
workspace:BulkMoveTo(parts, cframes, Enum.BulkMoveMode.FireCFrameChanged)
end))
end
Map.Changed:Connect(OnMapAdded)
OnMapAdded(Map.Value)