how could i make the rotations more like a curve? srry if im being annoying, but i just want to finish off my enemy system and be done with it.
You can try using bezier tweens on the NPC when nearing the end:
Also, don’t worry about asking questions. Sorry for not solving your problem earlier, I feel bad for taking this long.
You could also try using a Catmull Rom Spline for your entire track:
thank you! il try using the modules today.
Wait if i use the module what would i put as my control points?
Not sure, I’ve never used those modules before. They should have some documentation though.
Also, here’s another module for tower defense games:
hm. It looks good, but it still seems… kind of too smooth? okay that just sounds really stupid, but I want to make the rotations realistic, not smoother than soap. can u give me some pointers on how to make a curve rotation from scratch? Thanks
also, some weird bug where the client dosent finish the tween beforethe server teleports it. Heres a video:
hers the code:
--!native
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")
module.spawn = function(name: string, waypointfolder: Folder, exit, spawns: CFrame, boss: BoolValue)
local offset = math.random(-1, 1)
local model: Model = ServerStorage.Enemies:FindFirstChild(name):Clone()
model:PivotTo(spawns + Vector3.new(offset, 0, 0))
if boss then
ReplicatedStorage.AddHealthBar:FireAllClients(name, model.Health.Value, model.Health.Value)
end
--for _,parts:BasePart in pairs(model) do
-- if parts:IsA("BasePart") then
-- parts.CollisionGroup = "Enemies"
-- end
--end
model.Parent = Workspace:FindFirstChild(ReplicatedStorage.Map.Value).enemies
--local health = model.health
--health:GetPropertyChangedSignal("Value"):Connect(function()
-- if health.Value == 0 then
-- model:Destroy()
-- end
--end)
model.PrimaryPart:SetNetworkOwner(nil)
local enemySpeed = model.speed.value
--model.speed:GetPropertyChangedSignl("Value"):Connect(function()
-- enemySpeed = model.speed.Value
--end)
local _, size = model:GetBoundingBox()
for index = 1, #waypointfolder:GetChildren() - 2 do
local node = waypointfolder[index]
local finished = false
local distance = (node.Position + Vector3.new(offset, size.Y / 2, 0) - model.PrimaryPart.Position).Magnitude
local movethread = task.spawn(function()
local movementgoal = {
CFrame = CFrame.lookAlong(
node.Position + Vector3.new(offset, size.Y / 2, 0),
model.PrimaryPart.CFrame.LookVector
),
}
ReplicatedStorage.tweenenemy:FireAllClients(model, distance / enemySpeed, movementgoal)
task.wait(distance / enemySpeed)
model.PrimaryPart.CFrame = CFrame.lookAlong(
node.Position + Vector3.new(offset, size.Y / 2, 0),
model.PrimaryPart.CFrame.LookVector
)
finished = true
end)
local speed: IntValue = model:WaitForChild("speed")
local changedthread = nil
local speedChanged = nil
speedChanged = speed:GetPropertyChangedSignal("Value"):Connect(function()
if movethread then
task.cancel(movethread)
movethread = nil
end
if changedthread then
task.cancel(changedthread)
changedthread = nil
end
enemySpeed = model.speed.value
distance = (node.Position + Vector3.new(offset, size.Y / 2, 0) - model.PrimaryPart.Position).Magnitude
print(
"newspeed: "
.. tostring(enemySpeed)
.. " "
.. "newdistance: "
.. tostring(distance)
.. " "
.. "newtime: "
.. " "
.. tostring(distance / enemySpeed)
)
changedthread = task.spawn(function()
print("updating tweens")
local movementgoal = {
CFrame = CFrame.lookAlong(
node.Position + Vector3.new(offset, size.Y / 2, 0),
model.PrimaryPart.CFrame.LookVector
),
}
ReplicatedStorage.tweenenemy:FireAllClients(model, distance / enemySpeed, movementgoal)
task.wait(distance / enemySpeed)
model.PrimaryPart.CFrame = CFrame.lookAlong(
node.Position + Vector3.new(offset, size.Y / 2, 0),
model.PrimaryPart.CFrame.LookVector
)
finished = true
end)
end)
repeat
task.wait()
until finished == true
speedChanged:Disconnect()
local rotationgoal = {
CFrame = CFrame.lookAlong(model.PrimaryPart.Position, node.CFrame.LookVector),
}
local rotation
ReplicatedStorage.tweenenemy:FireAllClients(model, 0.05, rotationgoal)
task.wait(0.05)
if not model then
break
end
model.PrimaryPart.CFrame = CFrame.lookAlong(model.PrimaryPart.Position, node.CFrame.LookVector)
end
if model then
local node = exit
local finished = false
local distance = (node.Position + Vector3.new(offset, size.Y / 2, 0) - model.PrimaryPart.Position).Magnitude
local movethread = task.spawn(function()
local movementgoal = {
CFrame = CFrame.lookAlong(
node.Position + Vector3.new(offset, size.Y / 2, 0),
model.PrimaryPart.CFrame.LookVector
),
}
ReplicatedStorage.tweenenemy:FireAllClients(model, distance / enemySpeed, movementgoal)
task.wait(distance / enemySpeed)
model.PrimaryPart.CFrame = CFrame.lookAlong(
node.Position + Vector3.new(offset, size.Y / 2, 0),
model.PrimaryPart.CFrame.LookVector
)
finished = true
end)
local speed: IntValue = model:WaitForChild("speed")
local changedthread = nil
local speedChanged = nil
speedChanged = speed:GetPropertyChangedSignal("Value"):Connect(function()
if movethread then
task.cancel(movethread)
movethread = nil
end
if changedthread then
task.cancel(changedthread)
changedthread = nil
end
enemySpeed = model.speed.value
distance = (node.Position + Vector3.new(offset, size.Y / 2, 0) - model.PrimaryPart.Position).Magnitude
print(
"newspeed: "
.. tostring(enemySpeed)
.. " "
.. "newdistance: "
.. tostring(distance)
.. " "
.. "newtime: "
.. " "
.. tostring(distance / enemySpeed)
)
changedthread = task.spawn(function()
print("updating tweens")
local movementgoal = {
CFrame = CFrame.lookAlong(
node.Position + Vector3.new(offset, size.Y / 2, 0),
model.PrimaryPart.CFrame.LookVector
),
}
ReplicatedStorage.tweenenemy:FireAllClients(model, distance / enemySpeed, movementgoal)
task.wait(distance / enemySpeed)
model.PrimaryPart.CFrame = CFrame.lookAlong(
node.Position + Vector3.new(offset, size.Y / 2, 0),
model.PrimaryPart.CFrame.LookVector
)
finished = true
end)
end)
repeat
task.wait()
until finished == true
speedChanged:Disconnect()
ReplicatedStorage.BaseHealth.Value = math.clamp(
ReplicatedStorage.BaseHealth.Value - model.Health.Value,
0,
ReplicatedStorage.MaxBaseHealth.Value
)
model:Destroy()
end
end
return module
Edit: the only things i changed with the spawning is how the enemys are spawned. I made the wave system work with dual lanes, so calling the module more.
Make the wait longer. It’s most likely looking like this because it takes time for the client to receive the event.
Is this what you want?
I am going to try implementing this today. Thank you!
Also i noticed that now, if the client is lagging badly, the enemy will start teleporting around. Is there any way I can fix this?
Okay, i am in the process of implementing it, i am just trying to figure out where to put the 3rd control point. I am using Bezier Path. Something in noticed about the system is that when the enemy count starts to rack up, the enemys start instantly teleporting/spawning right at the 1st or second node. Heres a vid:
Also, the lag is getting a bit out of hand is there any way i could optimize this more? And again, sorry for bothering you. Thanks!
Edit: this dosent have the curves implemented
You could try to get rid of all the humanoids, because those have a lot of lag.
You can try to put a point at every node for BezierPath.
I already did delete the humanoids.
So do I just put a point at the corner of every node, and use that for the control points?
@Katrist
No, just use every node’s position in your positions table for the BezierPath.new
.
Okay? But I thought we needed an extra node to pull the curve up?
If you want the curve to be more exaggerated, you can move the nodes.
Also, could you show some code?