Unity to Roblox Reference

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