Example - ModuleScript as DB

This section provides a beginner-friendly example of using a ModuleScript in Roblox as a simple database for storing and managing game data, demonstrating how to set up, populate, and interact with data in a Roblox game.

  • Roda Logo Create a new experience in Roblox Studio
  • Roda Logo Create a ModuleScript in ServerStorage and name it "Items"
  • Roda Logo Create a new Project in Roda
  • Roda Logo Create a new Data File Configuration
  • Roda Logo Pick the Items ModuleScript as the Data File
  • Roda Logo Set the Table Type to Dict
  • Roda Logo Add properties to the Data File Settings
    • Roda Logo Click "Add From Code", paste the following Lua snippet, and click "Parse":
      name = "name"
      value = 0
      image = "image"
      
    • Roda Logo Set the UI Element of image property to "T.Box with Image Selection"
  • Roda Logo Upload some images (if you don’t have any, find free images on websites like Craftpix)
  • Roda Logo Insert the images and move them into a Folder
  • Roda Logo Set this Folder as Image Pool in the Data File Settings
  • Roda Logo Add some items on the Editor Page
  • Roda Logo Create the scripts, run the game, stop, edit items, run again...

    ServerScriptService.Script
    -- Load the items data from a ModuleScript located in ServerStorage
    local items = require(game.ServerStorage.Items)
    
    -- Create a RemoteEvent for clients to request the items table from the server
    local GetItems = Instance.new("RemoteEvent") -- Creates a new RemoteEvent object
    GetItems.Name = "GetItems" -- Names it "GetItems" for identification
    GetItems.Parent = game.ReplicatedStorage -- Places it in ReplicatedStorage for server-client communication
    
    -- Create a new RemoteEvent for notifying clients when an item is collected
    local ItemCollected = Instance.new("RemoteEvent") -- Creates another RemoteEvent object
    ItemCollected.Name = "ItemCollected" -- Names it "ItemCollected" for item collection events
    ItemCollected.Parent = game.ReplicatedStorage -- Places it in ReplicatedStorage for server-client communication
    
    -- Handle client requests for the items table
    GetItems.OnServerEvent:Connect(function(player) -- Listens for when a client fires this event
        GetItems:FireClient(player, items) -- Sends the items table back to the requesting client
    end)
    
    -- System to spawn spheres with GUIs and handle item collection
    local spawnAreaSize = 50 -- Defines the size of the 50x50 stud area where spheres spawn
    local spawnPoint = game.Workspace:WaitForChild("SpawnLocation").Position or Vector3.new(0, 0, 0) -- Gets the position of SpawnLocation or defaults to (0, 0, 0) if not found
    local maxSpheres = 200 -- Sets the maximum number of spheres allowed in the game at once
    local sphereCount = 0 -- Tracks the current number of active spheres
    
    -- List of colors for the spheres
    local colors = {
        Color3.fromRGB(255, 99, 51), -- Bright red-orange
        Color3.fromRGB(255, 105, 180), -- Hot pink
        Color3.fromRGB(144, 238, 144), -- Light green
        Color3.fromRGB(230, 69, 217), -- Bright purple
        Color3.fromRGB(255, 165, 0), -- Orange
        Color3.fromRGB(255, 255, 62), -- Bright yellow
        Color3.fromRGB(30, 51, 240), -- Deep blue
        Color3.fromRGB(88, 255, 249), -- Cyan
    }
    
    -- Create a table of item names (keys) for random selection from the items dictionary
    local itemNames = {} -- Initializes an empty table to store item names
    for name, _ in pairs(items) do -- Loops through the items dictionary to get all keys (item names)
        table.insert(itemNames, name) -- Adds each item name to the itemNames table
    end
    
    -- Function to spawn a sphere with an invisible outer sphere for touch detection
    local function spawnSphere()
        if sphereCount >= maxSpheres then
            return
        end -- Stops spawning if the maximum number of spheres is reached
    
        local randomItemName = itemNames[math.random(1, #itemNames)] -- Randomly selects an item name from the list
        local item = items[randomItemName] or error("Item not found: " .. randomItemName) -- Gets the item data or throws an error if not found
    
        local shapes = { -- List of possible shapes for the sphere
            Enum.PartType.Ball,
            Enum.PartType.Block,
            Enum.PartType.Cylinder,
            Enum.PartType.Wedge,
            Enum.PartType.CornerWedge,
        }
        local randomShape = shapes[math.random(1, #shapes)] -- Randomly picks a shape from the list
        local randomColor = colors[math.random(1, #colors)] -- Randomly picks a color from the colors list
    
        -- Create the visible inner sphere (small, colored)
        local innerSphere = Instance.new("Part") -- Creates a new Part for the visible sphere
        innerSphere.Shape = randomShape -- Sets the shape to a random type (e.g., Ball, Block)
        innerSphere.Size = Vector3.new(1, 1, 1) -- Sets a small size for the visible sphere
        innerSphere.Position = Vector3.new( -- Sets a random position within the spawn area
            spawnPoint.X + math.random(-spawnAreaSize / 2, spawnAreaSize / 2), -- Random X position
            spawnPoint.Y + math.random(5, 25), -- Random Y position (5 to 25 studs above ground) for dropping
            spawnPoint.Z + math.random(-spawnAreaSize / 2, spawnAreaSize / 2) -- Random Z position
        )
        innerSphere.Anchored = false -- Allows the sphere to fall due to physics
        innerSphere.BrickColor = BrickColor.new(randomColor) -- Applies a random color
        innerSphere.Parent = game.Workspace -- Places the sphere in the Workspace for visibility
    
        -- Create an invisible outer sphere for touch detection (larger, transparent)
        local outerSphere = Instance.new("Part") -- Creates a new Part for the invisible touch detection
        outerSphere.Shape = Enum.PartType.Ball -- Uses a Ball shape for consistent touch detection
        outerSphere.Size = Vector3.new(5, 5, 5) -- Sets a larger size for the touch area
        outerSphere.Position = innerSphere.Position -- Matches the position of the inner sphere
        outerSphere.Anchored = false -- Allows falling with the inner sphere
        outerSphere.Transparency = 1 -- Makes it fully invisible
        outerSphere.CanCollide = false -- Prevents physical collisions, only allowing touch detection
        outerSphere.Parent = game.Workspace -- Places it in the Workspace
    
        -- Weld the inner and outer spheres together
        local weld = Instance.new("WeldConstraint") -- Creates a WeldConstraint to connect the spheres
        weld.Part0 = innerSphere -- Sets the inner sphere as the base part
        weld.Part1 = outerSphere -- Sets the outer sphere to follow the inner sphere
        weld.Parent = innerSphere -- Parents the weld to the inner sphere for management
    
        -- Add item name as an attribute to the outer sphere (for touch event)
        outerSphere:SetAttribute("ItemId", item.name) -- Stores the item name as an attribute for identification
    
        -- Create a BillboardGui for the item display (attached to the inner sphere)
        local billboardGui = Instance.new("BillboardGui") -- Creates a GUI that displays above the sphere
        billboardGui.Size = UDim2.new(3, 0, 3, 0) -- Sets the size of the GUI (3x3 studs)
        billboardGui.StudsOffset = Vector3.new(0, 3, 0) -- Positions the GUI 3 studs above the inner sphere
        billboardGui.Adornee = innerSphere -- Attaches the GUI to the inner sphere
        billboardGui.Parent = innerSphere -- Parents the GUI to the inner sphere
    
        -- Add ImageLabel for the item image
        local imageLabel = Instance.new("ImageLabel") -- Creates an image label for the item’s image
        imageLabel.Size = UDim2.new(1, 0, 0.7, 0)
        imageLabel.Position = UDim2.new(0, 0, 0, 0) -- Positions it at the top-left of the GUI
        imageLabel.Image = item.image -- Sets the image from the item data
        imageLabel.BackgroundTransparency = 1 -- Makes the background fully transparent
        imageLabel.ScaleType = Enum.ScaleType.Fit -- Ensures the image fits within the label while maintaining aspect ratio
        imageLabel.Parent = billboardGui -- Parents it to the BillboardGui
    
        -- Add TextLabel for the value
        local valueLabel = Instance.new("TextLabel") -- Creates a text label for the item’s value
        valueLabel.Size = UDim2.new(1, 0, 0.3, 0) -- Sets the size to 30% of the GUI height
        valueLabel.Position = UDim2.new(0, 0, 0.7, 0) -- Positions it below the image (70% down)
        valueLabel.TextScaled = true -- Scales the text to fit the label
        valueLabel.Text = "$ " .. tostring(item.value) -- Displays the item’s value with a dollar sign
        valueLabel.TextColor3 = Color3.new(0.666667, 1, 0) -- Sets the text color to green
        valueLabel.Font = Enum.Font.Cartoon -- Sets the font to a cartoon style for a playful look
        valueLabel.BackgroundTransparency = 1 -- Makes the background fully transparent
        valueLabel.Parent = billboardGui -- Parents it to the BillboardGui
    
        -- Handle outer sphere touch to fire event to client and destroy both spheres
        outerSphere.Touched:Connect(function(hit) -- Detects when the outer sphere is touched
            local player = game.Players:GetPlayerFromCharacter(hit.Parent) -- Gets the player who touched the sphere
            if player and outerSphere and outerSphere.Parent then -- Checks if the player and outer sphere exist
                outerSphere.CanTouch = false -- Prevents the sphere from being touched multiple times
                local itemId = outerSphere:GetAttribute("ItemId") -- Retrieves the item name from the attribute
                if itemId then -- Ensures an item ID exists
                    -- Fire the ItemCollected event to the player with the item data
                    ItemCollected:FireClient(player, items[itemId]) -- Sends the item data to the client
    
                    -- Destroy both spheres immediately
                    if innerSphere and innerSphere.Parent then -- Checks if the inner sphere exists
                        innerSphere:Destroy() -- Removes the visible inner sphere
                    end
                    if outerSphere and outerSphere.Parent then -- Checks if the outer sphere exists
                        outerSphere:Destroy() -- Removes the invisible outer sphere
                        sphereCount = sphereCount - 1 -- Decrements the sphere count
                    end
                end
            end
        end)
    
        sphereCount = sphereCount + 1 -- Increments the sphere count for each new sphere
    end
    
    -- Spawn spheres continuously (every 0.25 seconds) up to maxSpheres
    spawn(function()
        while true do -- Runs an infinite loop to keep spawning spheres
            if sphereCount < maxSpheres then -- Checks if we’re below the maximum number of spheres
                spawnSphere() -- Calls the function to spawn a new sphere
            end
            wait(0.25) -- Pauses for 0.25 seconds before spawning the next sphere
        end
    end)
    
    StarterPlayer.StarterPlayerScripts.LocalScript
    -- Get the local player (the player running this script on their client)
    local player = game.Players.LocalPlayer
    
    -- Create a ScreenGui to hold the inventory UI
    local gui = Instance.new("ScreenGui") -- Creates a new ScreenGui object
    gui.Name = "InventoryGui" -- Names it "InventoryGui" for identification
    gui.Parent = player.PlayerGui -- Places it in the player's PlayerGui for client-side UI
    
    -- Create a main frame for the inventory GUI
    local frame = Instance.new("Frame") -- Creates a new Frame object for the GUI container
    frame.Name = "GuiFrame" -- Names it "GuiFrame" for identification
    frame.Size = UDim2.new(0.25, 0, 0.75, 0) -- Sets the size to 25% of the screen width and 75% of the screen height
    frame.Position = UDim2.new(0, 0, 0.25, 0) -- Positions it at the top-left corner (0 from left, 25% from top)
    frame.BackgroundTransparency = 1 -- Makes the background fully transparent
    frame.Parent = gui -- Parents it to the ScreenGui
    
    -- Create a UIListLayout to organize elements vertically in the frame
    local layout = Instance.new("UIListLayout") -- Creates a new UIListLayout for layout management
    layout.FillDirection = Enum.FillDirection.Vertical -- Arranges items vertically
    layout.HorizontalAlignment = Enum.HorizontalAlignment.Center -- Centers items horizontally
    layout.VerticalAlignment = Enum.VerticalAlignment.Center -- Centers items vertically
    layout.SortOrder = Enum.SortOrder.LayoutOrder -- Sorts items based on their LayoutOrder
    layout.Parent = frame -- Parents it to the frame
    
    -- Create cash label at the top of the frame
    local cashLabel = Instance.new("TextLabel") -- Creates a new TextLabel for displaying cash
    cashLabel.Name = "CashLabel" -- Names it "CashLabel" for identification
    cashLabel.Size = UDim2.new(1, 0, 0.2, 0) -- Sets the size to 100% of the frame width and 20% of its height
    cashLabel.BackgroundTransparency = 1 -- Makes the background fully transparent
    cashLabel.Text = "Cash: $0" -- Sets the initial text to show zero cash
    cashLabel.TextColor3 = Color3.new(0.666667, 1, 0) -- Sets the text color to green
    cashLabel.Font = Enum.Font.Cartoon -- Sets the Font
    cashLabel.TextScaled = true -- Scales the text to fit the label size
    cashLabel.LayoutOrder = 1 -- Sets the order for layout
    cashLabel.Parent = frame -- Parents it to the frame
    
    -- Create the main inventory frame (scrollable) inside the GUI frame
    local scrollingFrame = Instance.new("ScrollingFrame") -- Creates a new ScrollingFrame for scrollable items
    scrollingFrame.Name = "InventoryFrame" -- Names it "InventoryFrame" for identification
    scrollingFrame.Size = UDim2.new(1, 0, 0.8, 0) -- Sets the size to 100% of the frame width and 80% of its height
    scrollingFrame.BackgroundColor3 = Color3.new(0, 0, 0) -- Sets the background color to black
    scrollingFrame.BackgroundTransparency = 0.5 -- Makes the background semi-transparent (50% opacity)
    scrollingFrame.ScrollBarThickness = 8 -- Sets the thickness of the scrollbar
    scrollingFrame.CanvasSize = UDim2.new(0, 0, 0, 0) -- Initial canvas size for scrolling (auto-adjusts)
    scrollingFrame.AutomaticCanvasSize = Enum.AutomaticSize.Y -- Automatically adjusts the canvas height based on content
    scrollingFrame.LayoutOrder = 2 -- Sets the order for layout
    scrollingFrame.Parent = frame -- Parents it to the frame
    
    -- Create a layout for scrollable items within the scrolling frame
    local itemLayout = Instance.new("UIListLayout") -- Creates a new UIListLayout for organizing items
    itemLayout.Padding = UDim.new(0, 5) -- Adds 5 pixels of padding between items
    itemLayout.Parent = scrollingFrame -- Parents it to the scrolling frame
    
    -- Fetch items from the server
    local GetItems = game.ReplicatedStorage:WaitForChild("GetItems") -- Gets the GetItems RemoteEvent from ReplicatedStorage
    local allItems = nil -- Initializes a variable to store the items table
    
    GetItems:FireServer() -- Sends a request to the server to get the items
    GetItems.OnClientEvent:Connect(function(itemsData) -- Listens for the response from the server
        allItems = itemsData -- Stores the received items table for later use
    end)
    
    local collectSounds = {
        "rbxassetid://6586979979",
        --"rbxassetid://.."
    }
    
    -- Create and store sound instances once on the client for item collection
    local sounds = {} -- Initializes an empty table to store sound instances
    for _, soundId in pairs(collectSounds) do -- Loops through the list of sound IDs
        local sound = Instance.new("Sound") -- Creates a new Sound object
        sound.SoundId = soundId -- Sets the sound ID from the list
        sound.Parent = player.PlayerGui -- Parents the sound to PlayerGui for client-side playback
        sound.Looped = false -- Ensures the sound doesn’t loop
        sound.Volume = 0.5 -- Sets the volume (optional, default is 1)
        table.insert(sounds, sound) -- Adds the sound to the sounds table
    end
    
    -- Track inventory and cash for the player
    local inventory = {} -- Initializes an empty table to track collected items
    local totalCash = 0 -- Initializes the total cash to zero
    
    -- Handle item collection from server event
    local ItemCollected = game.ReplicatedStorage:WaitForChild("ItemCollected") -- Gets the ItemCollected RemoteEvent from ReplicatedStorage
    ItemCollected.OnClientEvent:Connect(function(item) -- Listens for when an item is collected on the client
        if item then -- Ensures an item was received
            local randomSound = sounds[math.random(1, #sounds)] -- Randomly selects a sound from the sounds table
            randomSound:Play() -- Plays the selected sound for item collection
    
            -- Add item to inventory (create GUI elements)
            local itemFrame = Instance.new("Frame") -- Creates a new Frame for the item in the inventory
            itemFrame.Size = UDim2.new(1, 0, 0.1, 0) -- Sets the size to 100% of the scrolling frame width and 10% of its height
            itemFrame.BackgroundColor3 = Color3.new(0.121569, 0.121569, 0.121569) -- Sets the background color to dark gray
            itemFrame.BackgroundTransparency = 0.6 -- Makes the background semi-transparent (60% opacity)
            itemFrame.Parent = scrollingFrame -- Parents it to the scrolling frame for display
    
            local image = Instance.new("ImageLabel") -- Creates an ImageLabel for the item’s image
            image.Size = UDim2.new(0.3, 0, 1, 0) -- Sets the size to 30% of the item frame width and 100% of its height
            image.Position = UDim2.new(0, 0, 0, 0) -- Positions it at the top-left of the item frame
            image.Image = item.image -- Sets the image from the item data
            image.BackgroundTransparency = 1 -- Makes the background fully transparent
            image.ScaleType = Enum.ScaleType.Fit -- Ensures the image fits within the label while maintaining aspect ratio
            image.Parent = itemFrame -- Parents it to the item frame
    
            local nameLabel = Instance.new("TextLabel") -- Creates a TextLabel for the item’s name
            nameLabel.Size = UDim2.new(0.7, 0, 1, 0) -- Sets the size to 70% of the item frame width, full height
            nameLabel.Position = UDim2.new(0.3, 0, 0, 0) -- Positions it to the right of the image (30% from left)
            nameLabel.Text = item.name -- Sets the text to the item’s name
            nameLabel.TextColor3 = Color3.new(1, 1, 1) -- Sets the text color to white
            nameLabel.BackgroundTransparency = 1 -- Makes the background fully transparent
            nameLabel.Font = Enum.Font.Cartoon -- Uses a cartoon-style font for a playful look
            nameLabel.TextScaled = true -- Scales the text to fit the label size
            nameLabel.Parent = itemFrame -- Parents it to the item frame
    
            -- Track the item in inventory by adding it to the list to prevent duplicates
            table.insert(inventory, item) -- Adds the item to the inventory table
            totalCash = totalCash + (item.value or 0) -- Adds the item’s value to the total cash (defaults to 0 if no value)
            cashLabel.Text = "Cash: $" .. totalCash -- Updates the cash label with the new total
        end
    end)