Basically should’ve asked this early before i started making this, but is it better for all npcs to be handled by one script or each to have their own script?
doing the 2nd method currently and have some code for it
Code
-- Defined Stuff --
local MainFolder = game.Workspace:WaitForChild("Humanoids")
local PlayerFolder = MainFolder:WaitForChild("Players")
local EntityFolder = MainFolder:WaitForChild("Entitys")
local Extras = MainFolder:WaitForChild("Extras")
local Players = game.Players
local RunService = game:GetService("RunService")
local Pfs = game:GetService("PathfindingService")
-- --
local function GetNearestPlayer(NbotCharFrame)
local NPlayer
local Distance
for _, Player in (Players:GetPlayers()) do
if Player.Character and Player.Character.Humanoid and Player.Character.Humanoid.Health ~= 0 then
local Mag = (Player.Character.HumanoidRootPart.Position - NbotCharFrame.Position).Magnitude
if Distance then
if Mag < Distance then Distance = Mag; NPlayer = Player.Character end
else
Distance = Mag; NPlayer = Player.Character
end
end
end
return NPlayer, Distance
end
local function MoveToMovement(Nbot, Distance)
RunService.Heartbeat:Connect(function(DeltaTime)
local NearestPlr, NPlrDistance
NearestPlr, NPlrDistance = GetNearestPlayer(Nbot.Character)
if NPlrDistance and NPlrDistance <= Distance then
if NearestPlr and NearestPlr.Humanoid.Health > 0 then
Nbot.Humanoid:MoveTo(NearestPlr.HumanoidRootPart.Position)
print("Moving To" .. NearestPlr.Name)
end
else
print("All Players out of range")
end
end)
end
local function PathFindingMovement()
end
local function NBotTouched(NBot, Thing, DmgDelay, NBotDamage, DelayTable)
if Thing.Parent:FindFirstChild("Humanoid") then
local Character = Thing.Parent
if table.find(DelayTable, Character) then return end
table.insert(DelayTable, Character)
Character.Humanoid:TakeDamage(NBotDamage)
task.wait(DmgDelay)
table.remove(DelayTable, table.find(DelayTable, Character))
end
end
local function NBotValueChange(NBot, NBotCharacter, Speed, JumpPower, CanBeKilled, Health, NBotPictureID)
NBot.Humanoid.WalkSpeed = Speed
NBot.Humanoid.JumpPower = JumpPower
if CanBeKilled == true then
NBot.Humanoid.MaxHealth = Health; NBot.Humanoid.Health = Health
else
local ff = Instance.new("ForceField", NBot)
ff.Visible = false
NBot.Humanoid.MaxHealth = math.huge; NBot.Humanoid.Health = math.huge
end
NBotCharacter.Back.ImageLabel.Image = "rbxassetid://" .. NBotPictureID
NBotCharacter.Front.ImageLabel.Image = "rbxassetid://" .. NBotPictureID
end
local function NBotSetup(Child)
print("NextBot Has Been Added: " .. Child.Name)
local NextBot = Child
local NextBotCharacterFrame = NextBot.Character
local ValFol = NextBot.ChangeableValues
local _Touched
local Movement
local NextBotDamage = ValFol.Damage.Value
local NextBotSpeed = ValFol.Speed.Value
local NextBotJumpPower = ValFol.JumpPower.Value
local NextBotHealth = ValFol.Health.Value
local CanBeKilled = ValFol.CanBeKilled.Value
local Pic = ValFol.Image.Value
local Dmgtime = ValFol.DmgCooldown.Value
local Distance = ValFol.DetectionDistance.Value
local SmartMovement = ValFol.SmartAi.Value
local Touched = {}
task.wait(.2)
NextBot.PrimaryPart:SetNetworkOwner(nil)
NBotValueChange(NextBot, NextBotCharacterFrame, NextBotSpeed, NextBotJumpPower, CanBeKilled, NextBotHealth, Pic)
if SmartMovement == true then
PathFindingMovement()
else
MoveToMovement(NextBot, Distance)
end
NextBotCharacterFrame.Touched:Connect(function(Thing)
_Touched = NBotTouched(NextBot, Thing, Dmgtime, NextBotDamage, Touched)
_Touched = nil
end)
end
local function CharacterSetUp(Character)
repeat task.wait() until workspace:FindFirstChild(Character.Name)
Character.Parent = PlayerFolder
end
local function PlayerSetup(Player)
Player.CharacterAdded:Connect(CharacterSetUp)
end
Players.PlayerAdded:Connect(PlayerSetup)
EntityFolder.ChildAdded:Connect(NBotSetup)
I am not sure about that question but I recommend putting all those functions into a module script which the script calls so you can edit the npcs easily without having to go to each and every one of them pasting the same thing over and over again.
ex.
local zombieModule = require(path.ZombieAI) -- Requiring a module script that has all the functions in
local char = script.Parent
local plr = zombieModule.FindNearestPlayer(char) --[[Runs a function from the module with the argument of
the zombie it wants to run it to, the argument is there for the module to detect the nearest plr of the
zombie]]
zombieModule.FollowPlr(char, plr) -- runs another function to follow the player in the module with the zombie it wants to move in as well
with that you can easily edit anything in the module script and it will automatically be applied to every
zombie using the module as well
I was thinking about something like this, althought i dont really know how to use module scripts that good to achieve this
I have a thing setup here for this
A bunch of changeable values in a folder which the setup gets all these values and distributes them out where they belong
local function NBotSetup(Child)
print("NextBot Has Been Added: " .. Child.Name)
local NextBot = Child
local NextBotCharacterFrame = NextBot.Character
local ValFol = NextBot.ChangeableValues
local _Touched
local Movement
local NextBotDamage = ValFol.Damage.Value
local NextBotSpeed = ValFol.Speed.Value
local NextBotJumpPower = ValFol.JumpPower.Value
local NextBotHealth = ValFol.Health.Value
local CanBeKilled = ValFol.CanBeKilled.Value
local Pic = ValFol.Image.Value
local Dmgtime = ValFol.DmgCooldown.Value
local Distance = ValFol.DetectionDistance.Value
local SmartMovement = ValFol.SmartAi.Value
local Touched = {}
task.wait(.2)
NextBot.PrimaryPart:SetNetworkOwner(nil)
NBotValueChange(NextBot, NextBotCharacterFrame, NextBotSpeed, NextBotJumpPower, CanBeKilled, NextBotHealth, Pic)
if SmartMovement == true then
PathFindingMovement()
else
MoveToMovement(NextBot, Distance)
end
NextBotCharacterFrame.Touched:Connect(function(Thing)
_Touched = NBotTouched(NextBot, Thing, Dmgtime, NextBotDamage, Touched)
_Touched = nil
end)
end
A module is kind of like a function but can be accessed by any script using require. Module scripts are very easy to make and are very useful as well, I recommend reading up on modules as they will definitely help!
I have a thing setup here for this
What I meant by changing the script is that if you find a bug in it or just something you want to edit to make it better than you will have to do that for every zombie in the game
Creating a module function is almost like making a normal function but with a few changes at the start and end
ex module script:
local module = {} -- Creates the table that will have all the functions and stuff in it
module.myFunction = function(arg1, arg2) -- Dont rlly know why its like this but this is how to make a func in a module
local result = str(arg1) + " " + str(arg2)
return result -- This returns the result to the script calling it
end -- no ")" at the end of the end
return module -- returns the table to whoever is calling it with require
ex script:
local module = require(path.module) -- Gets the module table that has all the functions in it
local answer = module.result("Hello", 5) -- calls the function we made in the module table with 2 arguments and putting it to a variable which will store the return the module gives
print(answer) -- prints the var which stores the module functions return aka the words combined into a string
Output:
“Hello 5”
I am not good at explaining things so I really recommend to read about it on the page here
when i work with ai i personally control all of them with one script, with each having a config module script displaying the properties that would be varying from each ai.
Sorry for the late reponse, but its something like this?
local Nbot = {}
Nbot.FindNearest = function(NbotCharacter)
local NPlayer
local Distance
for _, Player in (Players:GetPlayers()) do
if Player.Character and Player.Character.Humanoid and Player.Character.Humanoid.Health ~= 0 then
local Mag = (Player.Character.HumanoidRootPart.Position - NbotCharacter.Position).Magnitude
if Distance then
if Mag < Distance then Distance = Mag; NPlayer = Player.Character end
else
Distance = Mag; NPlayer = Player.Character
end
end
end
return NPlayer, Distance
end
return Nbot
And then something like
local NbotModule = require(game.ReplicatedStorage.NextBotHandler)
local NearestPlayer, NearestPlayersDistance = NbotModule.FindNearest(NextBotCharacterFrame)
Also another question, how do modules do in loops?
-- The NextBot Handler Module --
local Players = game.Players
local DisableAllBots = false
local Debug = false
local PathFindingService = game:GetService("PathfindingService")
local RunService = game:GetService("RunService")
-- Functions
local function FindNearest(NBC)
local NearestPlayer
local NearestDistance
for _, Player in (Players:GetPlayers()) do
if Player.Character and Player.Character.Humanoid and Player.Character.Humanoid.Health ~= 0 then
local Mag = (Player.Character.HumanoidRootPart.Position - NBC.Position).Magnitude
if NearestDistance then
if Mag < NearestDistance then NearestDistance = Mag; NearestPlayer = Player.Character end
else
NearestDistance = Mag; NearestPlayer = Player.Character
end
end
end
return NearestPlayer, NearestDistance
end
-- Module
local Nbot = {}
Nbot.Setup = function(NextBot)
NextBot.PrimaryPart:SetNetworkOwner(nil)
local ValFol = NextBot.ChangeableValues
local NextBotSpeed = ValFol.Speed.Value
local NextBotJumpPower = ValFol.JumpPower.Value
local NextBotHealth = ValFol.Health.Value
local CanBeKilled = ValFol.CanBeKilled.Value
local Pic = ValFol.Image.Value
local NBotHumanoid = NextBot.Humanoid
NBotHumanoid.WalkSpeed = NextBotSpeed
NBotHumanoid.JumpPower = NextBotJumpPower
if CanBeKilled == true then
NBotHumanoid.MaxHealth = NextBotHealth; NBotHumanoid.Health = NextBotHealth
else
local ff = Instance.new("ForceField", NextBot)
ff.Visible = false
NBotHumanoid.MaxHealth = math.huge; NBotHumanoid.Health = math.huge
end
NextBot.Character.Front.ImageLabel.Image = "rbxassetid://" .. Pic
NextBot.Character.Back.ImageLabel.Image = "rbxassetid://" .. Pic
if not NextBot.Humanoid:GetAttribute("Active") then
NextBot.Humanoid:SetAttribute("Active", false)
end
return "Setup Complete"
end
Nbot.Start = function(NextBot)
local ValFol = NextBot.ChangeableValues
NextBot.Humanoid.Active.Value = true
local Stepped
local NearestPlayer, NearestDistance
Stepped = RunService.Heartbeat:Connect(function(DTime)
print("D")
if NextBot.Humanoid.Active.Value == true then
NearestPlayer, NearestDistance = FindNearest(NextBot.Character)
if NearestPlayer and NearestDistance then
if NearestDistance <= ValFol.DetectionDistance.Value then
NextBot.Humanoid:MoveTo(NearestPlayer.HumanoidRootPart.Position)
end
end
else
Stepped:Disconnect()
end
end)
end
Nbot.Stop = function(NextBot, Stepped)
NextBot.Humanoid.Active.Value = false
end
Nbot.DisableAllBots = function(A)
if A then
print("This function doesnt require anything to be sent, disables all bots")
end
if DisableAllBots == true then
print("Bots are already disabled")
return "Failed, Bots Are Disabled Already"
end
DisableAllBots = true
return "Bots Disabled"
end
Nbot.EnableAllBots = function(A)
if A then
print("This function doesnt require anything to be sent, enables all bots")
end
if DisableAllBots == false then
print("Bots are already enabled")
return "Failed, Bots Are Enabled Already"
end
DisableAllBots = false
return "Bots Enabled"
end
return Nbot
and with a little testing with this script
local i = 0
local NextBotModule = require(game.ReplicatedStorage.NextBotHandler)
repeat wait() i += 20 until i == 20
local NextBot = script.Parent
local SetupStep = NextBotModule.Setup(NextBot)
print(SetupStep)
wait(2)
repeat task.wait() until SetupStep
NextBotModule.Start(NextBot)
print("Started NextBot")
repeat
print("NextBot Will Disable in " .. i .. " Seconds")
task.wait(1)
i -= 1
until i == 0
print("NextBotDisabled")
NextBotModule.Stop(NextBot)
It seems to work fine, although i do not know if ive done something that i could’ve done better