Overview
This document is an attempt to summarise important parts of the Roblox API from a Unity game developers perspective.
Note that this document is living and in progress so is incomplete and may contain errors.
Data Model
Objects
Every Object inherets from the Instance class.
3D Building Blocks
BasePart is the core class for pysically simulated 3D building blocks that render in the world. Various parts types exist such as Part, MeshPart, WedgePart etc..
Scripts
- Script – Exists on server, clients cannot access
- LocalScript – Exists on client cnanot be accessed by server
- ModuleScript – Re-usable script that you require() from server and client. Once a module has been loaded it is cached so future requires of that module will use the cached version.
Object organisation
- Workspace – Stores all objects that exist in the world
- Environment – Containers for lighting, SoundService etc..
- Replication – Containers for logic and content that replicates between server and client such as ReplicatedStorage and ReplicatedFirst
- Server – Containers for service side only ontent and logic
- Client – Containers for client side only ontent and logic
- Chat – Containers for ibjects that enable chat features such as TextChatService and VoiceChatService
Replication
Replication is the process of the server synchronising the state of your place with all connected clients. The Roblox engine automatically replicates data, physics, and chat messages between the server and client for many cases, but you can also specify certain objects to replicate by placing them in specific containers.
- ReplicatedFirst – Contains objects that you want to replicate to a client when they join the game. It contains objects that are essential to initialize a player, such as client side LocalScript objects and objects associated with these scripts. All content in this container is replicated from server to client just the once.
- ReplicatedStorage – Contains objects that are available to both the server and connected clients. Any changes that occur on the client persist but won’t be replicated to the server. The server can overwrite changes on the client to maintain consistency. This container is typically used for ModuleScript objects that need to be shared and accessed by both Script (server-side) and LocalScript (client-side) objects. In addition, you can use this container to replicate any objects that don’t need to exist in the 3D world until needed, such as a ParticleEmitter for cloning and parenting to all incoming character models.
Server
This data model defines dedicated containers for server side only objects that are never replicated to the client.
- ServerScriptService – Contains Script objects, ModuleScript objects that are required by server scripts, and other scripting-related objects that are only meant for server use. If your scripts require other, non-scripting objects, you must place them in ServerStorage. Scripts in this container are never replicated to clients, which allows secure, server-side logic.
- ServerStorage – Contains objects that are only meant for server use. You can use this container to store objects that you want to clone and parent to the workspace or other containers at runtime. For example, you can store large objects such as maps in this container until they are needed and move them into the workspace only when required This lets you decrease client network traffic on initial join.
When a game starts everything is copied to the client except these folders
Client
Client container services are meant for objects that are replicated to every connected client. This category of container replicate to every connected client and typically contain 3D objects and associated LocalScript objects. All objects you store in these containers are non-persistent across sessions and reset every time a client rejoins. You can put objects in these containers such as player GUIs, client-side scripts, and other objects that are only relevant to the client. When a client connects to a server, the Players container service listens for users joining your place and creates a Player object for every client. The server copies the objects from the client containers in the edit data model to the corresponding location in the runtime data model inside the Players object. The following table describes the original container it resides on in the container and the resulting container they are copied to on the client:
- StarterPack – Player.Backpack – Scripts that set up the player’s inventory and generally contain Tool objects but often contains local scripts as well.
- StarterGui – Player.PlayerGui – Scripts that can manage the player’s local GUI. When a player respawns, the contents of PlayerGui are emptied. The server copies the objects inside StarterGui into the PlayerGui.
- StarterPlayerScripts – Player.PlayerScripts – General purpose scripts for the client. For example, if you want to create special effects on the client when certain conditions are met, you can place a local script in this container to do that. The server cannot access this container.
- StarterCharacterScripts – Player.Character- Scripts that are copied to the client when they spawn. These scripts do not persist when the player respawns.
- ReplicatedFirst – The contents of this container are replicated to all clients (but not back to the server) first, before anything else.
Folders and Models
There are two primary methods for grouping objects in the data model: folders and models. Both are containers for objects, but they have different purposes.
- Folders are best for storing sections of an environment, such as the lobby or a combat arena.
- Models are used for sets of objects, such as a desk set that includes a chair, table, and a lamp. To organize more complex sets, nest models inside models.
Saving game state
The state of the game has to be saved so that it survives sessions / server restarts etc. There are two ways to save data on the server:
- DataStoreService – If the game state needs to persist across server shutdowns / updates and shares data across instances, Data containing the entire game state can be stored in a global key
- Server Storage – If the game world state only needs to be available while the server is running then it can be stored directly in server memory, so basically in a table in a server script
An example showing how to use the DataStoreService to store and retrieve game state:
local GameState = {
Version = 1,
Bricks = 0
}
function SaveGameState()
local success, error = pcall(function()
Version = 2;
GameStateStore:SetAsync("GameState", GameState)
end)
if not success then
warn(error)
end
end
function LoadGameState()
local success, gameState = pcall(function()
return GameStateStore:GetAsync("GameState")
end)
if success and gameState ~= nil then
print(gameState)
GameState = gameState
else
warn("Could not load game state")
end
end
Update
The main way we update objects in Unity is using the Update / FixedUpdate methods. This sae behaviour can be accomplished by connecting a function to the script objects heartbeat event, e.g.:
RunService.Heartbeat:Connect(function(Delta)
-- Do stuff in this script every frame
end)
Note that this function is called at the end of the frame after physics updates have taken place.
There are other update events that can also be tapped into including:
- RenderStepped – Called every frame, prior to the frame being rendered
- Stepped – Called every frame prior to the physics simulation
Prefabs
Whilst Roblox appears that it does not appear to support prefabs, it does allow you to define objects / models somewhere outside of the workspace and then Clone() it into the workspace.
local prefab = script.Parent.prefab1
local instance = prefab:Clone()
instance.Parent = workspace
Places
A Roblox game is called an experience, it is made up of individual scenes within called places. Each place contains all components for that portion of the experience, including specific environment, parts, meshes, scripts user interface and so on.
All experiences have a start place which is the default place a player goes when they run the experience. Once there the player can be teleported to other places using the TeleportService.
local Players = game:GetService("Players")
local TeleportService = game:GetService("TeleportService")
local TARGET_PLACE_ID = 1234 -- replace with your own place ID
local playerToTeleport = Players:GetPlayers()[1] -- get the first user in the experience
TeleportService:TeleportAsync(TARGET_PLACE_ID, {playerToTeleport}, teleportOptions)
Adding new places to an experience is done via the Assets Manager in Roblox Studio.
See https://create.roblox.com/docs/production/publishing/publishing-experiences-and-places for more info.
Global namespace
Roblox has a global namespace (well table) called _G that can be accessed across scripts (but not across clients or server)
Lua Overview
Everything a table
MyTable = {1, 2, 3, 4}
MyDic = {key1 = "data1", key2 = "data2"}
print(MyTable)
Functions are all like Unity coroutines
All functions basically wait until the preceding instruction is complete, so if you call an async function it will not continue execution of instructions in that function until the task has completed, for example, getting data from an external server.
Loops
for t = 1, 10 do
print(t)
end
for i,v in pairs(MyTable) do
print(i.." "..v)
end
for k,v in pairs(MyDic) do
print(k.." "..v)
end
while (true) do
print("loop");
task.wait(1)
end
Random numbers
local randomInt = math.random(1, 10)
randomInt += 1
print(randomInt)
Odd operators
-- Not equal
local var1 = 50
if (var1 ~= 10) then
print "No Equal"
end
-- logical operators and, or and not (yuk)
Functions
function Function1(var1, var2)
return 100
end
local function localFunc(...)
local allNumbers = {...}
print(allNumbers)
end
localFunc(1, 3, 5, 7, 9, 11)
Metatables
-- Metatables
local myTable2 = {1, 2, 3}
local metaTable = {
__add = function(table1, number)
local result = {}
for i,v in table1 do
result[i] = number + v
end
return result
end,
__index = function(table1, key)
print("key " .. key .. " not found")
return "N/a"
end,
}
metaTable. __call = function(table1, ...)
print("Called table with values")
print(...)
end
setmetatable(myTable2, metaTable)
print(myTable2 + 4)
print(myTable2[10])
myTable2(1, 2, 3, 4)
Coroutines
-- Coroutines
local thread = coroutine.create(function()
while true do
print("In a coroutine")
task.wait(1)
end
end)
continue.resume(thread)
Colon Operator
The colon operator is just a way of passing a hidden self to a function when calling it
local function MyClass:Speak(extra)
return self.speech .. extra
end
Modules
Module lets you pack code and data that can be shared across multiple scripts:
A module
local PickupManager = {}
local defaultMultiplier = 1.25
local rarityMultipliers = {
common = 10,
uncommon = 20,
rare = 50,
legendary = 100
}
-- Add the getPickupBonus function to the PickupManager module table
function PickupManager.getPickupBonus(rarity)
local bonus = rarityMultipliers[rarity] * defaultMultiplier
return bonus
end
return PickupManager
Using a module
-- Script in ReplicatedStorage
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Get value returned by ModuleScript
local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))
-- Call a ModuleScript function
local bonus = PickupManager.getPickupBonus("legendary")
print(bonus) --> 125
If we require() a ModuleScript from both sides of the client-server boundary, then the ModuleScript returns a unique reference for each side.
Object Orientation
A basic class using metatables
-- The class
local Enemy = {Name = "", Health = 0, Damage = 0, Speed = 0}
Enemy.__index = Enemy
-- Class functions
function Enemy:Attack()
print("The "..self.Name.." attacked with "..self.Damage.." damage!")
end
-- Constructor
function Enemy.new(name, health, damage, speed)
local self = setmetatable({}, Enemy)
self.Name = name
self.Health = health
self.Damage = damage
self.Speed = speed
return self
end
-- Creating an object
local goblin = Enemy.new("Goblin", 100, 50, 10)
goblin:Attack()
Example of inheritence
local Animal = { -- Superclass
-- Properties for all animals
Name = "Unknown",
Sound = "Silent",
}
Animal.__index = Animal
-- Function for all animals
function Animal:Speak()
print(self.Name .. " says " .. self.Sound)
end
local Cat = {} -- Subclass
Cat.__index = Cat
setmetatable(Cat, Animal) -- Cat class inherits properties/behavior from Animal superclass
Cat.Name = "Cat"
Cat.Sound = "Meow"
-- Function just for cats
function Cat:Sneak()
print(self.Name.." is sneaking around.")
end
local myCat = setmetatable({}, Cat)
myCat:Speak()
myCat:Sneak()
Script Reference
A script is also a table, its children can be accessed as follows:
script["myImage"] -- This accesses the myImage instane of the scripts children
Roblox Objects
Roblox has many different types of objects (called classes) that can be created in the editor and / or in script. There are too many to mention here so we will just cover a few common ones:
Player
A player object represents a client that is connected to the game. Players are added to the Players service when they join and removed when they disconnect.
The player object has a number of important properties:
- Name – The players username
- DisplayName – The DisplayName of the UserId associated with the Player
- UserId – The players unique user id
- Character – A Model that controlled by the player which contains a Humanod object, body parts, scripts and other objects
- CameraMode – Players camera mode
- GameplayPaused – Players client side paused state
- RespawnLocation – Location spawn point
- Many other properties…
Useful examples
-- Get list of players
local Players = game:GetService("Players")
-- Set up player added / removing events
Players.PlayerAdded:Connect(function(player)
end)
Players.PlayerRemoving:Connect(function(player)
end)
-- Get associated Humanoid (server side) - Need to make sure that the character has loaded using CharacterAdded event
local humanoid = player.Character:FindFirstChildWhichIsA("Humanoid")
-- Get associated Humanoid (client side)
local character = Players.LocalPlayer.Character
local humanoid = character.Humanoid
[TODO: Update as we go]
See https://create.roblox.com/docs/reference/engine/classes/Player for more info
Humanoid
The humanoid object is a special object type that gives models the ability of a character. Humanoid objects can walk around and interact the level. Humanoids are always parented inside a Model, the model is expected to be an assembly of BasePart and Motor6D.
There are two types of rig types for characters which are called R6 and R15.
The Humanoid object has a number of important properties:
- CameraOffset – Camera offset from player
- DisplayName – Name displayed above the characters head
- FloorMaterial – The material the character is currently stood on or Air if not
- Health – Amount of health
- MaxHealth – Max health of character
- JumpHeight – Jump height of character
- Many more properties
See https://create.roblox.com/docs/reference/engine/classes/Humanoid for more info
Parts
The Part object is a basic 3D part and a type of BasePart (BasePart is abstract). A part comes in a number of different primitive shapes including Ball, Block, Cylinder, Wedge, and CornerWedge as well as more complex parts such as MeshPart’s. Lets take a look at creating and destroying a part in code:
local part = Instance.new("Part")
part.Name = "MyBall"
part.Anchored = true
part.Shape = Enum.PartType.Ball
part.Color = Color3.new(1, 1, 1)
part.Parent = workspace -- Put the part into the Workspace
-- Destroy part
part:Destroy()
Note that parts automatically have physics applied to them.
Parts support all sorts of events which are fired when something happens to the part for example when the part is being destroyed:
local part = Instance.new("Part", workspace)
local function onPartDestroying()
print("Before yielding:", part:GetFullName(), #part:GetChildren())
task.wait()
print("After yielding:", part:GetFullName(), #part:GetChildren())
end
part.Destroying:Connect(onPartDestroying)
part:Destroy()
Another example is Touched and TouchEnded events:
local part = script.Parent
local billboardGui = Instance.new("BillboardGui")
billboardGui.Size = UDim2.new(0, 200, 0, 50)
billboardGui.Adornee = part
billboardGui.AlwaysOnTop = true
billboardGui.Parent = part
local tl = Instance.new("TextLabel")
tl.Size = UDim2.new(1, 0, 1, 0)
tl.BackgroundTransparency = 1
tl.Parent = billboardGui
local numTouchingParts = 0
local function onTouch(otherPart)
print("Touch started: " .. otherPart.Name)
numTouchingParts = numTouchingParts + 1
tl.Text = numTouchingParts
end
local function onTouchEnded(otherPart)
print("Touch ended: " .. otherPart.Name)
numTouchingParts = numTouchingParts - 1
tl.Text = numTouchingParts
end
part.Touched:Connect(onTouch)
part.TouchEnded:Connect(onTouchEnded)
Many different kinds of events are supported.
See https://create.roblox.com/docs/reference/engine/classes/Part and https://create.roblox.com/docs/reference/engine/classes/BasePart for more info
GuiObject
A GuiObject is an abstract base class that forms the base of all GUI objects, it provides some base properties such as size and position. UIComponent’s can be attached to GUI objects as children to affect their behaviour, such as forcing the layout of its children, adding padding etc..
Types of GUI objects:
- Frame – Like a Unity panel, these are used to group GUI elements together.
- TextLabel – Displays text.
- TextButton – Button with text
- TextBox – Text entry
- ImageLabel – Displays an image.
- ImageButton – Button with an image
Size and Positions
Elements are positioned and sized using scale and offset. Offset represents the pixel size / position, whilst scale represents size / position of parent. For example an element positioned at 0.5 scale and offset 100 would position the element half way across the screen + 100 pixels. Setting its size to scale of 0.1 and offset of 0 will make it 10% of the screen size (assuming the elements parent is the screen)
See https://create.roblox.com/docs/reference/engine/classes/GuiObject for info on GuiObject’s
See https://create.roblox.com/docs/ui for more general GUI info
[TODO: Add more object types]
Roblox API
The Game Object
game object is the big table for the whole game, both wonderful and nightmarish.
See https://create.roblox.com/docs/reference/engine/classes/DataModel for more info
Task Library
- task.wait(time) Yields a thread, we generally call this inside a loop of a spawned task
- task.spawn(function) – Spawns a function immediately
- task.defer(function) – Spawns a function at the end of the frame with all the other deferred tasks
- task.delay(time, function) – RunAfterTime basically
These functions all return a thread type which can be manipulated, e.g.:
local thread = task.delay(5, function()
DoSomeShiz
end
print(coroutine.status(thread)
See https://create.roblox.com/docs/reference/engine/libraries/task for more info
Basic Data Types
Examples:
local position = Vector3.new(1, 2, 3)
workspace.YellowPart.Position = position
workspace.YellowPart.Color = Color3.fromRGB(50, 100, 255)
local newPart = Instance.new("Part") – Creates an instance of a new Part
newPart.Anchored = true
newPart.Position = Vector3.new(1, 2, 3)
newPart.Shape = Enum.PartType.Ball
local rng = Random.new()
print(rng.NextInteger(1, 100))
Attributes
Attributes can be added to any object and accessed from code. They can be added in the editor under the Attributes section of the object or added in code. You can also delete attributes, get a list of all attributes and listen for changes to the attributes:
-- Add or update attribute
local weapon = script.Parent
weapon:SetAttribute("ReloadTime", 3)
-- Get the attribute value
local reloadTimeValue = weapon:GetAttribute("ReloadTime")
print(reloadTimeValue)
-- Get all instance attributes
local weaponAttributes = weapon:GetAttributes()
for name, value in weaponAttributes do
print(name, value)
end
-- Delete an existing attribute
weapon:SetAttribute("ReloadTime", nil)
--- Listen for one specific attribute change
weapon:GetAttributeChangedSignal("ReloadTime"):Connect(function()
print(weapon:GetAttribute("ReloadTime"))
end)
-- Listen for any attribute change on the instance
weapon.AttributeChanged:Connect(function(attributeName)
print(attributeName, weapon:GetAttribute(attributeName))
end)
See https://create.roblox.com/docs/studio/properties for more info
Coordinate Frames (CFrame)
Unity Transform without scale. Cframe is actually a matrix so if you multiple them together its like multipliying matrices. Cframes support Lerp:
local redBlock = workspace.RedBlock
local blueCube = workspace.BlueCube
-- Create a Vector3 for both the start position and target position
local startPosition = Vector3.new(0, 3, 0)
local targetPosition = blueCube.Position
-- Put the redBlock at startPosition and point its front surface at targetPosition
redBlock.CFrame = CFrame.new(startPosition, targetPosition)
See https://create.roblox.com/docs/workspace/cframes for more info
Event Driven
Roblox is very event drivem:
local part = workspace.EventPart
-- Touched event
part.Touched:Connect(function(otherPart)
print(otherPart.Name)
end)
-- Child / Descendant added event
part.ChildAdded:Connect(function(child)
print(child.Name)
end)
part.DescendantAdded:Connect(function(descendant)
print(descendant.Name)
end)
for i = 1, 2 do
local newPart = Instance.new("Part")
newPart.Name = "NewPart"..i
newPart.Parent = part:FindFirstChildWhichIsA("BasePart") or part
end
See https://create.roblox.com/docs/scripting/events for more info
Animation
Animations can be played both server and client side.
Remote events
A remote event instance allows the server to communicate information to the client or the client to the server.
Create a new RemoteEvent in ReplicatedStorage in the editor so that the client and server has access to the event and then:
Client
local replicatedStorage = game:GetService("ReplicatedStorage")
local event = ReplicatedStorage.RemoteEvent
event:FireServer("Hello")
Server
local replicatedStorage = game:GetService("ReplicatedStorage")
local event = ReplicatedStorage.RemoteEvent
event:OnServerEvent:Connect(function(player, data)
print(player.Name, data)
end)
See https://create.roblox.com/docs/scripting/events/remote for more info
Remote functions
A remote function instance allows the client to call the server and get a result returned. Can be used for calls to client from server too but not recommended because the elient may have left
Create a new RemoteFunction in ReplicatedStorage in the editor so that the client and server has access to the function and then:
Client
local replicatedStorage = game:GetService("ReplicatedStorage")
local event = ReplicatedStorage.RemoteFunction
local result = event:InvokeServer("Hello")
Server
local replicatedStorage = game:GetService("ReplicatedStorage")
local event = ReplicatedStorage.RemoteFunction
event:OnServerInvoke = function(player, password)
if (password == "Hello") then
return true
end
return false
end
See https://create.roblox.com/docs/reference/engine/classes/RemoteFunction for more info
Bindable Functions and Events
Bindable Function and Events are like Remote functions and events but only operate on the same side of the client-server divide. This allows for synchronous two-way communication between scripts on the same side of the client-server boundary. The code invoking the function yields until the corresponding callback is found, and the callback receives the arguments that you passed to Invoke(). If the callback was never set, the script that invokes it will not resume execution.
See https://create.roblox.com/docs/reference/engine/classes/BindableFunction for more info
Tween Service
TweenService can animate most properties, quick example of a looping tween;
local TweenService = game:GetService("TweenService")
local part = Instance.new("Part")
part.Position = Vector3.new(0, 10, 0)
part.Anchored = true
part.Parent = workspace
local tweenInfo = TweenInfo.new(
2, -- Time
Enum.EasingStyle.Linear, -- EasingStyle
Enum.EasingDirection.Out, -- EasingDirection
-1, -- RepeatCount (when less than zero the tween will loop indefinitely)
true, -- Reverses (tween will reverse once reaching it's goal)
0 -- DelayTime
)
local tween = TweenService:Create(part, tweenInfo, { Position = Vector3.new(0, 30, 0) })
tween:Play()
task.wait(10)
tween:Cancel() -- cancel the animation after 10 seconds
See https://create.roblox.com/docs/reference/engine/classes/TweenService for more info
User Input Service
Used to detect and capture different types of input from the users device, for example:
local UserInputService = game:GetService("UserInputService")
UserInputService.InputBegan:Connect(function(inputObj, processed)
print("Was processed by UI:", processed)
if inputObj.UserInputType == Enum.UserInputType.MouseButton1 then
print("mouse was held down")
elseif inputObj.KeyCode == Enum.KeyCode.E then
print("key E was held down")
end
end)
UserInputService.InputEnded:Connect(function(inputObj, processed)
print("Was processed by UI:", processed)
if inputObj.UserInputType == Enum.UserInputType.MouseButton1 then
print("mouse was released")
elseif inputObj.KeyCode == Enum.KeyCode.E then
print("key E was released")
end
end)
UserInputService.TouchTapInWorld:Connect(function(screenPos, processed)
print("Was processed by UI:", processed)
print("screen tap at position:", screenPos)
end)
See https://create.roblox.com/docs/reference/engine/classes/UserInputService for more info
Context Action Service
Allows you to bind user input to contextual actions, or actions that are only enabled under certain condition or at specific points n of time. An example is allowing a player to open a door only while close to the door, this will pop up a small contextual action bubble.
local ContextActionService = game:GetService("ContextActionService")
local function onAction(actionName, inputState, inputObj)
if inputState == Enum.UserInputState.Begin then
print("Input began!", actionName)
elseif inputState == Enum.UserInputState.End then
print("Input ended!", actionName)
end
return Enum.ContextActionResult.Pass
end
-- Allows us to listen to multiple different inputs & creates a button on screen
ContextActionService:BindAction("ExampleAction1", onAction, true, Enum.KeyCode.P, Enum.UserInputType.Touch, Enum.UserInputType.MouseButton1)
ContextActionService:BindAction("ExampleAction2", onAction, true, Enum.KeyCode.P, Enum.UserInputType.Touch, Enum.UserInputType.MouseButton1)
local button = ContextActionService:GetButton("ExampleAction1")
button:SetTitle("Example Action 1")
-- When we are done with listening to these actions we can unbind them
ContextActionService:UnbindAction("ExampleAction1")
ContextActionService:UnbindAction("ExampleAction2")
See https://create.roblox.com/docs/reference/engine/classes/ContextActionService for more info
Collection Service
CollectionService manages collections of instances with tags. Tags are sets of strings applied to objects that replicate from the server to the client. They are also serialized when places are saved. You can set a tag to objects in the workspace as well as in script.
local CollectionService = game:GetService("CollectionService")
-- Get all instances marked with KillBrick tag
local bricks = CollectionService:GetTagged("KillBrick")
local connections = {}
local function onTouched(otherPart)
local humanoid = otherPart.Parent:FindFirstChildWhichIsA("Humanoid")
if humanoid then
humanoid.Health = 0
end
end
-- Sets up all current kill bricks in the game
for _, brick in bricks do
connections[brick] = brick.Touched:Connect(onTouched)
end
-- Sets up any kill bricks added after the game starts
CollectionService:GetInstanceAddedSignal("KillBrick"):Connect(function(brick)
print("new killbrick was added!")
connections[brick] = brick.Touched:Connect(onTouched)
end)
-- Cleans up any parts that have this tag removed
CollectionService:GetInstanceRemovedSignal("KillBrick"):Connect(function(brick)
if connections[brick] then
connections[brick]:Disconnect()
connections[brick] = nil
end
end)
Dee https://create.roblox.com/docs/reference/engine/classes/CollectionService for more info
Players Service
The Players service contains Player objects for all connected clients to a Roblox server. It contains information about a place’s configuration. It can also collect info about players that are not connected to the server, i.e. players character appearances, friends and avatar thumbnail etc..
Players Joining / Leaving Events
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
print(player.Name .. " joined the game!")
end)
Players.PlayerRemoving:Connect(function(player)
print(player.Name .. " left the game!")
end)
Getting a players name from their ID
local Players = game:GetService("Players")
local name = Players:GetNameFromUserIdAsync(118271)
Accessing backpack
-- Backpack from a Server Script
game.Players.PlayerName.Backpack
-- Backpack from a LocalScript
game.Players.LocalPlayer.Backpack
Adding a tool via code
local Players = game:GetService("Players")
local function giveTool(player, tool)
local backpack = player:FindFirstChildOfClass("Backpack")
if backpack then
tool.Parent = backpack
end
end
local function onPlayerAdded(player)
local tool = Instance.new("Tool")
giveTool(player, tool)
end
Players.PlayerAdded:Connect(onPlayerAdded)
Adding a tool via editor
See https://create.roblox.com/docs/reference/engine/classes/Players for more info
Data Store Service
The DataStoreService allows us to store data that needs to persist between sessions, such as items in a player’s inventory or skill points. Data stores are consistent per experience, so any place in an experience can access and change the same data, including places on different servers. Also supports Ordered Data Store.
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local moneyDataStore = DataStoreService:GetDataStore("PlayerMoney")
local erroredPlayers = {}
local function getMoneyDataFor(player)
local success, result = pcall(function()
return moneyDataStore:GetAsync(player.UserId)
end)
if success then
if not result then
-- no result means this is a new player in our game
result = 0
end
return result
end
warn("Failed to grab money data for player:", player.UserId, result)
--[[ What if we failed to grab data?
then we don't want to save this data for the player when they leave.
Store them in a table so we can keep track of errored players
]]
erroredPlayers[player.Name] = true
return 0
end
local function saveMoneyDataFor(player, amount)
-- Don't wont want to save data for nonreal player accounts
if player.UserId < 1 then
warn("Unable to save data for nonreal player accounts!")
return
end
if erroredPlayers[player.Name] then
warn("Can't save data for an errored player!")
return
end
local success, err = pcall(function()
moneyDataStore:UpdateAsync(player.UserId, function(oldData)
-- this function is NOT allowed to yield!
oldData = amount
return oldData
end)
end)
if not success then
warn("Failed to save data for player:", player.UserId, err)
end
end
local function setupLeaderboardFor(player)
local folder = Instance.new("Folder")
folder.Name = "leaderstats"
folder.Parent = player
local money = Instance.new("NumberValue")
money.Name = "Money"
money.Value = getMoneyDataFor(player) -- grabs players money from data store
money.Parent = folder
end
local function saveMoneyDataForAllPlayers()
for _, player in Players:GetPlayers() do
task.spawn(function()
saveMoneyDataFor(player, player.leaderstats.Money.Value)
end)
end
end
Players.PlayerAdded:Connect(function(player)
setupLeaderboardFor(player)
end)
Players.PlayerRemoving:Connect(function(player)
-- Saves a players money when leaving the game
saveMoneyDataFor(player, player.leaderstats.Money.Value)
erroredPlayers[player.Name] = nil
end)
for _, player in Players:GetPlayers() do
setupLeaderboardFor(player)
end
game:BindToClose(function()
-- Saves players money when game is shutdown
saveMoneyDataForAllPlayers()
end)
while true do
-- saves players money every 5 minutes
task.wait(300)
saveMoneyDataForAllPlayers()
end
See https://create.roblox.com/docs/reference/engine/classes/DataStoreService for more info
Text Chat Service
TextChatService handles text chat, including managing channels, decorating messages, filtering text, creating commands, and developing custom chats interfaces.
-- text chat service & rich text markup
local TextChatService = game:GetService("TextChatService")
local Players = game:GetService("Players")
TextChatService.OnIncomingMessage = function(msg)
if not msg.TextSource then
return
end
local properties = Instance.new("TextChatMessageProperties")
local player = Players:GetPlayerByUserId(msg.TextSource.UserId)
local hasVIP = player:GetAttribute("HasVIP")
if hasVIP then
-- account for any previous prefixes by concatenating
properties.PrefixText = "<font color='#F5CD30'>[VIP]</font> "..msg.PrefixText
end
return properties
end
TextChatService.OnBubbleAdded = function(msg, adornee)
if not msg.TextSource then
return
end
local bubbleProperties = Instance.new("BubbleChatMessageProperties")
local player = Players:GetPlayerByUserId(msg.TextSource.UserId)
local hasVIP = player:GetAttribute("HasVIP")
if hasVIP then
bubbleProperties.TextColor3 = Color3.fromRGB(255, 149, 0)
bubbleProperties.BackgroundColor3 = Color3.fromRGB(81, 81, 81)
bubbleProperties.FontFace = Font.fromEnum(Enum.Font.Arcade)
end
return bubbleProperties
end
See https://create.roblox.com/docs/reference/engine/classes/TextChatService for more info
Messaging Service
MessagingService allows servers of the same game to communicate with each other in real time using topics. Topics are developer‑defined strings (1–80 characters) that servers use to send and receive messages.
Delivery is not guaranteed so we have to plan the game around delivery failures being possible.
local MessagingService = game:GetService("MessagingService")
local Players = game:GetService("Players")
local function onPlayerAdded(player)
--subscribe to the topic
local topic = "player-" .. player.UserId
local connection = MessagingService:SubscribeAsync(topic, function(message)
print("Received message for", player.Name, message.Data)
end)
player.AncestryChanged:Connect(function()
-- unsubscribe from the topic
connection:Disconnect()
end)
end
Players.PlayerAdded:Connect(onPlayerAdded)
See https://create.roblox.com/docs/reference/engine/classes/MessagingService for more info
Content Provider Service
This service is used to load content / assets into the game. The main use of this service is to preload assets into the game. Assets are loaded using PreloadAysnc().
Example:
local ContentProvider = game:GetService("ContentProvider")
local LOGO_ID = "rbxassetid://658743164"
local PAGE_TURN_ID = "rbxassetid://12222076"
local decal = Instance.new("Decal")
decal.Texture = LOGO_ID
local sound = Instance.new("Sound")
sound.SoundId = PAGE_TURN_ID
local assets = { decal, sound }
ContentProvider:PreloadAsync(assets)
print("All assets loaded.")
See https://create.roblox.com/docs/reference/engine/classes/ContentProvider for more info
Path Finding Service
[TODO]
Leaderboard Service
[TODO]
HTTP Service
[TODO]
Sound Service
[TODO]
MarketplaceService
[TODO]
Other Things
Instance Streaming
Roblox can stream larger environments instead of loading it all at once. This is automatic but can be customised
[TODO: Expand on this section]
Raycasting
-- raycast tool script
local tool = script.Parent
local handle = tool.Handle
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
tool.Activated:Connect(function()
params.FilterDescendantsInstances = {tool.Parent} -- excludes player's character's descendants from the raycast
local origin = handle.Position
local direction = handle.CFrame.LookVector
local result = workspace:Raycast(origin, direction * 100, params)
if result then
print("Hit instance:", result.Instance.Name, "at position:", result.Position)
-- visualizing the raycast
local part = Instance.new("Part")
part.Size = Vector3.new(0.05, 0.05, result.Distance)
part.Color = Color3.fromRGB(255, 255, 255)
part.Anchored = true
part.CanCollide = false
part.CFrame = CFrame.lookAt(origin, result.Position) * CFrame.new(0, 0, -result.Distance/2)
part.Parent = workspace
else
print("The ray hit nothing!")
end
end)
Teleporting
-- Teleport the player server side
function TeleportTo(player, position)
local character = player.Character
if character then
local primaryPart = character.PrimaryPart
if primaryPart then
primaryPart.CFrame = CFrame.new(position)
end
end
end
Collision
Parts that are anchored are not generally under control of the physics system so do not register touched events unless touched by an unanchored part. We can respond to a touch star / end events by connecting a function to the Touched function
local function onTouch(otherPart)
print("Touch started: " .. otherPart.Name)
end
local function onTouchEnded(otherPart)
print("Touch ended: " .. otherPart.Name)
end
part.Touched:Connect(onTouch)
part.TouchEnded:Connect(onTouchEnded)
Note that there are options to check if parts overlap in the WorldRoot API such as ArePartsTouchingOthers(), GetPartBoundsInBox(), GetPartBoundsInRadius(), GetPartsInPart(), Raycast() etc..
Camera rotate with player
Some games find it useful for the camera to align behind the player, e.g.:
local UP_VECTOR = Vector3.new(0, 1, 0);
RunService.Heartbeat:Connect(function(time: number, deltaTime: number)
UpdateCamera(deltaTime)
end)
function UpdateCamera(dt)
-- Get the camera to rotate with the player
local part = self.Player.Character.PrimaryPart
part.CFrame = CFrame.fromMatrix(part.Position, self.Camera.CFrame.RightVector, UP_VECTOR);
end
Offsetting the camera
Its offset useful to be able to offset the camera from the player for example have a shoulder cam set up, e.g.
local humanoid = self.Player.Character.Humanoid
if (humanoid) then
humanoid.CameraOffset = Vector3.new(3, 0, 0)
end
Detecting tool changes
Its possible to detect when the player changes tools server and client side, the same script can be used inside a server or local script with the script placed within the tool as child:
local RunService = game:GetService("RunService")
local Tool = script.Parent
local IsServer = RunService:IsServer()
Tool.Equipped:Connect(function()
print("GrenadeLauncher Equipped " .. tostring(IsServer))
end)
Tool.Unequipped:Connect(function()
print("GrenadeLauncher Unequipped " .. tostring(IsServer))
end)
-- Only Activated() does not run server side
Tool.Activated:Connect(function()
print("GrenadeLauncher Activated " .. tostring(IsServer))
end)
Note that the script does not need to be placed within the tool, it can be hosted elsewhere such as in a module however you will need to find the tool within the players backpack in order to access it:
local Tool = player.Character:FindFirstChildOfClass("Tool")
Note that for the above to work it requires that the Player and its Character must already be loaded
Plugins
[TODO]
See https://create.roblox.com/docs/studio/plugins for more info