Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

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

Asked by 5 years ago

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.

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. Delude_d 112 — 5y
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. Delude_d 112 — 5y
0
You really shouldn't have the client telling the server when npcStorage has stuff. hiimgoodpack 2009 — 5y

3 answers

Log in to vote
1
Answered by 5 years ago
Edited 5 years ago

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.

Ad
Log in to vote
2
Answered by
amanda 1059 Moderation Voter
5 years ago

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.

Log in to vote
0
Answered by
Delude_d 112
5 years ago
Edited 5 years ago
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)

Answer this question