Wiki / Scripting Games

Gameplay

14 min read

Scripting Games

Learn Voxly Luau basics, events, services, object properties, attributes, and simple gameplay patterns.

Voxly uses Luau

Voxly scripts are written in Luau, a Lua-based scripting language for readable gameplay logic.

Scripts make worlds interactive. They can respond when players join, touch objects, trigger events, collect items, complete objectives, or interact with world systems.

Voxly scripting is event-driven. Write setup code directly, then connect functions to events when you want something to happen.

Voxly may add optional lifecycle helpers later, but current creator examples should use direct setup code and event connections.

voxly.log("Hello from Voxly Luau")

Script types

  • Script runs on the server and is used for authoritative gameplay rules.
  • LocalScript runs for a player and is used for player-side input, camera, and interface behavior.
  • ModuleScript stores shared Luau code that other scripts can require and reuse.
  • ServerScriptService is the safe place for server-only scripts.
  • ReplicatedStorage is the place for shared objects, ModuleScripts, RemoteEvents, and RemoteFunctions.

Core built-ins

  • game:GetService("ServiceName") gets a built-in service such as Players, RunService, ReplicatedStorage, ServerScriptService, or CollectionService.
  • workspace contains the visible world objects players interact with.
  • Instance.new("ClassName") creates an object such as Part, Script, LocalScript, ModuleScript, RemoteEvent, or RemoteFunction.
  • object.Parent places an object into the world or into a service.
  • object.Name gives an object a readable name for finding and debugging.
  • voxly.log(message) prints a message to the Voxly script log while testing.

Create and place a part

Use Instance.new to create an object, set its properties, then parent it into workspace so it appears in the world.

local platform = Instance.new("Part")
platform.Name = "StarterPlatform"
platform.Position = { x = 0, y = 2, z = 0 }
platform.Size = { x = 12, y = 1, z = 12 }
platform.Anchored = true
platform.Parent = workspace

voxly.log("Platform created")

Find objects

Name important objects clearly so scripts can find them later. Use FindFirstChild when an object might not exist yet.

local door = workspace:FindFirstChild("CastleDoor")

if door then
    voxly.log("Found " .. door.Name)
else
    voxly.log("CastleDoor is missing")
end

Events and Connect

Events let scripts respond to things that happen. Connect attaches a function to an event. The function runs when the event fires.

local checkpoint = workspace:FindFirstChild("Checkpoint")

if checkpoint then
    checkpoint.Touched:Connect(function(hit)
        voxly.log("Checkpoint touched by " .. hit.Name)
    end)
end

Attributes

Attributes are custom values stored on objects. They are useful for gameplay settings like damage, team name, checkpoint number, or whether a door is locked.

local hazard = Instance.new("Part")
hazard.Name = "LavaBlock"
hazard.Parent = workspace
hazard:SetAttribute("Damage", 25)

hazard:GetAttributeChangedSignal("Damage"):Connect(function()
    voxly.log("Damage is now " .. tostring(hazard:GetAttribute("Damage")))
end)

hazard:SetAttribute("Damage", 40)

Players service

The Players service lets server scripts respond when players join or leave the world.

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
    voxly.log(player.Name .. " joined")
end)

CollectionService tags

Tags let one script manage many objects. For example, tag every lava part as DamageZone, then connect behavior to all matching parts.

local CollectionService = game:GetService("CollectionService")

local function attachDamage(zone)
    zone.Touched:Connect(function(hit)
        local damage = zone:GetAttribute("Damage") or 10
        voxly.log(hit.Name .. " took " .. tostring(damage) .. " damage")
    end)
end

CollectionService:GetInstanceAddedSignal("DamageZone"):Connect(attachDamage)

local lava = Instance.new("Part")
lava.Name = "Lava"
lava.Parent = workspace
lava:SetAttribute("Damage", 25)
CollectionService:AddTag(lava, "DamageZone")

RunService timing

RunService is for frame-based logic. Use Heartbeat when behavior should run repeatedly while the world is active.

local RunService = game:GetService("RunService")

RunService.Heartbeat:Connect(function(dt)
    -- Runs after the script update step.
end)

RemoteEvents

RemoteEvents send messages between LocalScripts and server Scripts. Use them when a player action needs to request a server-side gameplay change.

-- Server Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local remote = Instance.new("RemoteEvent")
remote.Name = "CoinPickup"
remote.Parent = ReplicatedStorage

remote.OnServerEvent:Connect(function(player, coinName)
    voxly.log(player.Name .. " picked up " .. coinName)
end)

RemoteFunctions

RemoteFunctions are for request-and-response flows. Use them sparingly because the caller waits for a result.

-- Server Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local remote = Instance.new("RemoteFunction")
remote.Name = "GetRoundInfo"
remote.Parent = ReplicatedStorage

remote.OnServerInvoke = function(player)
    return "Lobby", 30
end

Safety rules

  • Use Script for world-changing rules and LocalScript for client-side presentation.
  • Do not trust LocalScript for rewards, currency, trading, or important progression.
  • Use RemoteEvents to ask the server for a change; let the server decide if the change is allowed.
  • Prefer events over constantly checking everything every frame.
  • Wrap risky calls with pcall when failure is expected and recoverable.
  • Keep scripts small, named clearly, and focused on one system.