NPC System Help

Hey guys, I want to make a single script architecture like NPC module where I simply require the module on a server script to make the NPCs work. What I want to do is to make the NPCs walk towards the closest player if the player is close enough and make them punch the player when they’re in range. Right now it isn’t working properly as it has to wait every 1 second to update and the punching isn’t finishing before the next punch comes. I don’t want to reduce it to while wait(.1) as it is proven inefficient but want some efficient way of doing it through a connection or maybe by still using while wait(1) do.

I’ve tried finding replications of the thing I’m trying to do in the devforums already but can’t find one that is efficient.

function attack(i)
	local animationTrack = animations[i][math.random(1,2)]
	animationTrack:Play()
	animationTrack:AdjustSpeed(2)
	wait(animationTrack.Length/animationTrack.Speed)
	print(animationTrack.Length/animationTrack.Speed)
end

for _,v in pairs(NPCs:GetChildren()) do
	enableConnections(v,v:Clone())
end

coroutine.wrap(function()
	while wait(1) do
		for i,npc in pairs(NPCs:GetChildren()) do
			pcall(function()
				local npcHumanoid = npc.Humanoid
				local npcRootPart = npc.HumanoidRootPart
				local closestRootPart
				local lowestMagnitude = math.huge
				for _,plr in pairs(game.Players:GetPlayers()) do
					local humanoidRootPart = plr.Character.HumanoidRootPart
					local magnitude = (npcRootPart.Position-humanoidRootPart.Position).Magnitude
					if magnitude < lowestMagnitude and magnitude < 12 then
						lowestMagnitude = magnitude
						closestRootPart = humanoidRootPart
					end
				end
				npcHumanoid:MoveTo(closestRootPart.Position)
				local magnitude = (closestRootPart.Position-npcRootPart.Position).Magnitude
				if magnitude < 2 then
					if type(coroutines[i]) == "thread" then
						if coroutine.status(coroutines[i]) == "dead" then
							coroutines[i] = coroutine.wrap(function()
								while magnitude < 3 do
									attack(i)
								end
							end)()
						end
					else
						animations[i] = {
							npcHumanoid:LoadAnimation(serverAnimations.rightPunch),
							npcHumanoid:LoadAnimation(serverAnimations.leftPunch)
						}
						coroutines[i] = coroutine.wrap(function()
							while magnitude < 3 do
								attack(i)
							end
						end)()
					end
				end
			end)
		end
	end
end)()
2 Likes

Youtube has some short videos that have code for an NPC to follow and punch players. They’re also somewhat easy to customize. Ex. https://www.youtube.com/watch?v=DbWo9vMsJnE&t=169s

1 Like

Hi, yeah looping isn’t very efficient with this method.

It’s possible, within reason, that RunService.Stepped may serve you better instead of using an loop AND using coroutine.wrap()().

Yes, I could use RunService.Stepped but the question is if that would be more efficient and cause less lag and what you mean by AND using coroutine.wrap()()? Do you mean as I’m using coroutine wrap right now or in some other way?

Also, it still uses a loop and actually uses wait() which is extremely unefficient as it would cause a lot of unnecessary lag. RunService.Stepped would definitely be much more efficient than while wait() do.