I am currently making a guard AI for one of the games im working on and I’d really like many NPCs using the same code without having to copy and paste all the code inside of them.
I’m trying to make this with modules but I’ve heard the CollectionService can also be used for this, can you guys tell me which one is better and less resource-consuming?
Current Code
Server Script
--//Services\\--
local RunService = game:GetService("RunService")
--//Variables\\--
local AIModule = require(game.ServerScriptService.GuardAI)
local Player = game.Players.PlayerAdded:Wait()
local Character = Player.Character or Player.CharacterAdded:Wait()
--//Events\\--
local NPCFov = RunService.Heartbeat:Connect(function()
AIModule.NPCFov(Character,script.Parent)
end)
Module Script
local AICore = {}
AICore.NPCFov = function(Character,NPC) --//NPC's field of view main function\\--
local NPCtoChar = (Character.Head.Position - NPC.Head.Position).Unit
local NPCLook = NPC.Head.CFrame.LookVector
local DotProduct = NPCtoChar:Dot(NPCLook)
if DotProduct <= 0.2 then
--//The player is inside the NPC Field of view\\--
game.Workspace.VIEWPART.Color = Color3.fromRGB(255,0,0)
else
--//The player is NOT inside the NPC Field of view\\--
game.Workspace.VIEWPART.Color = Color3.fromRGB(0,255,0)
end
end
return AICore
1 Like
CollectionService is just a convenient way of working with collections (lists) of objects, e.g. often you want a list of all NPCs in your game. It’s a lot like putting all the NPCs in a Folder in Workspace and just calling GetChildren on it, except it’s completely separate from the instance hierarchy which gives you a lot more flexibility by having your “collection-getting code” interfere less with all your other code (there are lots of reasons for changing something’s Parent other than changing what collections it’s in).
You definitely shouldn’t put a copy of the AI script inside each NPC, that’s terrible. Instead have a centralized “NPC manager” script that loops through each NPC and sets up their AI.
E.g. without CollectionService:
local npc_folder = ... --All NPCs MUST be in this folder
function setupNpc(npcModel: Model)
...
end
for _, instance in ipairs(npc_folder:GetChildren()) do
setupNpc(instance)
end
npc_folder.ChildAdded:Connect(setupNpc)
e.g. with CollectionService:
--All NPCs will be included, no matter where they are located (even in ServerStorage or whatever)
local TagS = game:GetService("CollectionService") --because CollectionService is unnecessarily long when all it does is manage tags :P
function setupNpc(npcModel: Model)
...
end
for _, instance in ipairs(TagS:GetTagged("NPC")) do
setupNpc(instance)
end
TagS:GetInstanceAddedSignal("NPC"):Connect(setupNpc)
The reason they look so similar is because the example is really simple.
Rant about which approach is simpler in what situations 🤣
In real examples you’ll see that the CollectionService approach has a bit more complexity because it needs to exclude certain things (e.g. ignoring prefab NPCs in ServerStorage or w/e), while the “Folder” approach may end up with a lot more complexity to include the correct things. A specific example is dealing with mouse raycasts. Any decently complex game can’t use mouse.Target/mouse.Hit, because mouse.TargetFilter can only be set to a single instance, so a single Folder for example. Custom mouse raycasts then have to decide which parts to include or exclude for different situations. With CollectionService it can be as simple as raycastparams.FilterDescendantsInstances = TagS:GetTagged("MouseIgnore")
, while the Folder approach may have to have custom code to look through many different folders/models/whatever to figure out which parts to ignore. This is alleviated by the new-ish “CanQuery” property, but if your collection isn’t related to raycasts or the other spatial queries then you’re out of luck.
As you can see it’s not related to ModuleScripts at all. Your choice of CollectionService vs other ways of managing collections, and your choice of how to use ModuleScripts, are really completely unrelated.
5 Likes
Thank you man, I was very skeptical of using the CollectionService since the wiki made it look too complicated but you made it way easier to understand. Thanks.
1 Like