Hello everyone, so I was making my npc enemy ai system and decided to create the npcs on the client to optimize stuff.
However, I encountered a problem. When I tried simulating the game in roblox studio with 2 players, npcs appeared on player 1, but not for player 2 (I tried adding print statements as well)
Scripts:
–// the module for the ai of “Scavenger” enemy
local Replicated = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Deb = game:GetService("Debris")
local AnimationFolder = Replicated:WaitForChild("Assets"):WaitForChild("EnemyAnimations"):FindFirstChild(script.Name)
local StatModule = require(Replicated.Modules.EnemyStats)
local SelfStats = StatModule.Scavenger
local Characters = workspace.Characters:GetChildren()
local module = {}
local CurrentClosest = nil
local CurrentClosestDist = math.huge
module.EnemiesTable = {}
module.Animations = {}
function Bullet(targetpart, originpart)
local beam = Replicated.Assets.Bullet.Beam0:Clone()
beam.Parent = workspace.ClientEffects
local endatt = Instance.new("Attachment", targetpart)
beam.Attachment0 = originpart.ShootPos
beam.Attachment1 = endatt
Deb:AddItem(beam, 0.05)
Deb:AddItem(endatt, 0.05)
end
function module:AI(Character : Model)
print("init")
local Humanoid = Character:WaitForChild("Humanoid")
local Animator = Humanoid:WaitForChild("Animator")
local IdleAnim = Animator:LoadAnimation(AnimationFolder:WaitForChild("Idle"))
local FireAnim = Animator:LoadAnimation(AnimationFolder:WaitForChild("Fire"))
local Reload = Animator:LoadAnimation(AnimationFolder:WaitForChild("Reload"))
local AimAnim = Animator:LoadAnimation(AnimationFolder:WaitForChild("Aim"))
local AimIdleAnim = Animator:LoadAnimation(AnimationFolder:WaitForChild("AimIdle"))
local RunAnim = Animator:LoadAnimation(AnimationFolder:WaitForChild("Run"))
local CurrentClosest = nil
local CurrentClosestDist = math.huge
local ShootInCooldown = false
Character.Name = Character.Name..tostring(math.random(1, 10000))
IdleAnim:Play()
module.Animations[Character.Name] = {}
module.Animations[Character.Name].Idle = IdleAnim
module.Animations[Character.Name].Fire = FireAnim
module.Animations[Character.Name].Reload = Reload
module.Animations[Character.Name].Aim = AimAnim
module.Animations[Character.Name].AimIdle = AimIdleAnim
module.Animations[Character.Name].Run = RunAnim
Humanoid.Running:Connect(function(speed)
--// play run animation if moving
if speed > 0 then
if not RunAnim.IsPlaying then
RunAnim:Play()
end
else
if RunAnim.IsPlaying then
RunAnim:Stop()
end
end
end)
end
RunService.Stepped:Connect(function()
for i, v in module.EnemiesTable do
task.spawn(function()
CurrentClosest = nil
CurrentClosestDist = math.huge
for ia, va : Model in Characters do
local mag = (v.HumanoidRootPart.Position - va.HumanoidRootPart.Position).Magnitude
if mag < CurrentClosestDist and mag <= SelfStats.AggroRange then
CurrentClosest = va
CurrentClosestDist = mag
end
end
--//
if not CurrentClosest then return end
if not v:GetAttribute("ShootCD") then
Bullet(CurrentClosest.HumanoidRootPart, v.NeoRifle.Main)
module.Animations[v.Name].Fire:Play()
v.NeoRifle.Main.Shoot:Play()
v:SetAttribute("ShootCD", true)
task.wait(SelfStats.Firerate)
v:SetAttribute("ShootCD", false)
end
if CurrentClosestDist <= SelfStats.HitRange then
if module.Animations[v.Name].AimIdle.IsPlaying then else
module.Animations[v.Name].AimIdle:Play()
module.Animations[v.Name].Aim:Play()
module.Animations[v.Name].Idle:Stop()
end
local RootPos, Targpos = v.HumanoidRootPart.Position, CurrentClosest:GetPivot().Position
v.HumanoidRootPart.CFrame = CFrame.new(RootPos, Vector3.new(Targpos.X, RootPos.Y, Targpos.Z))
else
module.Animations[v.Name].AimIdle:Stop()
module.Animations[v.Name].Idle:Play()
end
end)
if CurrentClosest then
v.Humanoid:MoveTo(CurrentClosest:GetPivot().Position, CurrentClosest:FindFirstChild("HumanoidRootPart"))
end
end
end)
return module
--[[
--//
CurrentClosest = nil
CurrentClosestDist = math.huge
for i, v : Model in Characters do
local mag = (Character.HumanoidRootPart.Position - v.HumanoidRootPart.Position).Magnitude
if mag < CurrentClosestDist and mag <= SelfStats.AggroRange then
CurrentClosest = v
CurrentClosestDist = mag
end
end
--//
if not CurrentClosest then continue end
if CurrentClosestDist <= SelfStats.HitRange then
if AimIdleAnim.IsPlaying then else
AimIdleAnim:Play()
AimAnim:Play()
IdleAnim:Stop()
end
local RootPos, Targpos = Character.HumanoidRootPart.Position, CurrentClosest:GetPivot().Position
Character.HumanoidRootPart.CFrame = CFrame.new(RootPos, Vector3.new(Targpos.X, RootPos.Y, Targpos.Z))
if not ShootInCooldown then
Bullet(CurrentClosest.HumanoidRootPart, Character.NeoRifle.Main)
FireAnim:Play()
Character.NeoRifle.Main.Shoot:Play()
ShootInCooldown = true
task.wait(SelfStats.Firerate)
ShootInCooldown = false
end
else
AimIdleAnim:Stop()
IdleAnim:Play()
Character.Humanoid:MoveTo(CurrentClosest:GetPivot().Position, CurrentClosest:FindFirstChild("HumanoidRootPart"))
end
]]
–// Main script controller of all ai.
local Replicated = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Deb = game:GetService("Debris")
local player = game.Players.LocalPlayer
local character = workspace:WaitForChild("Characters"):WaitForChild(player.Name)
local Map = workspace.Map:FindFirstChildWhichIsA("Model")
local Enemies = Map:FindFirstChild("Enemies")
local StatModule = require(Replicated.Modules.EnemyStats)
local SelfStats = StatModule.Scavenger
local Characters = workspace.Characters:GetChildren()
print("run")
for i, v : Part in Map:FindFirstChild("Enemies"):GetChildren() do
print("e")
if script.Parent.AIs:FindFirstChild(v.Name) then
print("E")
local NewEnemy : Model = Replicated:WaitForChild("Assets"):WaitForChild("Enemies"):FindFirstChild(v.Name):Clone()
NewEnemy.Parent = workspace.SpawnedEnemies
NewEnemy:PivotTo(v.CFrame)
NewEnemy:SetAttribute("ShootCD", false)
require(script.Parent.AIs[v.Name]):AI(NewEnemy)
table.insert(require(script.Parent.AIs[v.Name]).EnemiesTable, NewEnemy)
end
end