yes, i anchored only the primary part.
Is it because it would be hard on the remotes? Because i could try to do something with unreliable remote events.
yes, i anchored only the primary part.
Is it because it would be hard on the remotes? Because i could try to do something with unreliable remote events.
No, itâs because the server wouldnât know the position of the units properly.
OH, okay. So how do i fix the enemys falling apart? also the enemys are floating, even after adding size.y / 2.
Edit: i also noticed that the enemys also start spawning at the first node after a bit of spawning.
Edit: Oops, didnt divide it by 2 But the enemys still spawn at the first node when its laggy. And the enemys still fall apart a lot.
Can you show the code where youâre calling .Spawn
? Also, the :PivotTo
at the start of your function is useless.
I donât have access to the code rn, but itâs just a for loop that calls the module, than has a random wait between 0.2 to 0.4.
Dose bezier path automatically pivot the part?
Edit: Heres the code:
local function spawnenemies(name, amount, exit, enemyspawn, nodes)
for _ = 1, amount, 1 do
local spawnthread = coroutine.create(function()
enemy.spawn(name, nodes, exit, enemyspawn.CFrame)
end)
coroutine.resume(spawnthread)
task.wait(math.random(0.2, 0.3))
end
end
coroutine.resume(coroutine.create(function()
for _, folder in pairs(wave.enemies) do
if lost == true then
break
end
for name, amount in pairs(folder) do
local wrap = coroutine.wrap(spawnenemies)
if lost == true then
break
else
wrap(name, amount, nodefolder.exit, nodefolder.enemyspawn, nodefolder)
end
end
task.wait(10)
end
end))
No, thereâs a reason I said âat the start of your functionâ.
You can try to do it on the client though, remember that you will need to keep track of the position on the server too.
okay, so do i send the value T to the client, and than have it compute on the Client?
And how do i fix the enemys falling apart?
@Katrist
Edit: Also, the first longer path enemies are much faster than the shorter path enemies. It seems that the longer path enemies speed up to make sure they reach the exit the same time as the second path
Edit2: okay i fixed edit one with a different equation for T.
Iâm honestly not very sure. Did this happen when the enemies were unanchored too?
no, the enemies didnt fall apart when it was unanchored
i recommend you donât make a new bezierpath object for every enemy, the precomputation in bezierpath is quite hefty. just make 1 bezierpath object when the game runs, and store it in a table and reuse it by just indexing said table instead of making a new object per enemy.
Also the way you are calculating the T value is not the best way.
You can get smooth movement by just doing:
local PathLength = NewPath:GetPathLength()
local T = (tick() - EnemySpawnTime) / (PathLength / EnemySpeed)
and put this in a run service loop.
It should help you get smoother movement.
They canât make a BezerPath object and cache it because they have an offset variable that changes for every mob, which means that the positions will be different. If that were removed though, this task would be significantly easier.
I did that(make one bezierpath for every path), and then had the enemy add the offset its self.
Also, I found out that the individual body parts arenât separated, but the body parts just arenât loaded in.
Is the performance better?
I would say its better. But the enemys still fall apart
Could you send a video?
just do UniformCFrame * OffsetCFrame
its what i do in my game lol
Sorry for late reply, didnt see that. Heres a video:
Also, its really laggy at the start. How can i fix it?
You can try to offload the work onto the client. Could I see your current code? Youâve said you have implemented it on the client but it doesnât look like it is.
yeah i havent done the client thing. I dont reallly know how i should do that. Heres my code:
--!native
--!strict
local module = {}
local ServerStorage = game:GetService("ServerStorage")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local PhysicsService = game:GetService("PhysicsService")
local moveremote = ReplicatedStorage:WaitForChild("tweenenemy")
local Players = game:GetService("Players")
local BezierPath = require(ReplicatedStorage.Packages.BezierPath)
local janitor = require(ReplicatedStorage.Packages.janitor)
local paths = {}
module.createnavpath = function(nodefolder, index)
local nodePositions = {}
table.insert(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 StartTime = tick()
ReplicatedStorage.DebugValues.EnemyCount.Value += 1
local offset = math.random(-1,1)
local tweenenemy = ReplicatedStorage.tweenenemy
local model: Model = ServerStorage.Enemies[name]:Clone()
--model:PivotTo(spawns + Vector3.new(offset,0,0))
print("spawningenemy")
if boss then
ReplicatedStorage.AddHealthBar:FireAllClients(name,model.Health.Value,model.Health.Value)
end
for _,parts:BasePart in pairs(model:GetChildren()) do
if parts:IsA("BasePart") then
parts.CollisionGroup = "Enemies"
end
end
model.Parent = Workspace:FindFirstChild(ReplicatedStorage.Map.Value).enemies
local health:IntValue = model:WaitForChild("Health")
local healthdestroyconnection = health:GetPropertyChangedSignal("Value"):Connect(function()
if health.Value == 0 then
model:Destroy()
end
end)
--model.PrimaryPart:SetNetworkOwner(nil)
local speed:IntValue = model:WaitForChild("speed")
--model.speed:GetPropertyChangedSignl("Value"):Connect(function()
-- enemySpeed = model.speed.Value
--end)
local _, size = model:GetBoundingBox()
local debugconnection = model.Destroying:Connect(function()
ReplicatedStorage.DebugValues.EnemyCount.Value -= 1
end)
local nodetouchindex = 0
local movethread
movethread = task.spawn(function()
local touchbox:BasePart = model:FindFirstChild("RightFoot")
local noderemoveconnection
noderemoveconnection = touchbox.Touched:Connect(function(hit)
--[[ if hit:FindFirstAncestor("nodes") then
nodetouchindex += 1
table.remove(nodePositions,nodetouchindex)
end ]]
end)
local enemyjanitor = janitor.new()
enemyjanitor:Add(noderemoveconnection)
enemyjanitor:Add(healthdestroyconnection)
enemyjanitor:Add(debugconnection)
local t = 0
local TotalTime = newPath:GetPathLength() / speed.Value
while t < 1 do
t = (tick() - StartTime) / (TotalTime)
model.PrimaryPart.CFrame = newPath:CalculateUniformCFrame(t) + Vector3.new(offset,size.Y / 2, 0)
task.wait()
if not model.PrimaryPart or not model.Parent then
break
end
end
ReplicatedStorage.BaseHealth.Value = math.clamp(ReplicatedStorage.BaseHealth.Value - model.Health.Value,0,ReplicatedStorage.MaxBaseHealth.Value)
model:Destroy()
end)
local speedchanged = nil
speedchanged = speed.Changed:Connect(function(value)
end)
end
return module