Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

How can i use a Module script to make my code more organised and efficient?

Hello, I'm working on my NPC for my game and so far have achieved awesome progress it works flawlessly as of so far however, to make it easier for my self i'd love to get into Module scripts as that will allow me to easily navigate through my code when it comes to error fixing and adding code in general. The issue is, where do i get started? I understand the practicality of module scripts but when i open up one of those scripts i feel really awkward on how to use them.

Here is all my code for the NPC for those who are interested:

-Controller

local Event = script.Parent:WaitForChild("findTarget")

local npcStorage = workspace.Game.npcStorage

while true do wait(1)
	if #npcStorage:GetChildren() >0 then
		Event:FireServer()
	else
		script.Parent:WaitForChild("Target").Value = ""
	end
end

-TargetFinder

local Event = script.Parent:WaitForChild("findTarget")

Event.OnServerEvent:Connect(function()	
	local NPC = script.Parent.Parent	
	local myTeam = NPC.AI:WaitForChild("Team")
	local HRP = NPC:WaitForChild("HumanoidRootPart")
	
	
	local Target = NPC.AI:WaitForChild("Target")	
	local NPCs = workspace.Game.npcStorage
	
	
	local closestTarget = nil
	local targetsDistance = nil
	
	
	for _, NPC in pairs(NPCs:GetChildren()) do
		local eHRP = NPC:FindFirstChild("HumanoidRootPart")
		
		for _, child in pairs(NPC:GetChildren()) do					
			if child.Name == "AI" and child:FindFirstChild("Team").Value ~= myTeam.Value then --and (HRP.Position - eHRP.Position).magnitude < targetsDistance then
				local Team = child:FindFirstChild("Team")				
				
				closestTarget = NPC.Name
				targetsDistance = (HRP.Position - eHRP.Position).magnitude
				Target.Value = closestTarget						
				
			end
		end 
	end
end)

-Movement

local atkDistance = 3.5
local Tower = workspace.Game:FindFirstChild("RedTower")



--/// myNPC
local NPC = script.Parent.Parent
	local HRP = NPC:WaitForChild("HumanoidRootPart")
	local Hum = NPC:WaitForChild("Humanoid")

	local AI = NPC:WaitForChild("AI")
	local Team = AI:WaitForChild("Team")
	local Target = AI:WaitForChild("Target")	
	local moveToTower = AI:WaitForChild("moveToTower")	
	
	
--/// Event
local Event = script.Parent:WaitForChild("Trigger")
local findTarget = script.Parent:WaitForChild("findTarget")



Hum:MoveTo(Tower.Target.Position)
Target.Changed:Connect(function()
	--/// Enemy  NPC	
	local eNPC = workspace.Game.npcStorage:FindFirstChild(Target.Value)
		local eHRP = eNPC:FindFirstChild("HumanoidRootPart")	
	
	
	while true do wait(.1)
		if Target.Value == "" or eNPC:FindFirstChild("Humanoid").Health <= 0 then
			Target.Value = ""
			
			Hum:MoveTo(Tower.Target.Position)		
		
		--/// Attack or Move
		elseif (HRP.Position - eHRP.Position).magnitude <atkDistance then -- Checks if the distance between the enemy and NPC is less than 5 studs
			Event:FireServer()
		elseif Target.Value ~= nil then 
			Hum:MoveTo(eHRP.Position)
			--Hum.MoveToFinished:Wait() -- May improve srv performance but will make NPCs appear derpy as they may walk to far than suppose to
		end	
	end
end)

If you need to know any more information please let me know. And thankyou if you can explain how to use Module Scripts.

3 comments

0

Modules are like bindable functions. They can be passed using seperate scripts. To get a module script's and all of it's function, use "require(moduleplacing)". I'd show you mine but i'm new to scripting helpers and idk how to post scripts. Anyways, you give the module a name, "local Object = {}" then a function inside like "function Object.NAME()" then call it from another script.

0

You call it using the variable name that requires the module, like "Object = require(module)". Then, to call a function, do "Object.FunctionName(arguments)". Modules are very simple.

0

You really shouldn't have the client telling the server when npcStorage has stuff.

3 answers

✓ Accepted answer

###ModuleScript objects have default code already pasted, similar to Scripts and LocalScripts how they have print("Hello world") as the default code. This is the default code for modules:

local module = {}

return module

###Modules act like a function in a way. It must be called. Modules are basically tables, which will be returned, so we can index objects inside the table. Take this for example:

local module = {} -- You can name them anything, I just used the default name

function module.functionInModule() 
    print("I’m a function inside a module!")
end



return module -- required to work

###Functions inside modules MUST be global, cannot be local. You make it local by adding the keyword local before function. local function ###From your server/local script:

local module = require(game.Workspace.ModuleScript) -- i put in workspace

module.functionInModule() -- prints code 

###A cool thing to note about ModuleScripts is that they take on the behaviour of a Script or a LocalScript, depending on what you use. For example, if you used LocalPlayer in a module, you MUST require it from a LocalScript else the script will error and LocalPlayer will return nil, since LocalPlayer is client-side only.

Hello there! I am excited that you are giving ModuleScripts a chance for the sake of organization.

Although there are good practices and bad practices many people use modules to a different extent, because as is with a normal script, it heavily depends on your coding style and how much code you can handle in your regular scripts before you consider it unorganized.

With that in mind, first I will teach you the basic functionality of a module, and then I will show you how I use modules.

--

A module is like any other script, the code in it runs from top to bottom, and it only runs once.

If you have a loop inside it, that loop will obviously still loop, but a ModuleScript is not a function that you call.

The primary differences are as follows:

  • it does not run until the first time it is required
  • at the very end of the ModuleScript, you must return exactly one value

Module Script

print("ModuleScript is running")

return true

"Normal" (Server) Script

local testing = require(script.Testing) --> true

if testing then
	print("TEST MODE ACTIVATED!")
else
	print("THIS IS NOT A DRILL!")
end

In this example, all the module does is print that it is running, and then returns true. In this case, I am letting the script that is requiring it know that the game is currently in "test mode", whatever that means.

With that being said, you can require the same module in multiple scripts, and then they will all know that the game is in test mode. If you want to change the test mode, you just have to change it in the module, and not have to worry about each individual script.

Module Script

local quickmaths = {}

quickmaths.Add = function(a, b)
	if a and b then
		local res = a + b
		print(("%d + %d = %d"):format(a, b, res))
		return res
	else
		print("2 + 2 = 4")
		return 2 + 2
	end
end

quickmaths.Subtract = function(a, b)
	if a and b then
		local res = a - b
		print(("%d - %d = %d"):format(a, b, res))
		return res
	else
		print("4 - 1 = 3")
		print("QUICKMATHS")
		return 4 - 1
	end
end

return quickmaths

"Normal" (Server) Script

local quickmaths = require(script.quickmaths)

local seven = quickmaths.Add(5, 2) 		
local four = quickmaths.Subtract(seven, 3)

quickmaths.Add()
quickmaths.Subtract()

Here, you should be able to see the difference. I've moved a table of custom math methods into a module, thus organizing my code.

ModuleScripts are extensions of normal scripts. You can throw the clutter in them. Functions, tables, math, libraries. What does that leave your normal script looking like?

If you've done it right, at the end of it all, it is short, readable, and easy to understand the flow of the game.

--

Final notes:

  • The return value of a module script is cached.
  • Modules run in the environment you require them in. If you put a module in ReplicatedStorage, it is copied to both the Client and the Server, however editing it will be editing their separate copies and is not a means to send messages without remotes.

Contact me on Discord if you have any questions, or would like more information about modules that I have not provided in this answer. My Discord tag is amanda#9999.

local Object = {}

--------------- Function.Waves(BrickColor.new("Cyan"), Torso, 1, 0.5)

local Effects = game:GetService("ServerStorage"):WaitForChild("Skills")
local Meshes = Effects:WaitForChild("Assets")
local Parts = workspace:WaitForChild("PartStorage")
local rep = game:GetService("ReplicatedStorage")
local Assets = rep:WaitForChild("Assets")
local auras = rep:WaitForChild("Aura")
local auras2 = rep:WaitForChild("WideAuras")

----------- DUST 2.0
function Object.Dust(root, duration)
	local dust = Assets.Dust:Clone()
	dust.Parent = root
	wait(duration)
	dust.Rate = 0
	game.Debris:AddItem(dust, 5)
end

return Object

------ script
local object = require(module) ----- define everything in the script you call the module functions

local plr = plr
local char = character
local root = char.HumanoidRootPart

object.Dust(root, 5)

This discussion is preserved as it was. New answers, comments, and votes are closed.