Now let’s get to the folder inside the module, specifically the EnemyScripts folder. But first, go ahead to your enemy model and put in an ObjectValue named TargetWaypoint, as well as an Animation object named Walk. You may choose to insert an AnimationId into the Animation object now, or lee it blank.
Now, create a folder named, you guessed it, EnemyScripts inside the module. Then, create 2 scripts with the first one being named Move and the other one being named Animations.
The Move script handles the enemy’s movement through the pathways. It has a function named MoveToWaypoint which is the function that actually moves the enemy. It uses the built-in Humanoid function called MoveTo, which takes in a Position and moves the enemy to that specified position. Then, the function has a MoveToFinished event, which is also built-in into the Humanoid. This MoveToFinished event runs whenever the Humanoid has successfully reached the target position within 8 seconds. If it succeeds, it returns true, and false if not. If the function detects that it got true, it would disconnect the event and move on to the next waypoint. If not, then the function would return the same MoveToWaypoint function in order for the Humanoid to successfully reach the target position. Then the script has a for loop that loops through the path waypoints and runs the MoveToWaypoint function on each iteration on each path.
local Path = workspace:WaitForChild("Path") local TargetWaypoint = script.Parent:WaitForChild("TargetWaypoint") local Humanoid = script.Parent:WaitForChild("Humanoid") local ReachedCurrentWaypoint = false local Finished = nil local function MoveToWaypoint(point) Humanoid:MoveTo(point) Finished = Humanoid.MoveToFinished:Connect(function(reached) print(reached) if reached == false then Finished:Disconnect() return MoveToWaypoint(point) else Finished:Disconnect() ReachedCurrentWaypoint = true return end end) end for i=2,#Path:GetChildren(),1 do ReachedCurrentWaypoint = false local CurrentPath = Path:FindFirstChild(tostring(i)) TargetWaypoint = CurrentPath local DesiredPosition = (CurrentPath.CFrame * CFrame.new(0,0,1)).Position MoveToWaypoint(DesiredPosition) repeat task.wait() until ReachedCurrentWaypoint == true endLastly, the Animations script basically just plays and loops the Walk animation it found within the enemy model. You may change the number between the parenthesis on the Play() so that the animation speed matches the enemy’s walking speed.
local Humanoid = script.Parent:WaitForChild("Humanoid") local WalkAnimation = Humanoid:WaitForChild("Animator"):LoadAnimation(script.Parent:WaitForChild("Walk")) WalkAnimation:Play(1) --// Change this value to match the enemy's walk speed WalkAnimation.Looped = true TESTINGWe can test the system we’ve made by creating a Script inside ServerScriptService. You could name it to anything you want since it will only be used for testing. The script requires the EnemyModule that we’ve scripted and it uses it to run the Spawn function for every iteration of the for loop. You can also see that we used the first 1x1 part as the spawn position of the enemies. You may change the value of the NumberOfEnemyToSpawn as well as the value of the SpawnDelay. Note that the SpawnDelay is in seconds.
local EnemyHandler = require(script.Parent:WaitForChild("EnemyHandler")) local Path = workspace:WaitForChild("Path"):GetChildren() local NumberOfEnemyToSpawn = 5 local SpawnDelay = .75 task.wait(5) for i=1,NumberOfEnemyToSpawn do EnemyHandler.Spawn("Enemy", Path[1].CFrame) task.wait(SpawnDelay) end VIDEO TEST