Very modular approach of scripting-how?

Hello, recently I was watching janisjanis01’s video where he made a viral singing game. While I was watching the video, I realized-he uses a LOT of module scripts-each with their own function. This got me thinking, I have to modulize my games more. For context, I have around 3 years of on/off experience. I do work in modules, but not that much. I can handle OOP and just normal modules. In the video he has many folders-like services, config, etc. Each containing modules. I know some modules handled stuff like visuals and allat but what I’m really trying to figure out is how can I learn this method of approaching scripting-because usually I script at face value. Sure I’ll use module scripts, but a lot of stuff is just handled in server and client scripts-with a high usage of remote events. Is there any certain thing I need to learn to achieve this approach? What would be the benefits? And is there any TUTORIAL per say on this.

Any help is appreciated :cowboy_hat_face:

5 Likes

I think of modules as libraries that you’d want to use throughout your code, like if one script uses that same function, it is best to create a module so it wouldn’t have to be repeated several times. Modules are also 1 per server, meaning

there exist one version of the module on the server and another one in the client

2 Likes

When you’re programming, you break down tasks into functions for the most part. Or you could add generic scripts to them. One step further is using modules. Even beyond that, from a library perspective, many modules use command setups. All of this uses a defined set of whatever you’re keeping track of or need overall. I think that last line is the full crossover.

2 Likes

Have you ever heard of computational thinking? It basically involves fundamental programming skills to help you write better code and problem solve. One of the elements of computational thinking is called decomposition. It’s basically where you take a big problem and split it down into its components - each being a smaller sub-problem You can then break those down into sub-problems, and keep going basically as much as you want. You then write a solution to each of these sub-problems, and before you know it, those solutions piece together to make one big solution for the original problem, keeping the whole structure modular and self-contained. This also brings the benefit of independence - if you want to change one bit, you only need to edit that component, and then you don’t have to redo everything else to fit your one change.

Apply that here. Take a problem, split it down. For each sub-problem, think “is it worth creating a module for this? (does this need breaking down further? can I abstract it into one function, or does it need more?”

If it needs a module, dedicate a module to it. If it only needs a function, only give it a function. If it’s still too big, break it down further and repeat.

Take an example of a movement system.

Movement system can be broken down into:

  • Controls
  • Movement states

Movement states:

  • Crouching
  • Running
  • Idle
  • Walking
  • Jumping
  • Sprinting
  • Sliding

For each movement state:

  • What does it require?
  • How do I apply it?

and from there, you should just see it blend in to other programming concepts. For example, for the movement states, you might make an abstract class for states, then have each state implement its own methods like Apply().

This is definitely a concept you should chase more. It’ll make your code way more readable and maintainable. It’s great practice.

8 Likes

Taking an example from something I’m working on, I have a GuiManager module that manages gui under StarterGui and a child script that starts it. Every ScreenGui in my game has a ModuleScript called Config as a child of it that tells the GuiManager how to treat it. This is just one way modules can be used everywhere.

For reference, here’s an example Config:

return {
    enabledAtStart = false,
    transitionIn = function() ... end,
    transitionOut = function() ... end,
}

Very simple, but pretty useful.

2 Likes

I personally find this way of handling GUI amazing, and I personally store the settings and behaviour of each GUI inside the Shared Module "GUIHandler", in a Components folder, with the name of the GUI or abbreviated. Although, I do have a rule of thumb of not using it for games that require little to no GUI, and that aren’t too complex.

Example structure:

ReplicatedStorage > GUIHandler (Folder) > MainHandler (ModuleScript) > Components (Folder) > Shop (ModuleScript)

Then, in the Shop component:

local SETTINGS = 
{
-- List of Shop's properties
}


-- Functions/Behaviour

Then, in the MainHandler, all I would do is make a pairs loop to require all Components, check if it has a _init() function to call it, and then setup events so the client can listen

6 Likes

This is sort of what I do, I am going to take the approach you and the others gave me and try and see what I can do. Will definitely be practicing this, I want to take my code to the next level :smiley:

1 Like

Also wanted to add.. this is optional. Yes, it works well, but keeping track of your scripts can too. Many will say it’s the only way to go, but it’s just one other and optional way to go. You should learn it, you should use it, but you don’t have to fully commit to it unless you want to. I would sure learn without it and then add that to what you know. So you truly understand how it’s working.

Modular programming doesn’t necessarily mean using modules.
“modular” refers to breaking a program into smaller, independent, reusable parts.
aka: Generic scripting.

What I’m trying to say is learn how to program modularly first, then add using modules to that.

Here are some resources: Concept to creation..

Modular programming: beyond the spaghetti mess
Writing Modular Code

Single Script Architecture and Modular Programming

How to Use Module Scripts – Community Tutorials
ModuleScripts – Roblox Scripting Tutorial
How to work on Modular GUIs

If you want to see a full-blown full usage of this technique all the way to a modular package, take a look at the Studio Racing Template.

2 Likes

what you can do is for remote events u can create them via code. you can either make your own networker wrapper or u can use a networker library from online for Server and Client communication. here’s a few. i use suphi’s packet networker because its very user friendly.

as for the actual practice of modularizing your whole game, a common practice is called Single Script Architecture (SSA) where you have one client script, one server script. inside each of those scripts you will have your module scripts which will contain an :Init() function.

i handle networking in just 2 module scripts. one called ServerNetwork and one called ClientNetwork. with that way in mind, i won’t have to require my Networking modules in 100+ scripts but only 2! its a game changer :double_exclamation_mark:

i also use libraries which are basically tools or frameworks like Roact or Fusion which i store in ReplicatedFirst along with my client stuff.

as for scripting complex systems, metatables and OOP is recommended and i’m still finding my feet for system organization and game organization so bare w me. :face_exhaling:

don’t neglect the templates in studio, i use the Laser Tag template to understand how they structured their systems & instances.

i would also recommend that you follow the Single Responsibility Principle (SRP) for your systems which means each module does one thing kinda. it’s super conventional!

u should learn about wrappers too. wrappers are just a shorter way for doing stuff. take a look at my SoundPlayer for example. with this, i can play a sound with 1 line of code rather than 20-40. :slight_smile:

3 Likes