[Full Tutorial] How to script on Roblox | Beginners!

How do script [ Update Version], 2022/2023

Introduction

Hey there! Today, I will be teaching you how to script from scratch - all the basics you need to know when coming to script on Roblox with a better and updated version!

[If you’re a beginner] After this tutorial, you should learn:

  • Understand the very basics of scripting on Roblox.

In this tutorial, we’ll be talking about:

  • Variables, DataTypes.
  • Attributes, Properties.
  • Math library.
  • Conditions,Functions, Loops.
  • Return, Remotes.
  • Gamepasses,DevProducts.
  • Tools,Player, Character, Animation.
  • TweenService, Camera.
  • ClickDetectors & ProximityPrompts.
  • Mouse & UserInputService.

Anticipation and expectations

Look, like every other profession/hobbies, it doesnt take straight away to success in learning something new. It is a process, it might be short or long way, but you can’t escape the process. The result doesn’t matter. What matters is the process done throughout the way. Because during that, you’re learning how to be better, and how to struggle with multiple conditions.

So, what does scripting mean?

When you’re scripting/programming, you’re actually manipulating, customizing, and making cool stuff using an existing program/system. Meaning, you’re providing instructions to your computer - telling it what to do, and how do you want to acheive your goal by doing what I mentioned above.

On Roblox, you could think of scripting as the Scenes in the back of each game on the platform. And every game you see on Roblox, was made by people who scripted and wrote codes to run these games properly and playable.

Let’s dive into the sea!

So now that we know what we are doing and what stands behind it, we should start learning how to implement and write our first codes which would eventually lead to a long process that at the end, we’ll be ready to make our own games.

Part 1

Variables

A variable is basically a name[ string ] that can hold / have any value.
Very impotant! There are few keys that you can not use as variables, and those are:


Defining a variable should look like this:

local myVar = 5
--OR
myVar = 5

The difference between the 2 ways is: first one is local, whereas the second one is global[ which is slower by the way]. You could see that difference in the following example:

--Local Variable
local myVar = 0
for k = 1,10 do
	local myVar = 0
	myVar += k
	print("myVar now equals to: "..k) -- 10
end
print("myVar now equals to: "..myVar) -- 0


--Global Variable
myVar = 0
for k = 1,10 do
	myVar += k
	print("myVar now equals to: "..k) -- 10
end
print("myVar now equals to: "..myVar) -- 55
DataTypes

A DataType in programming means classifying values and specifying their variables with value types. [For example : string, number, boolean, table, nil]. In addition to that, it also determines what type of mathematical, relational or logical operations can be applied to it, which would eventually lead us to different results depending on what we used.

Data Types On Roblox!

On Roblox, we have 6 types of Data Types, let’s review them and see what they are and what they do.

1. Nil

On Roblox, the nil value means nothing/doesn’t exist. And what it does is remove the object/value from your game or and/or its reference. Moreever, luau [ Roblox language] has a garbage collector which basically removes any data/references which are not used/accessible by any script. Let’s see an example:

local part = Instance.new("Part")

--Properties
part.Name = "Test"
part.Color = Color3.fromRGB(85, 255, 255)
part.Size = Vector3.new(1,1,1)
part.Transparency = 0.5
part.Position = Vector3.new(0,5,0)

--Parenting it
part.Parent = workspace
print(part) -- Test

--Delay
task.wait(3)

--Re-parting it and removing it, so you can't see it.
part.Parent = nil
print(part,part.Parent) -- Test, nil

--Removing part reference
part = nil
print(part) -- Nil

As you can see, the code above creates a part, changes some of its properties, parents it into workspace, and then to nil, and then setting the part itself to nil, and as you should’ve noticed :
Although we parented the part to nil, we still had its reference, hence that’s why the second print returned us the part, whereas the last print returned nil because we removed the part’s reference.

2. Boolean

The boolean value can have 2 values - true or false. Notice that if you set the bool’s value to nil, it would return you false. An example:

local value = Instance.new("BoolValue")

value.Name = "Boolean"
value.Value = nil
value.Parent = workspace

print(value,value.Value) -- Boolean, false
3. Numbers

A number value represents any possible number. Including decimals, zero and negatives. It is also important to know its limits:
Range: from : -1.7 × 10308 to 1.7 × 10308 (around 15 digits of precision)

An int value represents any possible integers. Including zero and negatives.
Trying to set an intvalue’s value to a decimal number, would give you the following error:
Unable to cast string to int64.
It is also important to know its limits -
Range: from: -2 ^ 31 to 2^31 - 1.

Note:
When you’re trying to set an int/numbervalue’s value to nil, it’d return 0. And when you’re trying to set an intValue’s value to a decimal, it’d round that number to its closest int value. [ see example below].

The following example is simply creating an IntValue and a NumberValue, and tries to set its values to different time of values.

------Creating an IntValue-------
local Int = Instance.new("IntValue")
Int.Name = "Int"
Int.Value = 10
Int.Parent = workspace

------Creating a NumberValue-------
local Num = Instance.new("NumberValue")
Num.Name = "Num"
Num.Value = 10
Num.Parent = workspace

------Setting their values to different values-------
Int.Value = nil
print(Int.Value) -- 0

Int.Value = 10.5
print(Int.Value) -- 11

Num.Value = nil
print(Num.Value) -- 0
4. Strings

A string value is simply a sequence full of characters [ letters, numbers and symbols].

Declaring Strings On Roblox:
There are multiple ways to define/delcare a string on Roblox, I will show 3 of them:
1.double quotes ("), look at the example below to see.
2.single quotes ('), look at the example below to see.
3.double brackets ([[), look at the example below to see.

The following example simply delcares multiple strings in all 3 ways mentioned above.

------------Defining Strings------------
local String1 = "Hey! This is a string!"
local String2 = '1+1 = 2! This is a string too!'

local String3 = [[
"Hello!"
'Hello!'
]]

------------Printing Strings------------
print(String1) -- Hey! This is a string!
print(String2) -- 1+1 = 2! This is a string too!
print(String3) -- "Hello!"
               -- 'Hello!'

Converting Strings → Numbers and vice versa.
There are multiple times when you would prob need to convert a string into a number [ or vice versa], a fresh example would be: Say you have a TextBox which lets you redeem players’ IDs, and you want to use the input to do something. You notice that that number is passed as a string. Not as a number.
That’s where tonumber() and tostring() get involved.

tonumber()
This function would convert your string into a number [ if possible].

tostring()
This function would convert your value into a string [ if possible].

The following example would try to convert both a string → number, and number → string.

local Number = 1
local String1 = "Hello"
local String2 = "1"

print(Number + String2) -- 2! Since `String2` can be defined as a number , althought its variable defined as a string.
print(Number + String1) -- Error! attempt to perform arithmetic (add) on number and string.

print(tonumber(String2)) -- 1
print(tonumber(String1)) -- nil

print(tostring(Number)) -- 1
print(tostring(String2)) -- 1

Combining Strings
To combine 2 [ or more] strings, you’ll need to use this: .. . See example below:

local String1 = "Hello"
local String2 = "World"
local String3 = 5

print(String1.." "..String2) -- "Hello World"
print(String1..String2) -- "HelloWorld"
print(String1..String3) -- Hello5
5. Tables

Think of tables as big containers which contain multiple types of variables [ except for nil].
There are ‘2 types of tables’ that you’ll see:

Arrays

A list with an order, containing multiple types of values. An example:

local myArray = {"Hello",1,game.Workspace.MyPart,true)

As you can see, myArray contains 4 types of values: string, number, object and a boolean [ accordingly].

Notes:
To get a value/ read from an array, simply put a [] and the index within. For example:

print(myArray[1]) -- would print "Hello"
print(myArray[6]) -- nil, doesnt exist.

To replace an exisiting value within an array, with something else, you should call the index of the value you want to change, and put in within the [ ] when calling the array, an example:

local myArray = {"Hello",1}
print(myArray[1]) -- "Hello"

myArray[1] = 2
print(myArray[1]) -- 2

Functions For Arrays:
There are multiple functions to work with when using arrays, here is the list of them:
-table.clone()
-table.find()
-table.getn()
-table.maxn()
-table.move()
-table.pack()
-table.sort()
-table.clear()
-table.concat()
-table.create()
-table.freeze()
-table.insert()
-table.remove()
-table.unpack()
-table.foreach()
-table.foreachi()
-table.isfrozen()

I will exaplain 4 of them:
1.table.getn(): returns the amount of items your array has. An example:

local mytab = {1,2,6}
print(table.getn(mytab)) -- 3

2.table.insert(): inserts the provided value into the provided table. An example:

local mytab = {1,2,6}
print(mytab[4])--nil
local newValue = table.insert(mytab,5)
print(mytab[4]) -- 5

3.table.concat(): returns all the values in your array, separated with the given symbol. An example:

local mytab = {1,2,6}
print(table.concat(mytab,"!")) -- 1!2!6!

4.table.clear(): clears all the values from the given table. Meaning it sets those values to nil. An example:

local mytab = {1,2,6,"hey"}
print(mytab[1],#mytab) -- 1,4
table.clear(mytab)
print(mytab[1],#mytab)-- nil,0

Iterating/Looping over arrays:
To loop over an array, simply use the global ipairs() [or pairs(), depending on your use] function in a for loop. You should also remember that arrays have numerical indices, which means - you can also use a numeric for loop from 1 to the length of the array (#array).
An example:

local tab = {4,3,2,1.2}

for index,value in pairs(tab) do
	print(index,value)
end

print("------------------------")

for index,value in ipairs(tab) do
	print(index,value)
end

The difference is that if there was a nil value within the table, pairs would continue counting, but without the nil index. Whereas ipairs would stop at one index before the nil value, and won’t continue.

Dictionaries

Extention of arrays.Unlike arrays, dictionaries contain a set of key-value pairs. (where the keys can be any number, string, or object.) An example:

local dictionary = {
	Key1 = "Bell", -- Key,Value
	Key2 = "Steve", --Key,Value
	Key3 = 500 --Key,Value
}
print(dictionary)

To replace an exisiting value within a dictionary, simply specify the key of that value within a couple of []. An example:

local dictionary = {
	Key1 = "Bell",
	Key2 = "Steve",
	Key3 = 500
}
print(dictionary["Key1"]) -- Bell
dictionary["Key1"] = 5
print(dictionary["Key1"]) -- 5

To add new values, simply specify a key within a [ ]. An example:

local dictionary = {
	Key1 = "Bell",
	Key2 = "Steve",
	Key3 = 500
}
print(dictionary["Key4"]) -- nil
dictionary["Key4"] = 5
print(dictionary["Key4"]) -- 5

Iterating/Looping over dictionaries:
Notice! ipairs only works with arrays, so don’t try to use ipairs on dictionaries [unless you have made custom functions which would help you with that].

Notice! using pairs would NOT necessarily return you the items in a specified order, it’s random.
A solution could be as the following:

--Our dictionary, containing multiple keys.
local dictionary = {
	Key1 = 5,
	Key2 = 25,
	Key3 = 500,
	Key4 = 210
}
--A table[to be an array] that will store our values from the dictionary
local values = {}

--A for loop, to loop over our dictionary and then insert the values into our 'values' array
for key,value in pairs(dictionary) do
	table.insert(values,value)
end

--Using 'table.sort' to sort our values with an order. function(a,b) would determine what order we want to have
table.sort(values,function(a,b)
	return a<b
end)

--Printing our 'new sorted' dictionary
print(values)
6. Enums

Enums ( stands for enumeration ) are numbers which can take on specific sets of values. To access any type of enum, you should start with Enum., an example:

local Part = Instance.new("Part")

Part.Name = "Block"
Part.Color = Color3.fromRGB(255, 170, 0)
Part.Shape = Enum.PartType.Ball
Part.Name = "Ball"

Part.Parent = workspace

The above example creates a new part, changes few of its properties, and then switch its shape into a Ball. Now, we could alternatively change its shape like this:

Part.Shape = "Ball"

But this isn’t the best way, and might be a little problematic.
Now, if you’re curious, you could go and put another . after the Ball, and you’ll see: Name, Value and EnumType. And if you try to print those, you’d get:

print(Part.Shape.EnumType,Part.Shape.Name,Part.Shape.Value) -- PartType, Ball, 0

Each Enum has a Value [ a number], a Name[ string], and a EnumType [enum].
If you want to get the entire list of available enums, you’ll need to go to the DeveloperHub.

Notes:
To get all items of an enum, use GetEnumItems(). An example:

local PartEnums = Enum.PartType:GetEnumItems()

for index,value in pairs(PartEnums) do
	print(value)
end

--[[
	Enum.PartType.Ball
	Enum.PartType.Block
	Enum.PartType.Cylinder
]]
Properties & Attributes

In this section, we’ll be learning about Properties and Attributes[ custom properties].

So, what are properties?

Properties allow you to adjust and change the look & behaviour of certain objects, you can change some of them manually through VIEWPROPERTIES.In the following example, we’re changing multiple properties of a Part :

------Inserting a Part------
local Part = Instance.new("Part")

------Editing some properties------
Part.Name = "Hey there" -- chaning its name
Part.Size = Vector3.new(5,5,5) -- changing its size
Part.BrickColor = BrickColor.random()  -- changing its BrickColor to a random one
Part.Anchored = true -- setting its anchored to true, so that it won't fall from air

------Parenting it to workspace------
Part.Parent = workspace

Attributes

Attributes are custom properties which allow you to customize and edit your own properties on objects.
Attributes can be used in these cases:

To manually create an attribute, you should go to your object’s properties, scroll down until you find Add Attributes button.

To create an attribute from a script, we will use the SetAttribute() method, and inside, we’ll provide 2 arguments : 1.Attribute Name, 2.Attribute Value.

local Part = script.Parent
Part:SetAttribute("NewProperty",50)

To get an exisiting/created attribute from your object, we will use GetAttribute(), and provite it 1 argument - the attribute’s name. [Notice, you could also use GetAttributes() [don’t provide anything], it would return you a table of all your object attributes.

local Part = script.Parent

-----Setting the Attribute------
Part:SetAttribute("NewProperty",50)

-----Calling the Attribute------
print(Part:GetAttribute("NewProperty")) -- 50

To simply delete an attribute, set its value to nil.

local Part = script.Parent

-----Setting the Attribute------
Part:SetAttribute("NewProperty",50)

-----Removing the Attribute------
Part:SetAttribute("NewProperty",nil)

To detect when an attribute has changed, we will use either GetAttributeChangedSignal(AttributeName:string) or AttributeChanged(). See the example below:

local Part = script.Parent

-----Setting the Attribute------
Part:SetAttribute("NewProperty",50)

-----Detecting Attribute Changes------
Part:GetAttributeChangedSignal("NewProperty"):Connect(function()
	print(Part:GetAttribute("NewProperty"))
end)
Math Functions

In this section, we’ll be learning some of the most useful functions there are in luau math library. Let’s begin! (If you’re interested in seeing all math functions, please visit Math Library - Roblox DebHub.)

math.abs(x:number):

abs stands for absolute. Meaning it returns you the absolute value of the number.

print(math.abs(-5)) -- > 5

math.ceil(x:number):

ceil stands for ceiling. Meaning it rounds your number up to the closest integer.

print(math.ceil(5.21)) -- > 6

math.floor(x:number):

This function rounds your number down to the closest integer.

print(math.floor(5.21)) -- > 5

math.clamp(x:number,minimum:number,maxmium:number):

This function checks the first given number, and checks if it’s within the minimum & maximum range. There are 3 possible conditions:

A. That number is within the range. Result: we should get the exact same number.
B. That number is bigger than the maximum. Result: we should get the maximum number.
C. That number is smaller than the minimum. Result: we should get the minimum number.

print(math.clamp(1,0,10)) -- > 1
print(math.clamp(-1,0,10)) -- > 0
print(math.clamp(25,0,10)) -- > 10

math.min(x:number,…:number):

Simply returns the minimum[smallest] number among the passed numbers.

print(math.min(-5,25,-10,0,15,1)) -- -10

math.max(x:number,…:number):

Simply returns the maximum[biggest] number among the passed numbers.

print(math.max(-5,25,-10,0,15,1)) -- 25

math.random(x:number,y:number):

Simply returns a random number within the range of these 2 numbers.

print(math.random(1,100)) -- > 66

(If you’re interested to get decimals aswell, you might want to use the following:)

local random = Random.new()
print(random:NextNumber(1, 100)) -- 82.012

math.sqrt(x:number):

Simply returns the squre root ot the given number.

local number = 25
print(math.sqrt(number)) --- 5

Notice that when you’re trying to do: math.sqrt(-number) [number > 0], this would return you nan [ not a number].

math.pow(x:number,y:number):

Simply returns you x to the power of y.

local a = 2
local b = 5
print(math.pow(a,b)) -- 2 ^ 5 = 32

math.rad(angle:number):

Simply returns you the given angle[degrees] but in radians.

local AngleInDegrees = 90
print(math.rad(AngleInDegrees)) -- 1.5707

math.deg(angle:number):

Simply returns you the given angle[radians] but in degrees.

local AngleInDegrees = 90
local AngleInRadians = math.rad(AngleInDegrees)

print(math.deg(AngleInRadians)) -- 90

math.round(x:number):

Simply returns you the closest integer to that number.

local a = 25.666666666666666666666
local b = 25.111111111111111111111

print(math.round(a)) -- 26
print(math.round(b)) -- 25

math.log(x:number,y:base):

Simply returns you the logarithm of x, with the base of y.

local num = 8
local base = 2

print(math.log(num,base)) -- 3, since 2^3 == 8

Numbers with math. :

math.pi: A number. Equals [ approximately] to 3.14159265359.
math.huge: A huge number. Would return you inf if you printed math.huge.

If Statements

If statements are conditional statements. Meaning - code inbetween the if statement would only run under specified condition.Let’s see some examples:

local myVar = false

if myVar == true then -- if our variable equals to true, then..[condition 1]
	print(true)
else -- if not, meaning it equals to false [because booleans have only true / false conditions], then..[condition 2]
	print(false)
end

As you can see, when we run this code, it prints false. Simply because the first condition didn’t happen because it wasn’t true. But the ncame the second condition [ the else]. And checked if this
can happen, and it did.

Now, here are some tips/notes :
1.Instead of doing if myVal == true, you could simply do if myVal
2.Do not get confused! = is used when we set , change or define variables. Whereas == is used to compare between conditions.

The following example would check if the script.Parent, which is a Part here, is transparent or not, and act accordingly:

local Part = script.Parent

if Part.Transparency == 1 then
	print(Part.Name.. " is transparent!")
else
	print(Part.Name.." is visible!")
end
Loops

Before we get into what loops are. Let’s say we have a code that runs once, and we want to run it multiple times. How’d we do that? Obviously, there are several ways to do that, but we’ll focus on loops. Using a loop will help us run our code for more than once. And that’s what loops basically do - some loop through values / objects , whereas others would just run the code multiple times.
Let’s review some of the loops we have on Roblox:

The for k = a,b,c loop.

for k = 0,10,1 do
	print(k)
end
--This would print all numbers from 0 to 10.

Now, you might be wondering what are these 3 numbers, let’s have a look here:
for k = a: Is the ‘control variable’, in fact - that would be our variable and starting point.
b: Is the end value where that loop should stop at.
c: The increment value. By what number, do we want to increase/decrease the count.

Let’s now see an example where we decrease the value.

--This would not run, since we can't really increase 10 by 1 to reach 0.
for k = 10,0,1 do
	print(k)
end

--This would count from 10 to 0, -1 is the value we decrease the count by.
for k = 10,0,-1 do
	print(k)
end

The for index,value in pairs() / in ipairs() loops.

local tab = {1,2,3,4,nil,5,6}

for index,value in pairs(tab) do
	print(index,value)
end

--[[
	1 1
	2 2
	3 3
	4 4
	6 5
	7 6
]]

print("------------------------")

for index,value in ipairs(tab) do
	print(index,value)
end

--[[
	1 1
	2 2
	3 3
	4 4
]]

Let’s understand and review what’s going on here. So first, we have a table - containing few number values and 1 nil value. Both loops would loop through the items[values] within the table and print their index + value. If so, why do we get different results?
The answer is:
ipairs would stop once it finds a nil value within the table.
Whereas, pairs would just ignore that nil value and continue to the end.

As we mentioned when we talked about tables. pairs is a loop that would run for both types of tables, whereas ipairs would only run for arrays.

The While Loop

while true do
	--Code here would run forever, as long as the condition is met
	--Notice that without putting a delay, this would crash your game!
	--That's why, you should always have a task.wait()
	task.wait() -- you can choose any number you want, depending on your needs.
end

Let’s analyze this code,
so we first have this line while true do, which basically would run forever, as long as the condition is true/met.

You might be asking, but why do we need that task.wait()?
The answer is simple! If you tried to run a while loop without a delay, this would crash your studio/game, and that - we don’t want.

Breaking a While Loop

local Elapsed = 0
local Limit = 10

while true do
	print("Looping...")
	task.wait(1)
	Elapsed += 1

	if Elapsed == Limit then
		break
	end
end

print("Loop interupped/stopped.")

Let’s analyze the code, so we first have 2 variables at the top.
Elapsed is the initial value we’re counting on.
Limit is the maximum number we want the counting to go on.

Next, we’re having a delay of 1 second, and then we’re adding +1 to our initial value.

if Elapsed == Limit then
    break
end

This if statement is checking if we’ve reached the maximum number we want to add to our counting, and if it did, we break the loop. Which means, the loop will stop.

Functions

In this section, we’ll be learning about all basic types of functions you’ll need to know when scripting on Roblox. You could view functions as alot of things, one common way is as machines with defined tasks. And if we want to be a bit more accurate, functions are values that take up memory , receives thread control when called, and can be anonymous. Where the goals are portability, simplicity, small size, and scripting.

Define A Function:

local function myFunction() -- myFunction is the name of the function.
	--Any code here, would run only when the function is called
end

Now, you might be asking 2 things:
1.When I run this code, it doesnt do anything, why?
2.What if I wanted to put values in the ( )?

Parameters & Arguments

Let’s answer these questions and see how to implement it.
1.In order to make it actually do something/what the function is defined to do, you need to call the function. You can do this by declaring the function’s name.

local function myFunction() -- myFunction is the name of the function.
	print("This function is now running!")
end

myFunction() -- Calling the function to begin

2.If we wanted to provide values into our function, that’s what parameters are for!
Parameters allow us to edit and modify objects/values within our functions. You now might be wondering - how do I set parameters and use them? Let’s take a look here:

local function myFunction(String1,String2) -- myFunction is the name of the function.
	print(String1..String2) -- Hello!World
end

myFunction("Hello!","World") -- Calling the function to begin

As we can see, we have 2 parameters in out function - String1 and String2.
And you might notice that when we’re calling the function,we provided 2 values,[ in this case, 2 string values] - those are called arguments. And it is important to match them accordingly. What I mean is:
Hello!String1
WorldString2.

Returning data

Let’s assume we have the following function:

local function SumNumbers(n1,n2)
	local sum = n1+n2
	print(sum)
end

SumNumbers(1,2) -- > 3
SumNumbers(2,5) -- > 7
SumNumbers(2,5-2) -- > 5
SumNumbers(2,3)-5 -- > error

We can conclude a few conclusions:
1.We can call the function multiple times with different arguments.
2.We can’t perform any arithmetic actions with the result of the function yet.

And now, a question is asrising - how can we get the result [ the sum in this case], and perform arithmetic actions on it? The answer is return! Returning any data we want from the function, will help us use that data later on, again and again. Let’s return sum and see what happens:

local function SumNumbers(n1,n2)
	local sum = n1+n2
	return sum
end

local CallingFunction1 = SumNumbers(1,2) 
print(CallingFunction1) -- 3


local CallingFunction2 = SumNumbers(1,2) + 5 
print(CallingFunction2)  -- 8


local CallingFunction3 = CallingFunction1 + CallingFunction2
print(CallingFunction3) -- 11

You can notice that since we’re returning data and want to use it, we’re setting our function call as variables. This also allows us to easily do our stuff much faster. We could also do this if we wanted:

local function SumNumbers(n1,n2)
	local sum = n1+n2
	return sum
end

local CallingFunction1 = SumNumbers(2,3) 
print(CallingFunction1 / 25) -- 0.2, since 5/25 is 1/5 which is 0.2

Anonymous Functions

So far, we’ve seen functions with names. But now, it’s time to learn a ‘new type’ of functions - the anonymous functions! They do not have names, and they’re usually connected to an event / callback. Let’s take a look:

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(Player)
	print(Player.Name.." has arrived!")
end)

I am sure all of you have seen this event and used alot of it. What it does is basically calls an event [PlayerAdded] which is an event for the Players service and connects it to a function. Within that function, we can provide a parameter, which refers to the player who joined in the game. This is useful in so many cases.

Variadic Functions

Variadic Functions are functions that can accept an unlimited amount of arguments.[take for example the print() function:

print("Hello there John! did you know that :",1,"+",1,"=",2)
print(string.format("This %s is a %s!", "post", "tutorial")) -- This post is a tutorial!

Calling a Variadic Function with Arrays

Let’s assume we had the following array local array = {2,4,8,10,12}
We could do the following:

local array = {2,4,6,8,10,12}
print( "The first 5 even numbers are:", unpack(array))

Which basically ‘gets out’ all the items from the array , and arrange them in the string.

Part2

In the comment below, since we have a 50k characters limit.

Wait! So how do I make a game?

That’s a good question! Here are some tips, that some of them are given from some successul developers on Roblox:

1.Don’t give up! Keep going!
2.Try learn from free models, see the logic behind it!

Resources to learn from

Here, I am giving you some very helpful resources which would help you understand scripting better and how to move on, step by step.

Roblox ‘DevHub’ [now named Docs]:
This is probably one of the best, if not the best resource you can learn scripting from.

Feedback

It took me about 2-3 days to make this post [ organize and work as hard as possible to make it the best I could do].
And I would be very delighted to hear from all of you, is there anything I forgot/was wrong about?
if so, it’d be wonderful if you sent me a dm , here on Roblox, and tell me what should be improved!

  • It’s flawless ! I found this helpful!
  • Although I am not a beginner, I like it!
  • It’s very good! Feels like could’ve been a bit better, but good job.
  • Overall, it’s pretty nice for beginners!

0 voters

Your feedbacks will help me improve myself for the next tutorial!

Thank you! And best of luck!

91 Likes

Part 2

Remote Events & Functions

In this section, we’ll be talking about Remote Events & Remote Functions + how to secure them as much as possible.

Introduction:

So first, what are they and why do we need them?
To those of you who didn’t know, back then - before Roblox changed and updated their filterenabled system & security, exploiters could basically do any type of exploit they wanted - it was a disaster, tons of exploits that ruined some good & popular games. And that’s when Roblox have decied to add remote event and functions. This wouldn’t completely stop exploiters tho, but it SIGNIFICANTALLY changed and fixed tons of issues, including patching alot of exploits that no longer work.

Idea:

As mentioned above, the idea of using RemoteEvents and RemoteFunctions is to help us handle our game as correctly as possible, and to protect our game from being completely ruined. From the moment they were added, we now can use them to prevent exploiters from doing some crazy and weird exploits. Le’ts begin!

Remote Events

A remote event allows us to : one-way communicate across the client-server boundary. You can use it to send requests across the boundary without yielding for a response.[ Meaning: You could use these to handle things on the server / client when needed.

When can I use remote events ?
Remote events are good to use in these cases:

Client --> Server

Using this to fire an event from a certain client[player] to the server, so that everyone could see those changes. Let’s have an example:

--Local Script, StarterGui
local Replicated = game:GetService("ReplicatedStorage")
local UserInput = game:GetService("UserInputService")

local Remote = Replicated:WaitForChild("ClientServer")


UserInput.InputBegan:Connect(function(Key,IsTyping)
	if IsTyping then return end -- if he's typing in chat/anything like that.
	if Key.KeyCode == Enum.KeyCode.K then
		Remote:FireServer("string1",Color3.fromHSV(0.056, 0.501961, 1),25)
	end
end)


--Server Script
local Replicated = game:GetService("ReplicatedStorage")
local Remote = Replicated.ClientServer

Remote.OnServerEvent:Connect(function(Player,arg1,arg2,arg3) -- Player is the player who fired the remote.
	--Let's check their types, to see that an exploiter didn't provide a not matching type
	--If the types are not matching, we end the function.
	if typeof(arg1) ~= "string" and typeof(arg2) ~= "Color3" and typeof(arg3) ~= "number" then return end
	print(Player.Name.." has fired a remote!")
end)
Server --> Client
--Server Script
local Replicated = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

local Remote = Replicated.ServerClient

Players.PlayerAdded:Connect(function(Player)
	Remote:FireClient(Player,Player.Name)
end)

--Local Script, StarterPlayerScripts
local Replicated = game:GetService("ReplicatedStorage")
local Remote = Replicated:WaitForChild("ServerClient")


Remote.OnClientEvent:Connect(function(Player)
	game:GetService("StarterGui"):SetCore("ChatMakeSystemMessage",{
		Text = string.format("Hey %s , welcome to the game!",Player);
		Color = Color3.fromRGB(85, 255, 127)
	})
end)
Server --> All Clients
--Server Script
local Replicated = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

local Remote = Replicated.ServerClients

Players.PlayerAdded:Connect(function(Player)
	Remote:FireAllClients(Player.Name)
end)

--Local Script, StarterPlayerScripts
local Replicated = game:GetService("ReplicatedStorage")
local Remote = Replicated:WaitForChild("ServerClients")


Remote.OnClientEvent:Connect(function(Player)
	game:GetService("StarterGui"):SetCore("ChatMakeSystemMessage",{
		Text = string.format("%s  has joined the game!",Player);
		Color = Color3.fromRGB(255, 170, 127)
	})
end)

As you can see here, on the server side, we’re using FireAllClients() function, which would fire/ notify every client[player] in the game, about the given event/message provided / made on the client. Note: the message could’ve been made on the server and sent as the second argument within the FireAllClients().
On the client side, we use game:GetService("StarterGui"):SetCore() to create a message on chat, so that everyone in-game can see that.

Client --> Other Client

This can’t be directly done, so it has to be through the server. Here is how:
You can use FireServer() to share the server with the changes, then on the server, use FireClient() or FireAllClients() to fire the client[s] ,and then use OnClientEvent() on the client to do the stuff.

Remote Functions

A remote function , unlike remote events, allow us to two-way communicate across the client-server boundary. You can use it to send requests across the boundary and yield for a response. Here it what it means:

Player1: Invokes the server [ using InvokeServer()], then, on the server ,he returns something [ most commonly is booleans], and then - on the client, he can use that result after he assigned the InvokeServer() call as a variable, like this -local call = remote:InvokeServer(). (This is very useful when we want to make a code redeeming system, for example, or even a trade system).

When can I use remote functions?
Remote functions are good to use in these cases:

Client -- > Server
--LocalScript, under a `ScreenGui`.
local Replicated = game:GetService("ReplicatedStorage")
local Remote = Replicated:WaitForChild("ClientServer")

local Button = script.Parent.Release
local Input = script.Parent.Input
local ResultText = script.Parent.Result

Button.MouseButton1Click:Connect(function()
	local Result = Remote:InvokeServer(Input.Text)
	if Result then -- if the code was valid
		ResultText.Text = "SUCCESS" 
	else -- if the code wasnt valid
		ResultText.Text = "FALED"
	end
	task.wait(3)
	ResultText.Text = "" -- 'making the text invisible - no text'
end)

--Server Script
local Replicated = game:GetService("ReplicatedStorage")
local Remote = Replicated:WaitForChild("ClientServer")
local Codes = {
	["Test1"] = 250,
	["FREE"] = 50
}

Remote.OnServerInvoke = function(Player,Code)
	if typeof(Code) ~= "string" then return end
	print(string.format("%s has redeemed the input: %s",Player.Name,Code))
	if not Codes[Code] then return false else return true end
end
Server --> Client

Not recommended, do not try it unless you’ve a strong sanity checks that would prevent exploiters from ruining and messing up with it. These are the risks you could have with it:

1.If the client throws an error, the server throws the error too.
2.If the client disconnects while it’s being invoked, then RemoteFunction:InvokeClient() throws an error.
3.If the client doesn’t return a value, the server yields forever.

Player & Character

In this section, we’ll be talking about the Player and its ‘visual’ appearance - the Character.
We’ll talk about how they’re different, and what each has and offers, that the second - does not.

Player

The Player is an object/instance, where you can view most of the main things/properties your player/other players have in-game[ and some can actually give info from out of the game]. To be a bit more accurate, every Player object represents the Client when they’re connected to the game.

Properties

Like every other object, the Player object has properties aswell, let’s review some of them:

Character

This property is an ObjectValue, and it should represent the actual model of the player - the character [ which we can visually see in-games].

DisplayName

Obviously, this property is a String, and it should represent the DisplayName of the player.

AccountAge [Read Only]

This property is a Number , and it automatically updates the Age [in days] of the player.
NOTICE: this property is read only, meaning - you can’t modify or change that property.

Team

This property belongs to the Team class, and this allows us to know/edit and change the player’s team.The Team value itself, is an ObjectValue. And it’s supposed to represent the player’s team or nil [if the team doesnt exist/destroyed].

Events

In here, we’ll be talking about some cool and useful events the Player object has.

CharacterAdded(Character)

This event should fire every time the player’s character spawns or respawns.

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(Player)
	print(Player.Name.."- Player Instance")
	Player.CharacterAdded:Connect(function(Character)
		print(Character.Name.."- Model Instance")
	end)
end)

Chatted(Message)

This event would fire each time the player is chatting through Roblox built-in chat.

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(Player)
	Player.Chatted:Connect(function(Message)
		print(string.format("%s has said the word: %s",Player.Name,Message))
	end)
end)
Methods

In here, we’ll be talking about some useful methods you might need to know and use.

ClearCharacterAppearance()

This method would remove all accessories and objects from the player’s character.[if they are decals, accessories and clothes].

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(Player)
	print(Player.Name.."- Player Instance")
	Player.CharacterAppearanceLoaded:Connect(function(Character)
		Player:ClearCharacterAppearance()
	end)
end)

Kick(Message)

This method would kick the player from your game and show him the given message [if given], if not,t then the default Roblox message.

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(Player)
	Player:Kick("Test")
end)

Character

The Character is a Model object, which should represent the player’s character [ or any player’s character], and can also be used for making NPC’s. Every character essentially contains:
Humanoid ,HumanoidRootPart and a Head part. About other limbs - depending on what rig you’re using [R6 or R15].The character is the entity of yourself and other players in games , which allows you to do actions [ run, walk,sit, jump ,dance] and more things that can be viewed from the character prespective.

Properties

Like every other object/instance, the Character object has properties aswell, let’s review some of them.

Archivable

This property [ boolean ] would determine if the object is included in the game and can be seen when published and it also impacts to clone objects. If set to false, the object won’t be cloned. If set to true, the object will be cloned when using the Clone() method.

local newObject = Instance.new("Part")
print(newObject:Clone())  --> Part, because `Archivable` is automatically set here to true

newObject.Archivable = false

print(newObject:Clone())  --> nil

PrimaryPart

This is an ObjectValue, which refers to the PrimaryPart of your model. You should know that -
The primary part acts like the physical reference for the pivot of the model, which basically means -
The pivot will move in sync with the primary part. If the primary part is not set, the pivot will stay at the same position in world space even if parts within the model are no longer there.
It is also important to mention that when setting a primary part, that primary part has to be a descendant of that model, or else - setting that primary part will change it to nil automatically.

Events

In here, we’ll be talking about some useful events to use on our character.

AncestryChanged()

This event would run when the parent or any of its ancestors is changed. It includes 2 parameters: child and parent. Where:

child is the object whose parent was changed.
parent is the new parent of that child[object].

local Baseplate = game.Workspace.Baseplate

Baseplate.AncestryChanged:Connect(function(Child,Parent)
	print(Child.Name .. " is now a child of " .. Parent.Name)
end)
Baseplate.Parent = workspace.isModel
Methods

In this section, we’ll be learning about some cool and useful methods to use on our character.

BreakJoints()

This method will break any connection between parts in your character. Using this on your character, will kill you [ by killing your humanoid].

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(Player)
	Player.CharacterAdded:Connect(function(Char)
		task.wait(1)
		Char:BreakJoints()
	end)
end)

MoveTo()

This method will move the character/any model’s primary part to the provided position.Make sure your model always has a PrimaryPart. Because if your model doesnt have one, this would select the root part of that model as the primary part. And, since the root part is not deterministic, it is recommended to always set a primary part.

Tools, Backpack & StarterGear

In this section, we’ll be talking about tools, backpack ,startergear, and how to use and how they work.

Tools

By definition, tools on Roblox are objects which the Character[ if he has a humanoid within], can equip , unequip and activate it. Notice this pattern:
Tool is in BackpackPlayer Equips it – > Tools is now in his Character.
When you place tools in StarterPack, this would put all the given tools under the player’s Backpack folder. [From where he can equip his tools].

You notice that when you die, you lose your tools. How can you prevent this?
Simply make sure the tools are also in StarterGear, this would give you those items each time you die/reset.

On desktops,pressing a number key (1, 2, 3…) will equip the tool whose index is at that number key.
[Meaning, pressing 1 should give you the first tool, etc.]
Let’s review a quick example:

local tool = script.Parent

local function explode(point)
	local e = Instance.new("Explosion")
	e.DestroyJointRadiusPercent = 0 
	e.Position = point
	e.Parent = workspace
end

local function Activated()
	--Getting the humanoid of the tool's owner
	local human = tool.Parent.Humanoid
	--Calling the explode function
	explode(human.TargetPoint)
end

--Connecting the Activated event to the Activated function
tool.Activated:Connect(Activated)

The tool in the above example will create an explosion at the position of the tool owner.
Let’s now move onto Properties, Events and Methods.

Properties

In here, we’ll be talking about some useful properties you might need when working with tools.

CanBeDropped [ boolean ]

This property will determine if you can drop your tool [by pressing Backspace] or not.

Enabled [ boolean ]

This property will determine if you can actually use the tool or not.[ Say you wanted to remain that tool in the player’s backpack, but only preventing him from using it].
When set to true, the player can use the tool. When set to false, the tool is disabled and the player cannot use it. This would also prevent any Activation / Deactivation events from happening, since you aren’t able to use the tool if set to false.

RequiresHandle [ boolean ]

This property determines if your tool can work without the need of a handle.
[Meaning that if your tool doesnt have a handle, and that property is set to false, then you could still activate your tool and do stuff].

Events

In here, we’ll be talking about some useful events on tools.

Activated

This event runs whenever the player clicks while equipping a tool.
[Do not get confused with the method Activate().]

local Tool = script.Parent

Tool.Activated:Connect(function()
	print(string.format("%s was activated!",Tool.Name))
end)

Equipped

This event runs whenever the player equips a tool.

local Tool = script.Parent

Tool.Equipped:Connect(function()
	print(string.format("%s was equipped!",Tool.Name))
end)
Methods

In this section, we’ll be learning about some useful methods to do with tools.

ClearAllChildren()

This method simply clears every child / descendant of the given object.
Notice that if you’re wishing to not clear completely all children, you could use a for loop + an if statement to check the class of the children , etc.

Gamepasses & DevProducts

In this category, we’ll be trying to understand the ideas behind gamepasses and devproducts, and what they do.Before we dive into that, let’s first explain what service they stand behind.
As you might know, each service in Roblox Studio has different types of tasks to do/get.
And obviously, not all services are shown in the Explorer.

In this part, we’ll be using the Marketplace Service.
MarketplaceService allows us to configure and work with in-game transactions, use its methods to fetch information about developer products and gamepasses, and more assets.

It has many many events, as well as methods. We’ll be talking about some prominent ones.

Events

Here,we’ll be talking about some very useful events to work with MarketplaceService.

PromptGamePassPurchaseFinished

This event would run whenever the purchase dialog of a game pass is closed.Meaning whenever the player presses either ‘OK’ or ‘Cancel’.

It contains 3 parameters:

player[instance]: the player object whom got the prompt.
gamePassId[number]: the id of our gamepass.
wasPurchased[boolean]: checks if it was purchased or not.

--Defining Services
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")

--Making a Function
local function gamepassPurchaseFinished(player,id,purchased)
	print(player,id,purchased)
	print("PromptGamePassPurchaseFinished", player,id,purchased)
end

MarketplaceService.PromptGamePassPurchaseFinished:Connect(gamepassPurchaseFinished)

task.wait(5)
--Prompting a Gamepass Purchase for the testing
MarketplaceService:PromptGamePassPurchase(Players.LocalPlayer,87186006)

--In this case, we got:
--[[
 	PromptGamePassPurchaseFinished Valkyrop 87186006 false
]]

Notice that we got false here, because I already own this gamepass.

PromptPremiumPurchaseFinished

Fires whenever the premium purchase modal closes[ meaning ‘Cancel’ or ‘OK’ buttons].

--Defining Services
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")

MarketplaceService.PromptPremiumPurchaseFinished:Connect(function()
	print("Player either closed or purchased premium!")
end)

task.wait(5)
--Prompting a Gamepass Purchase for the testing
MarketplaceService:PromptPremiumPurchase(Players.LocalPlayer)
Methods

In this section, we’ll be learning about some useful methods.

PromptGamePassPurchase()

This method prompts the given player, the given gamePassID.

--Defining Services
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local GamepassID = 000000000 -- change it to your gamepass ID

--Prompting a Gamepass Purchase for the testing
MarketplaceService:PromptGamePassPurchase(Players.LocalPlayer,GamepassID)

PromptPremiumPurchase()

This method simply prompts the player to buy/get premium from the game.[Only parameter is the player whom this will be shown to].

GetDeveloperProductsAsync()

This method returns pages/lists of all current DevProducts the game has.

local MarketplaceService = game:GetService("MarketplaceService")
local developerProducts = MarketplaceService:GetDeveloperProductsAsync():GetCurrentPage()


for _, devProduct in pairs(developerProducts) do
	for index, value in pairs(devProduct) do
		print(index .. ": " .. value)
	end
	print(" ")
end

--Result:
--[[
 DeveloperProductId: 16344291
 displayName: Developer Product 1 
 Name: Developer Product 1
 ProductId: 1316305655
 PriceInRobux: 25
]]

GetProductInfo()

This method returns information about an asset,dev product or even a gamepass.
You should provide the assetID + assetType, meaning:

local success,result = pcall(function()
    return MarketService:GetProductInfo(87186006,Enum.InfoType.GamePass)
end)
ClickDetectors & ProximityPrompts

In this section, we’ll be learning about ClickDetectors and ProximityPrompts.

Introduction:

So, before we dive into it. Let’s first understand what they are and what they do.

ClickDetectors:allow us receive pointer input on 3D objects through their MouseClick event, meaning - lets us click on objects with our cursor, and do lots of stuff. They only work if they’re parented to:
BasePart, Model or Folder's. Here is a very simple example:

--Assuming you have this script under a clickdetector which is under a part.
script.Parent.MouseClick:Connect(function()
	print("Someone has clicked on me!")
end)

ProximityPrompts: unlike ClickDetectors, ProximityPrompts are visualized gui that appears each time the player approaches to objects, within a certain range of a distance.
Here is a simple example:

--Assuming you have this script under a ProximityPrompt which is under a Part
script.Parent.Triggered:Connect(function()
	print("Someone has pressed this Prompt!")
end)
ClickDetectors

So after that introduction, let’s begin by learning some of its properties and events.

Properties

CursorIcon[Content]

This property allows you to change the icon of your cursor.

MaxActivationDistance[number]

This property tells you from what distance you’re able to click and activate that clickdetector.

Events

MouseClick

This event fires everytime a player presses and releases the left mouse button while the cursor is hovering over a model or any basepart with a clickdetector.Also, it’s important for the player’s character to be within the MaxActivationDistance, in order to activate it.

local clickDetector = script.Parent:FindFirstChild("ClickDetector")

clickDetector.MouseClick:Connect(function(Player) -- Player is a parameter for the player who clicked on it
	print(string.format("%s has pressed on me!",Player.Name))
end)

MouseHoverEnter

This event runs whenever the player begins to hover his cursor over the ClickDetector's parent.[Can be used in both Script and LocalScript].

local clickDetector = script.Parent:FindFirstChild("ClickDetector")

clickDetector.MouseHoverEnter:Connect(function(Player) -- Player is a parameter for the player who clicked on it
	print(string.format("%s has hovered his cursor!",Player.Name))
end)
ProximityPrompts

So after that introduction, let’s begin by learning some of its properties and events.

Properties

ActionText[string]

This property is where the text you’ll see on your prompt, like this:
image

HoldDuration[float]

This would determine how long the player would have to hold the prompt.

MaxActivationDistance[float]

This would help you determine from what distance the player can activate the prompt.

Events

Triggered

This event runs whenever the player has done clicking/holding the prompt [and finished it].

script.Parent.Triggered:Connect(function()
	print("Prompt has been triggered!")
	game.Workspace.Baseplate.Size = Vector3.new(4,4,4)
end)

PromptButtonHoldBegan

This event runs whenever the prompt is being held by the player[make sure HoldDuration is > 0].

script.Parent.PromptButtonHoldBegan:Connect(function()
	print("Prompt triggering has begun")
end)

TweenService

In this section, we’ll be learning about TweenService, what it does and how to use it.

Introduction:

Tweens are used to interpolate the properties of instances. Meaning, to edit,modify and change them in style/animation.Notice! Only the following types can be used in TweenService:
image.

To start using this server and its features, you should use the main function : TweenService:Create(), which takes information about the object and acts accordingly when playing the tween.

NOTES:
1.You can tween multiple properties at the same time.
2.If you’re trying to tween the same properties at the same time, only the last one of those properties would tween.

Examples

1.Tweening part size
local tweenService = game:GetService("TweenService")
local Part= script.Parent
local tweenInfo = TweenInfo.new(
	2, -- Time
	Enum.EasingStyle.Linear, --Style
	Enum.EasingDirection.Out, -- Direction
	-1, --RepeatCount.[if it's <0 this would loop forever]
	true, -- Reverse
	0 -- daly
)
local Goal = { -- properties to change
	Size = Vector3.new(10,10,10)
}
local PartTween = tweenService:Create(Part,tweenInfo,Goal) -- preparing the animation
PartTween:Play() -- playing the tween

task.wait(7) -- delay
PartTween:Cancel() -- this will stop the tweening
2. Tweening part size and Color
local tweenService = game:GetService("TweenService")
local Part= script.Parent
local tweenInfo = TweenInfo.new(
	2, -- Time
	Enum.EasingStyle.Linear, --Style
	Enum.EasingDirection.Out, -- Direction
	-1, --RepeatCount.[if it's <0 this would loop forever]
	true, -- Reverse
	0 -- daly
)
local Goal = {
	Size = Vector3.new(10,10,10),
	Color = Color3.fromRGB(0, 85, 255)
}
local PartTween = tweenService:Create(Part,tweenInfo,Goal)
PartTween:Play()

task.wait(7)
PartTween:Cancel()
--Change the part color to 'Really Red' to see the efffect.
Tweening a Door Spin
local tweenService = game:GetService("TweenService")
local Door= script.Parent
local tweenInfo = TweenInfo.new(
	2, -- Time
	Enum.EasingStyle.Linear, --Style
	Enum.EasingDirection.Out, -- Direction
	-1, --RepeatCount.[if it's <0 this would loop forever]
	false, -- Reverse
	0 -- daly
)
local Goal = {
	CFrame = Door.CFrame * CFrame.Angles(0,math.rad(180),0),
}

local Tween = tweenService:Create(Door,tweenInfo,Goal)

Tween:Play()
Camera

In this section, we’ll be learning about Camera ; what it is , and what it does.

Introduction:

Camera on Roblox is a special object which lets us define and view the world from a 3D prespective.
Every time a client[player] joins the game, he has his own camera object.
We can’t access others camera through the server,only on the client, and access ours only. To access/find the camera object, we use Workspace.CurrentCamera.

The Camera object has many important proprties, however - only 5 of them are more important than others, and these are:

[Camera.CFrame]: Simply represents the position and rotation of the camera.
[Camera.Focus](CFrame): Simply sets the focus of the camera to the given CFrame, it is the point where the camera is looking.
[Camera.CameraType]: Determines how will the camera update every frame.
[Camera.CameraSubject]: Determines what object should the camera follow.
[Camera.FieldOfView]: Determines the observable world through the camera field of view.
The bigger the number, the further the field of view is.

Examples:

Switching Camera Objects
--Variables
local camera = workspace.CurrentCamera
local players = game:GetService("Players")

local player = players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()

--Making the camera scriptable, so we could apply our changes
camera.CameraType = Enum.CameraType.Scriptable


--Variables
local bb = script.Parent.BlueBrick
local door = script.Parent.Door
local you = script.Parent.You

bb.MouseButton1Click:Connect(function()
	camera.CameraSubject = game.Workspace.BlueBrick
end)

you.MouseButton1Click:Connect(function()
	camera.CameraSubject = char.Humanoid or char:WaitForChild("char")
end)

door.MouseButton1Click:Connect(function()
	camera.CameraSubject = game.Workspace.Door
end)
Spectate Players Button
--Variables
local camera = workspace.CurrentCamera
local playersSerivce = game:GetService("Players")

local player = playersSerivce.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()

local toggle = script.Parent.Spectate
local frame = script.Parent.ViewingPlayers
local previous = frame.Previous
local next = frame.Next

--This would help us counting [down/up] when we press previous/next, and get the players.
local countingPlayers = 1 

toggle.MouseButton1Click:Connect(function()
	frame.Visible = not frame.Visible
	frame.PlayerName.Text = player.Name
	camera.CameraSubject = char
end)

previous.MouseButton1Click:Connect(function()
	local players = #playersSerivce:GetPlayers()
	countingPlayers -= 1
	if countingPlayers < 1 then
		countingPlayers = players
	end
	local realPlayer = playersSerivce:GetPlayers()[countingPlayers]
	camera.CameraSubject = realPlayer.Character.Humanoid
	frame.PlayerName.Text = realPlayer.Name
end)

next.MouseButton1Click:Connect(function()
	local players = #playersSerivce:GetPlayers()
	countingPlayers += 1
	if countingPlayers > players then
		countingPlayers = 1
	end
	local realPlayer = playersSerivce:GetPlayers()[countingPlayers]
	camera.CameraSubject = realPlayer.Character.Humanoid
	frame.PlayerName.Text = realPlayer.Name
end)
Humanoid/Tools Animation

In this section, we’ll be learning how to apply animations onto tools/player’s character.
When we talk about Animation here, we talk about loading custom/built in movements/actions for our tools/humanoid actions.When you’re testing in studio, you can view under your humanoid, there is an object named Animator. The Animator is the main object that is responsible for the animations you have in your game. There are 2 ways to create this object:
1.Humanoid:LoadAnimation().
2.AnimationController:LoadAnimation().

Important notes:

For animation replication to function it is important for the Animator to be first created on the server.

The Animator object must be initially created on the server and replicated to others for animation replication in order to be shown to all. If the Animator is created locally, then any animation loaded through this animator, won’t replicate to server.

Loading Animation:

You’ll need to use the LoadAnimation() method ,and provide an Animation object [NOT its animationID]. An example:

local UIS = game:GetService('UserInputService')
local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local Anim = Instance.new('Animation')
Anim.AnimationId = 'rbxassetid://10910827063'

--Start Running Animation
UIS.InputBegan:connect(function(input,processed)
	if processed then return end
	if input.KeyCode == Enum.KeyCode.LeftShift then
		Humanoid.WalkSpeed = 24
		PlayAnim = Humanoid:LoadAnimation(Anim)
		PlayAnim:Play()
 	end
end)

--Stop Running Animation
UIS.InputEnded:connect(function(input)
 	if input.KeyCode == Enum.KeyCode.LeftShift then
		Humanoid.WalkSpeed = 16
		if PlayAnim then
			PlayAnim:Stop()
			PlayAnim:Destroy()
		end
 	end
end)
Mouse & UserInputService

In this section, we’ll be learning about Mouse and UserInputService ; what they are and what they do.

Introduction:

Mouse:
Simply our cursor. We can get the Mouse in this way:

--Local script
local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local Mouse = Player:GetMouse()

Notice:

Although Mouse is deprecated [UserInputService and ContextActionService are its replacement],
it is still supported and can be used.

Properties

Hit(CFrame)

This property returns the mouse’s position in the 3D space which we work with in studio.

Target(BasePart)

This property returns the 3D object which the mouse is pointing to.
Notice: if you set Mouse.TargetFilter, then all the provided objects within the filter would be ignored.

Events

Move

This event fires whenever the mouse is moved.[Only when the mouse’s position is updated/changed].

local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local Mouse = Player:GetMouse()

Mouse.Move:Connect(function()
	local Target = Mouse.Target
	print(Target) -- would print nil if pointed to sky
end)

UserInputService:
Simply a service used to detect and capture the different types of input available on a user’s device.[Console, Mobile, PC, etc].
Basically, the main purpose of this service is to provide the best experience possible to all possible devices.

Notice:

This service is client-sided only. Meaning, it can only be used on the client. Which obviously means - you can only use it in LocalScript's or in ModuleScript's required by localscripts.

Properties

MouseEnabled[boolean]

This property checks if the player’s device has a mouse.[ and returns true if found], if not found - it returns false.

TouchEnabled[boolean]

Simply checks if the player’s device has any available touch screen.
If there is a touch screen found, you could use UserInputService - TouchEnded/TouchStarted events to operate accordingly and detect their behavior on their device.

VREnabled[boolean]

Simply checks if the player is using a VR device. If a VR device was found, you could use some events such as UserInputService:GetUserCFrame() to do some cool stuff with it.

Events

InputBegan

This event would run whenever a player begins interacting with one of the following devices [ pc,mobile,console,vr,etc].

local UserInputService = game:GetService("UserInputService")

UserInputService.InputBegan:Connect(function(Key,Processed)
	if Processed then return end -- if I am during chatting, then end the function.
	print(Key.KeyCode.Name) -- would print the name of the pressed key.
end)

InputChanged

This would fire everytime the player is changing their interaction type [ for example: Mouse button down].

local UserInputService = game:GetService("UserInputService")

UserInputService.InputChanged:Connect(function(Key,Processed)
	if Processed then return end -- if I am during chatting, then end the function.
	if Key.UserInputType == Enum.UserInputType.MouseMovement then
		print("The Mouse has been moved!")
	end
end)

Here is Part2, since I couldnt fit it in the original post because of a limit.

52 Likes

Thank you! I was having a bit of trouble learning UserInputService

5 Likes

Hello, I just read your tutorial and it’s 65% better than all the tutorials I’ve seen.

You provided an explanation on what each thing does and put it in very specific words, although my brain is really bad at understanding just looking at words, but definitely very useful!

11 Likes

Do you give out paid tutorials?

1 Like

can you add an option to the poll saying its the worst reading experience i ever had in my life

3 Likes

No, sorry
I don’t have time for it

but I hope this somehow helped you :wink:
best of luck!

1 Like

Thank you so much for writing this. I have used other programming languages and I’m working to get into Lua. Knowing how things are formatted with Lua has helped me a lot!

1 Like