mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-24 15:01:38 +00:00
rules
This commit is contained in:
parent
a9b4f8e83b
commit
e6efc04756
8494 changed files with 495610 additions and 0 deletions
|
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
title: Coding fundamentals
|
||||
description: Teaches the basics of coding with Luau.
|
||||
next: /tutorials/fundamentals/coding-1/landing
|
||||
---
|
||||
|
||||
### Series description
|
||||
|
||||
Start coding on Roblox with this easy-to-follow series covering the fundamentals of how to use the programming language Luau. These courses are perfect for those new to coding or just starting with Luau. Each course centers around a foundational computer science principle, and features individual lessons with step-by-step tutorials you can use to create your own experiences on Roblox.
|
||||
|
||||
Before beginning this course, the reader should have basic knowledge of Roblox Studio, as demonstrated in the [Studio](../../curriculums/studio/index.md) and [Building](../../curriculums/building/index.md) lesson.
|
||||
|
||||
### Series contents
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Series</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[Variables and objects](landing.md)</td>
|
||||
<td> Create your first script and start making things happen with code. These tutorials cover variables, data types, and properties.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Functions and events](../coding-2/functions-and-events.md)</td>
|
||||
<td>Use functions to create chunks of code that run only when you tell it. Connect your code to in-world events to create interactive objects like traps or bridges.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Conditionals](../coding-3/landing.md)</td>
|
||||
<td>Conditionals use the coding pattern of "if this happens then do that." Apply this pattern to check if the time is right to unlock power ups for your players.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Loops](../coding-4/landing.md)</td>
|
||||
<td>Learn how to repeat code a certain amount of time or make it run forever using for and while loops. Practice using these loop types to code timed bridges and flashing lights.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Dictionaries and arrays](../coding-5/landing.md)</td>
|
||||
<td>Learn how to store a lot of data in a single variable using tables and arrays. Data structures such as these can store large data sets like a player's inventory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Organize code](../coding-6/landing.md)</td>
|
||||
<td>Take your code organization a step further and learn about module scripts, a unique type of script that can interact with other scripts in Luau.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
---
|
||||
title: Create a script
|
||||
description: Learn how to create a script in Roblox Studio using Luau. Great for beginners interested in coding or computer science on Roblox.
|
||||
next: /tutorials/fundamentals/coding-1/object-properties
|
||||
prev: /tutorials/fundamentals/coding-1/landing
|
||||
---
|
||||
|
||||
**Coding** is the process of creating instructions for computers to follow. Just like people use different languages, such as English and Spanish, so do programs. Roblox uses the coding language **Luau**.
|
||||
|
||||
This article will cover how to start coding in Roblox, introducing common concepts like scripts, data types, and variables. By the end, you'll be able to type out code that displays messages in Roblox Studio.
|
||||
|
||||
## Code with scripts
|
||||
|
||||
In Roblox Studio, lines of Luau code are held in **scripts**. These scripts give the experience sets of instructions on how to give players health points, create a rain of fireballs, or anything else imaginable.
|
||||
|
||||
### Create a script
|
||||
|
||||
Scripts are commonly created in **ServerScriptService**, a special folder made just for holding scripts.
|
||||
|
||||
1. In Explorer, hover over **ServerScriptService** to see the **+** button.
|
||||
<img src="../../../assets/education/coding-1/hover-over-serverscriptservice_400x400.png" width="40%" />
|
||||
|
||||
2. Click the **+** button and select **Script**. A new script will be created and the script editor will open.
|
||||
|
||||
3. Right-click Script and select **Rename**. Name the script _PracticeScript_. Naming scripts helps you and any teammates remember what each script does.
|
||||
|
||||
### Hello world
|
||||
|
||||
New scripts include a print function at the top of the script editor. **Print functions** display text on the screen. It's one of the first functions many people learn, and you'll use it often. This code will make "Hello world!" appear on the screen.
|
||||
|
||||
```lua title = 'Default code'
|
||||
print("Hello world!")
|
||||
```
|
||||
|
||||
To find the script next time you open up Roblox Studio, click on the name of the script above the 3D viewport, or double-click the script's name in Explorer.
|
||||
|
||||
### Test output
|
||||
|
||||
You can see the result of running the default code with the **Output** window. If you've never used it before, you'll need to enable it.
|
||||
|
||||
1. From Studio's Window menu, open the [Output](../../../studio/output.md) window.
|
||||
2. To test the script, [initiate a playtest](../../../studio/testing-modes.md#playtesting). `Hello world!` will show up in the output.
|
||||
|
||||
<img src="../../../assets/education/coding-1/helloworld-output_800x150.png" width="80%"/>
|
||||
|
||||
3. Click **Stop** to end the playtest. You can now return to the **Script** tab.
|
||||
|
||||
## Identify data types
|
||||
|
||||
Coding languages classify different kinds of values into **data types**. For example, one data type is a **number**. Number data types are self-explanatory as they are made up of only numbers.
|
||||
|
||||
Another data type is a **string**. Strings can hold numbers, letters, and characters. Take another look at the default code in the new script; the words and quotations within the parenthesis is an example of a **string** data type.
|
||||
|
||||
```lua title = 'Default code'
|
||||
print("Hello world!")
|
||||
```
|
||||
|
||||
Strings like `"Hello World"` always sit inside quotation marks, `"like this"`. More examples of strings are below. Notice how they hold a mix of letters and numbers.
|
||||
|
||||
- `"You just joined the game!"`
|
||||
- `"There are 50 players left"`
|
||||
- `"10"`
|
||||
|
||||
## Create variables
|
||||
|
||||
**Variables** are containers for information the program can use and change, like player names or points.
|
||||
|
||||
**Declaring** a variable is what coders call the process of creating a new variable. In Luau, to declare a new variable, type `local`, then type the name for the new variable. A variable that can hold a player name might look like: `local playerName`
|
||||
|
||||
<Alert severity="info">
|
||||
When declaring new variables, some coding languages require that you also state what data type the variable can use. For example, a variable in Java would be `String name = "Pavel"`. Luau only requires a name.
|
||||
</Alert>
|
||||
|
||||
In Luau, variables can be global or local. You'll usually use **local** variables. Local variables can only be used within the script or chunk of code where they were created. Global variables can potentially be used by other scripts, but too many global variables can make your experience slow and unresponsive. It's better to stay in the habit of making variables local unless necessary.
|
||||
|
||||
### Use variables and strings together
|
||||
|
||||
Time to declare your own variables. These steps will use a string to store the name of your favorite animal.
|
||||
|
||||
1. Delete `print("Hello world!")`. It's best practice not to leave unnecessary code in your scripts.
|
||||
|
||||
2. Declare a new variable by first typing `local`, then naming the variable `myAnimal`.
|
||||
|
||||
```lua title = 'Declares a new variable'
|
||||
local myAnimal
|
||||
```
|
||||
|
||||
<Alert severity='warning'>
|
||||
Variable names can't include spaces. Be careful not to include spaces or the code won't work as intended.
|
||||
</Alert>
|
||||
|
||||
### Name variables
|
||||
|
||||
Variables can be named anything, but good names will always describe their purpose. Generic names make your code difficult to read and update later. Coders will also use different capitalization styles to remind themselves how the variable is used within the script. A good default style is **camelCase**.
|
||||
|
||||
To write in camelCase:
|
||||
|
||||
- Begin with a lowercase letter
|
||||
- Leave out spaces
|
||||
- Capitalize additional words
|
||||
|
||||
Good Variable Names
|
||||
|
||||
- `playerPoints`
|
||||
- `numberStorageArray`
|
||||
|
||||
Bad Variable Names
|
||||
|
||||
- `myVariable` - Doesn't describe the purpose of the variable
|
||||
- `player name` - The included space will cause issues
|
||||
|
||||
### Assign values to variables
|
||||
|
||||
New variables are empty. To **assign** it a value, or put something inside its container, use the `=` symbol. In this case, assign the variable the name of your favorite animal.
|
||||
|
||||
1. After the variable name, type `=`.
|
||||
|
||||
```lua title = 'Equal assigns values'
|
||||
local myAnimal =
|
||||
```
|
||||
|
||||
2. On the same line, type a string that contains your favorite animal. Remember the quotation marks.
|
||||
|
||||
```lua title = 'Assigns "Porcupines" to myAnimal'
|
||||
local myAnimal = "Porcupines"
|
||||
```
|
||||
|
||||
### Use print() for your own messages
|
||||
|
||||
Print functions display text on the screen, as you saw earlier. It's one of the first functions many people learn since it's a simple way of giving the script a command. To see your variable, use the `Global.LuaGlobals.print()` function.
|
||||
|
||||
1. On a new line, type `print()`.
|
||||
|
||||
```lua title = 'Adds empty print()'
|
||||
local myAnimal = "Porcupines"
|
||||
print()
|
||||
```
|
||||
|
||||
2. Type the name of your variable within the parenthesis.
|
||||
|
||||
```lua title = 'Outputs "Porcupines"'
|
||||
local myAnimal = "Porcupines"
|
||||
print(myAnimal)
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
If you see a red error in the output editor, it's like there's an error in the code. Each error has a unique way of describing itself. Try and use the information from the error to fix your code.
|
||||
</Alert>
|
||||
|
||||
3. Test your code with the play button. You should see the name of your animal in the Output window.
|
||||
|
||||
### Combine strings
|
||||
|
||||
You can display any string in the Output using `print()`; you can even print multiple strings stored within variables or typed directly within the function. **Concatenation** is combining strings. To concatenate the string assigned to your variable and a second string, use two dots `..` The following example concatenates two variables and two typed strings.
|
||||
|
||||
```lua title = 'Uses variables and strings together'
|
||||
|
||||
local firstAnimal = "porcupines"
|
||||
local secondAnimal = "dolphins"
|
||||
|
||||
print("I like " .. firstAnimal .. " and " .. secondAnimal)
|
||||
```
|
||||
|
||||
Play around with printing different combinations of strings.
|
||||
|
||||
## Summary
|
||||
|
||||
New scripts can be created by clicking the + button next to the name of an object. ServerScriptService is a common place to create new scripts. New scripts include the default code `print("Hello world!")`. This code will display `Hello world!` in the Output window, where you can see the results of your code and if any errors have occurred.
|
||||
|
||||
"Hello world!" is an example of a string data type. Strings can include any combination of characters that you might type on your keyboard. Concatenation is when multiple strings are combined.
|
||||
|
||||
Variables are containers that can be assigned to hold different data types, such as strings and numbers.
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
title: Variables and objects
|
||||
description: Learn how to start coding in Roblox Studio in this tutorial series.
|
||||
next: /tutorials/fundamentals/coding-1/create-a-script
|
||||
prev: /tutorials/fundamentals/coding-1/coding-fundamentals
|
||||
---
|
||||
|
||||
### Series description
|
||||
|
||||
For anyone interested in learning computer science or coding, this serves as a foundational series. This series is recommended for anyone interested in taking other coding lessons in Roblox Studio.
|
||||
|
||||
### Objectives and prerequisites
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="20%"><b>Learning objectives</b></td>
|
||||
<td>
|
||||
Understand the process of scripting, such as creating scripts and being able to identify interface elements like the Output window.
|
||||
|
||||
Utilize data types, and variables use strings to print messages to the Output window and change object properties.
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Prerequisites</b></td>
|
||||
<td>
|
||||
Basic knowledge of how to create and manipulate parts in Roblox Studio.
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Series contents
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Article</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="create-a-script.md">Create a script</a></td>
|
||||
<td>Learn how to create new script objects and print messages to the Output window.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="object-properties.md">Object properties</a></td>
|
||||
<td>Change the color of a part using just code</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="parents-and-children.md">Parents and children</a></td>
|
||||
<td>Instead of calling out a specific part name, learn how to navigate the hierarchy to make code that will work for any part</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
---
|
||||
title: Object properties
|
||||
description: Learn how to use Luau to change the appearance properties of different objects, such as color and shape.
|
||||
next: /tutorials/fundamentals/coding-1/parents-and-children
|
||||
prev: /tutorials/fundamentals/coding-1/create-a-script
|
||||
---
|
||||
|
||||
**Properties** control how objects look and function. Each object in Roblox Studio has its own set of properties. For example, a part object has color, size, and shape properties. Properties can be changed in the Properties window or through code.
|
||||
|
||||
To learn about properties, you'll explore common properties found in parts and then write a script to change part colors.
|
||||
|
||||
## The Properties window
|
||||
|
||||
The **Properties** window can be used to learn about an object's properties. Use it to take a look at a part's properties.
|
||||
|
||||
1. Select a part.
|
||||
|
||||
2. In the **Properties** Window on the bottom-right, look at the different properties that can be changed, like color, size, material and transparency. You can also change most properties in this window from within a script.
|
||||
|
||||
<img src="../../../assets/education/coding-1/part-properties_400.png" width="40%" />
|
||||
|
||||
## Add comments to scripts
|
||||
|
||||
Comments are special lines starting with `--` that help coders remember what parts of scripts do. Unlike other code, comments don't run; they're just there so you can leave notes to yourself and other programmers. This script will change a part's `Class.BasePart.Color|Color` property at the start of the experience.
|
||||
|
||||
1. Select an existing part or create a new one. Rename the part PracticePart.
|
||||
|
||||
2. In **ServerScriptService**, create a new script named ChangeColor.
|
||||
|
||||
3. In the script, delete the default code. Then, write a **comment** by typing `--` and a brief description of what the script will do.
|
||||
|
||||
```lua title = 'Describes what the script does'
|
||||
-- Changes the color of a part
|
||||
```
|
||||
|
||||
### Locate the part
|
||||
|
||||
To make changes to a part, you must be able to describe the part's location. The Explorer is an excellent tool for **referencing** locations. In this case, **PracticePart** is under **Workspace**.
|
||||
|
||||
<img src="../../../assets/education/coding-1/practice-part_400.png" width="40%" />
|
||||
|
||||
Now that you know where the part is, the part's location needs to be translated into something a script can understand.
|
||||
|
||||
1. Under the comment, type `workspace.PracticePart`.
|
||||
|
||||
```lua title = 'References PracticePart in Workspace'
|
||||
-- Changes the color of a part
|
||||
workspace.PracticePart
|
||||
```
|
||||
|
||||
### Change a property with code
|
||||
|
||||
You'll use an RGB value to change the part's color. Computers use **RGB values**, the combination of red, green, and blue, to create all the colors on your screen.
|
||||
|
||||
RGB values use three numbers from 0 to 255, separated by commas. For example, black is `(0, 0, 0)` while white is `(255, 255, 255)`.
|
||||
|
||||
For the part, the script will change its Color property to a new Color3, a data type that stores colors.
|
||||
|
||||
1. After `PracticePart`, type `.Color` to access the Color property.
|
||||
|
||||
```lua title = 'Accesses the Color property'
|
||||
-- Changes the color of a part
|
||||
workspace.PracticePart.Color
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
Roblox will autocomplete words as you type to help speed up the coding process. You can use the arrow keys to move down the list when the words appear. Pick an option by pressing <kbd>Enter</kbd>.
|
||||
</Alert>
|
||||
|
||||
2. Next, type `= Color3.fromRGB()` This code will allow you to assign a new color.
|
||||
|
||||
```lua title = 'Uses Color3.fromRGB()'
|
||||
-- Changes the color of a part
|
||||
workspace.PracticePart.Color = Color3.fromRGB()
|
||||
```
|
||||
|
||||
3. RGB color values can be manually typed inside the parentheses, but using the color picker is easier. Click **inside** the parentheses, and then click the color wheel. Follow the popup to create a color.
|
||||
|
||||
<img src="../../../assets/education/coding-1/color-picker_800x140.png" width="80%" />
|
||||
|
||||
Your code should look similar to the code below.
|
||||
|
||||
```lua title="Updates the color of PracticePart"
|
||||
-- Changes the color of a part
|
||||
workspace.PracticePart.Color = Color3.fromRGB(255, 230, 50)
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
If you want to type an RGB value manually, make sure each number is between 0 to 255 and separated by commas, such as (10, 50, 10).
|
||||
</Alert>
|
||||
|
||||
4. [Initiate a playtest](../../../studio/testing-modes.md#playtesting) to test that your part changes color.
|
||||
|
||||
## Summary
|
||||
|
||||
All objects have properties. Parts have properties like color and transparency. At the same time, other object types have their unique properties.
|
||||
|
||||
To change the color of a part, you need to be able to describe where to find it. If the part is in Workspace, use the keyword `workspace`. Then use dot operators to state the desired part and access its properties.
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
title: Parents and children
|
||||
description: Practice navigating object hierarchies instead of using specific names in your code.
|
||||
next: /tutorials/fundamentals/coding-2/functions-and-events
|
||||
prev: /tutorials/fundamentals/coding-1/object-properties
|
||||
---
|
||||
|
||||
Instead of running scripts from ServerScriptService, you may want to attach a script to the part. For instance, using a script to turn a part into a trap or make a part give the player points when they touch it. By understanding how scripts and parts are related in the hierarchy, you can create a script that works automatically without naming which part to use.
|
||||
|
||||
To do this, you must understand **parent and child relationships**.
|
||||
|
||||
Parents and children are ways to describe the hierarchy between different objects. Anytime you've added a new part to Workspace, Workspace has been the parent object, and the part became a child object. When you added a script to ServerScriptService, ServerScriptService was the parent, and the script was a new child.
|
||||
|
||||
## Set up the project and script
|
||||
|
||||
To demonstrate parent and child relationships, you'll start with a single part that changes colors and then duplicate the script across multiple parts.
|
||||
|
||||
1. Create a new part and rename it. This lesson will use ColorPart.
|
||||
|
||||
2. Right-click the **part** and select **Insert Object** ⟩ **New Script**. Rename the script **ColorChanger**.
|
||||
<img src="../../../assets/education/coding-1/color-changer_400x216.png" width="40%" />
|
||||
|
||||
3. Copy and paste the code below into **ColorChanger**. This version of the code is the same that you used before. It assigns a specific part to a variable.
|
||||
|
||||
```lua title="Changes the color of ColorPart"
|
||||
local Workspace = game:GetService("Workspace")
|
||||
|
||||
local colorPart = Workspace.ColorPart
|
||||
colorPart.Color = Color3.fromRGB(50, 240, 255)
|
||||
```
|
||||
|
||||
4. Test and check that the part changes color as desired.
|
||||
|
||||
## Parent and child relationships
|
||||
|
||||
A **parent** is anything with objects, like scripts or parts, attached below it. Anything under the parent is its **children**. In the example below, ColorPart is the parent, and ColorChanger is the child.
|
||||
|
||||
<img src="../../../assets/education/coding-1/color-changer_400x216.png" width="40%" />
|
||||
|
||||
With the current script, you can only change the color of a **single part** named ColorPart. To change any part's color, you can design the code to work on the script's parent object, whatever it happens to be named. The code `script.Parent`, will go up the hierarchy and find the object the script is attached to.
|
||||
|
||||
### Use script.Parent
|
||||
|
||||
`script.Parent` can be assigned to a variable like any other value with the `=` symbol.
|
||||
|
||||
1. In the script, replace the named part with `script.Parent`. Check your code below.
|
||||
|
||||
```lua title="Changes the color of the parent object"
|
||||
local colorPart = script.Parent
|
||||
colorPart.Color = Color3.fromRGB(50, 240, 255)
|
||||
```
|
||||
|
||||
### Test reusable parts
|
||||
|
||||
Now that the variable will refer to whatever part the script is attached to, you can make as many copies as you want.
|
||||
|
||||
1. Right-click on the color part and select Duplicate, or use the hot-key <kbd>Ctrl</kbd><kbd>D</kbd> (<kbd>⌘</kbd><kbd>D</kbd>). Create at least three total parts.
|
||||
|
||||
2. Run the experience to check that all parts change color.
|
||||
<video controls src="../../../assets/education/coding-1/scriptParent_finalExample_web.mp4" width="80%"></video>
|
||||
|
||||
## Summary
|
||||
|
||||
Instead of always directly referencing parts by name and location, script.Parent can be used as an alternative. That code will grab the parent, or object, that the script is attached to, thus letting the script make modifications to it. Using code such as `script.Parent` will come in handy to make your code reusable. One drawback to remember is that you now have multiple scripts that require updating if you want to change the code.
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
---
|
||||
title: Code a function
|
||||
description: What a function is, and how to code a function in Luau
|
||||
next: /tutorials/fundamentals/coding-2/use-parameters-and-events
|
||||
prev: /tutorials/fundamentals/coding-1/parents-and-children
|
||||
---
|
||||
|
||||
**Functions** are sets of instructions that can be used many times in a script. There are pre-made functions (also called methods) like `print()` and `Library.task.wait()` that are built into most programming languages. Coders can also create their own custom functions for code they want to use more than once, but don't feel like writing over and over. In Luau, this is done by typing:
|
||||
`local function nameOfTheFunction()`
|
||||
|
||||
Functions can be thought of like a recipe. They're both lists of specific instructions. For example, you could use a function to teach a robot how to make spaghetti. First, make a `local function` that lists the steps to prep the meal. Then, whenever you want dinner, just say, "Robot, run makeSpaghetti()".
|
||||
|
||||
The steps to make dinner might look like this:
|
||||
|
||||
1. Boil water
|
||||
2. Add pasta
|
||||
3. Cook 15 minutes
|
||||
4. Add sauce
|
||||
5. Serve on a plate
|
||||
|
||||
While the code version might look like something like this:
|
||||
|
||||
```lua
|
||||
local function makeDinner()
|
||||
-- List of instructions
|
||||
end
|
||||
|
||||
-- Tell the code to run
|
||||
makeDinner()
|
||||
```
|
||||
|
||||
## Create a function
|
||||
|
||||
To practice, your first function will print your favorite food in the Output window. First set up the script you're going to use, if you don't remember how, here's a reminder:
|
||||
|
||||
1. Create a new script in **ServerScriptService**.
|
||||
2. Rename the script _FunctionsPractice_.
|
||||
3. Delete `"Hello World"`.
|
||||
4. Add comment at the top. For example: `-- Prints your favorite food`
|
||||
|
||||
Next, you create and name the function. All functions should have names that help you remember what their purpose is. Functions names are camelCased, with the first letter lowercase and next words capitalized.
|
||||
|
||||
Examples: `addPoints()`, `restartGame()`, `rainFlamingLlamas()`
|
||||
|
||||
- Type `local function printFood()`, then press <kbd>Enter</kbd> on your keyboard. It should autocomplete the function to look like:
|
||||
|
||||
```lua
|
||||
local function printFood()
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
Type `end` yourself if the code doesn't autocomplete for some reason. If the function doesn't have an `end`, your code won't run.
|
||||
</Alert>
|
||||
|
||||
### Add code to functions
|
||||
|
||||
All of the code for your function has to be typed between the lines `local function printFood()` and `end`. Any code not between those two points won't run when the function does.
|
||||
|
||||
```lua
|
||||
local function printFood()
|
||||
-- Code here runs when the function is called
|
||||
end
|
||||
|
||||
-- Code here will not run
|
||||
```
|
||||
|
||||
Information that is inside the function, or can be used by the function, is in **scope**.
|
||||
|
||||
- Between `local function printFood()` and `end`, use `print()` to state your favorite food.
|
||||
|
||||
```lua
|
||||
local function printFood()
|
||||
print("Curry!")
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="success">
|
||||
As you typed, your code should have indented automatically. This makes it easier for you and others to see the start and end of a function. If it didn't auto indent, you can press <kbd>Tab</kbd> at the beginning of the line to quickly indent it.
|
||||
</Alert>
|
||||
|
||||
### Tell the function to run
|
||||
|
||||
There's one more thing we need to do before the function will work, and that's to tell it to run, also known as **calling** a function. Functions won't run until they are called. To call a function, type the function's name including the `()`.
|
||||
|
||||
1. Under `end`, type `printFood()`.
|
||||
|
||||
```lua
|
||||
local function printFood()
|
||||
print("Curry!")
|
||||
end
|
||||
|
||||
printFood()
|
||||
```
|
||||
|
||||
2. Test the code. Your favorite food should appear in the [Output](../../../studio/output.md) window.
|
||||
|
||||
### Troubleshooting tips
|
||||
|
||||
If your code doesn't run, check for errors such as the following:
|
||||
|
||||
- Check that `print("Your Food Here")` is between `local function printFood()` and `end`.
|
||||
- Make sure that your food is a string, with quotations on `"each side"`.
|
||||
- Check that the function is called after it's been created. `printFood()` should be below `end`.
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
title: Functions and events
|
||||
description: Landing page for chapter on coding functions in Luau and using events on Roblox.
|
||||
next: /tutorials/fundamentals/coding-2/code-a-function
|
||||
prev: /tutorials/fundamentals/coding-1/parents-and-children
|
||||
---
|
||||
|
||||
### Series description
|
||||
|
||||
Use functions and events to make code run when you want, as often as you want. With functions and events you can set up traps, buttons, health pickups, and more.
|
||||
|
||||
Covered in this course are functions, parameters, arguments, and returning values.
|
||||
|
||||
### Objectives and prerequisites
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="20%"><b>Learning Objectives</b></td>
|
||||
<td>
|
||||
Learn to place code into reusable chunks called functions.
|
||||
|
||||
Understand what it means for code to be "in scope".
|
||||
|
||||
Set up events within an experience and use them to tell the functions when to run.
|
||||
|
||||
Practice using functions and events to create traps and buttons.
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Prerequisites</b></td>
|
||||
<td>
|
||||
Basic knowledge of Roblox Studio such as moving and rotating parts.
|
||||
Previous experience creating Script objects and using variables, properties, and strings.
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Series Contents
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Article</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[Code a function](../coding-2/code-a-function.md)</td>
|
||||
<td>Set up chunks of code in a way that only runs when you tell it to run.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Use parameters and events](../coding-2/use-parameters-and-events.md)</td>
|
||||
<td>How to code a function when you don't have all of the information yet.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Parameters practice - buttons](../coding-2/parameters-practice-buttons.md)</td>
|
||||
<td>Practice using events and parameters by making a bridge appear in-world with the push of a button.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Multiple parameters and arguments](../coding-2/multiple-parameters-and-arguments.md)</td>
|
||||
<td>Pass multiple pieces of information into a function at once.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
---
|
||||
title: Multiple parameters and arguments
|
||||
description: Pass multiple pieces of information into a function in Luau using arguments and parameters.
|
||||
next: /tutorials/fundamentals/coding-3/landing
|
||||
prev: /tutorials/fundamentals/coding-2/parameters-practice-buttons
|
||||
---
|
||||
|
||||
Functions can actually have more than one parameter, allowing for multiple arguments (pieces of information), to be passed into the function. An example might be assigning a player to a team. Here you would need a parameter to pass in the player, and a parameter to pass in which team to assign them to.
|
||||
|
||||
To set up multiple parameters, separate the parameter names with a comma.
|
||||
|
||||
```lua
|
||||
local function assignTeam(playerName, whichTeam)
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
## Practice with multiple parameters
|
||||
|
||||
To practice working with multiple parameters, create a function that sorts objects into trash or recycling.
|
||||
|
||||
- The **first** parameter will be trash, which will be destroyed.
|
||||
- The **second** parameter will be for recycling, which will be made shiny and new again.
|
||||
|
||||
### Set up the function
|
||||
|
||||
First set up the function with multiple parameters and then test your work.
|
||||
|
||||
1. Create a new script in **ServerScriptService**.
|
||||
2. Code a new function named `sortGarbage()` with two parameters, `trash` and `recyclable`.
|
||||
3. At the bottom of the script, call the function.
|
||||
4. Quickly check the code so far using a print statement inside the function.
|
||||
|
||||
```lua
|
||||
local function sortGarbage(trash, recyclable)
|
||||
print("garbage test")
|
||||
end
|
||||
|
||||
sortGarbage()
|
||||
```
|
||||
|
||||
### Use multiple parameters
|
||||
|
||||
Inside the function, parameters can be used similar to variables. In this example, `trash` is destroyed and then `recyclable` is given sparkles using a Particle Emitter.
|
||||
|
||||
1. Delete the print statement, and use Instance.new() to create a new Particle Emitter as shown. This will be used to give recyclables their sparkle.
|
||||
|
||||
```lua
|
||||
local function sortGarbage(trash,recyclable)
|
||||
-- Create a new Particle Emitter
|
||||
local sparkle = Instance.new("ParticleEmitter")
|
||||
|
||||
end
|
||||
|
||||
sortGarbage()
|
||||
```
|
||||
|
||||
<Alert severity="success">
|
||||
|
||||
`Datatype.Instance.new()` can also be used to create objects such as Fire, folders, and parts.
|
||||
|
||||
</Alert>
|
||||
|
||||
2. Destroy whatever is passed in through the trash parameter the same as if trash were any other variable.
|
||||
|
||||
```lua
|
||||
local function sortGarbage(trash,recyclable)
|
||||
local sparkle = Instance.new("ParticleEmitter")
|
||||
|
||||
-- Destroy the trash
|
||||
trash:Destroy()
|
||||
end
|
||||
|
||||
sortGarbage()
|
||||
```
|
||||
|
||||
3. Parent the Particle Emitter to the recyclable.
|
||||
|
||||
```lua
|
||||
local function sortGarbage(trash,recyclable)
|
||||
local sparkle = Instance.new("ParticleEmitter")
|
||||
|
||||
-- Destroy the trash and make recyclables shiny
|
||||
trash:Destroy()
|
||||
sparkle.Parent = recyclable
|
||||
end
|
||||
|
||||
sortGarbage()
|
||||
```
|
||||
|
||||
## Pass values through parameters
|
||||
|
||||
Time to take out the trash! With the parameters set up, the functions are ready to take in information.
|
||||
|
||||
1. Create two objects using basic parts to represent things you might throw away. One should be trash and one recyclable. Make sure they have unique names.
|
||||
|
||||
2. At the top of the script, add variables for the objects you created. These will be your arguments.
|
||||
|
||||
```lua
|
||||
local Workspace = game:GetService("Workspace")
|
||||
|
||||
local cementBlock = Workspace.Cement
|
||||
local glassBottle = Workspace.GlassBottle
|
||||
```
|
||||
|
||||
3. At the bottom of the script, where `sortGarbage()` is called, pass in each argument.
|
||||
|
||||
```lua
|
||||
local Workspace = game:GetService("Workspace")
|
||||
|
||||
-- Objects to use as arguments
|
||||
local cementBlock = Workspace.CementBlock
|
||||
local glassBottle = Workspace.GlassBottle
|
||||
|
||||
--Destroys trash and cleans up recyclables
|
||||
local function sortGarbage(trash,recyclable)
|
||||
local sparkle = Instance.new("ParticleEmitter")
|
||||
|
||||
trash:Destroy()
|
||||
sparkle.Parent = recyclable
|
||||
end
|
||||
|
||||
-- Pass in the arguments
|
||||
sortGarbage(cementBlock, glassBottle)
|
||||
|
||||
```
|
||||
|
||||
4. Test your code. The object passed in first will be destroyed. The second object will sparkle.
|
||||
|
||||
## Order of parameters
|
||||
|
||||
Typically, arguments are matched to parameters based on the order they're passed in. For instance, the first argument is used for the first parameter. The second argument is used for the second.
|
||||
|
||||
In our example, there are two parameters. Whatever gets passed in first will always be trash, and the second will always be recyclable.
|
||||
|
||||
```lua
|
||||
|
||||
--Destroys trash and cleans up recyclables
|
||||
local function sortGarbage(trash,recyclable)
|
||||
local sparkle = Instance.new("ParticleEmitter")
|
||||
|
||||
trash:Destroy()
|
||||
sparkle.Parent = recyclable
|
||||
end
|
||||
|
||||
--Goes in order. Cement is destroyed and the glass bottle is recycled
|
||||
sortGarbage(cementBlock, glassBottle)
|
||||
|
||||
--GlassBottle is destroyed and cementBlock is recycled
|
||||
sortGarbage(glassBottle, cementBlock)
|
||||
```
|
||||
|
||||
If you were to only pass in only one argument, that argument would be treated as trash. If you were to pass in three arguments, nothing would happen to the third argument because there is no third parameter.
|
||||
|
||||
## Summary
|
||||
|
||||
Parameters are placeholders through which values can be passed into functions. Arguments are the values that get passed through the placeholder. You can create multiple parameters by separating their names with commas. When calling functions, the order that values get passed into the receiving function determines which parameter they're used.
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
---
|
||||
title: Parameters practice - buttons
|
||||
description: Practice connecting functions to events by creating a button that activates a bridge.
|
||||
next: /tutorials/fundamentals/coding-2/multiple-parameters-and-arguments
|
||||
prev: /tutorials/fundamentals/coding-2/use-parameters-and-events
|
||||
---
|
||||
|
||||
Buttons can be used by players to unlock new areas, give points, and reveal treasure. Whenever a player touches a button, it should give some feedback to let players know it's being interacted with, like change colors or make sounds.
|
||||
|
||||
In this example, the button will be used to activate a bridge. When the button has been pressed, it'll turn green and players will be able to use the bridge. If the player hasn't pressed the button, they'll fall through the bridge when they try to walk on it.
|
||||
|
||||
## Make a bridge
|
||||
|
||||
Start off by setting up the bridge.
|
||||
|
||||
1. Create an area in your environment where players will need a bridge.
|
||||
2. Create a part for the bridge and rename it Bridge.
|
||||
3. Select the bridge, in the Properties window:
|
||||
|
||||
- Change **Transparency** to .5. For Transparency, 0 is visible, 1 is invisible.
|
||||
- Check **Anchor**.
|
||||
- Uncheck **CanCollide**.
|
||||
|
||||
4. When you test the experience, the bridge should be misty looking and people shouldn't be able to walk on it yet.
|
||||
<img src="../../../assets/education/coding-2/transparent-bridge.jpg" width="80%" />
|
||||
|
||||
## Create the button
|
||||
|
||||
Now that the bridge is set up, create the button.
|
||||
|
||||
1. Create a new part named _Button_.
|
||||
2. Change the button color to red.
|
||||
3. **Anchor** the button.
|
||||
4. Move the button so it's slightly floating and not touching anything. This is so to make sure the `Touched` event doesn't accidentally fire.
|
||||
<img src="../../../assets/education/coding-2/red-button.jpg" width="80%" />
|
||||
|
||||
## Make the button interactive
|
||||
|
||||
This time, instead of using the `Class.BasePart.Touched|Touched` event to create a trap, you'll use it to create a button that makes the bridge usable. To make the bridge collidable, use the code `bridge.CanCollide = true` within a custom function that runs when a player touches the button. You know everything else you need to complete the following steps.
|
||||
|
||||
Try to figure it out yourself before looking at the code solution.
|
||||
|
||||
1. Insert a new **script** into the button named _ActivateBridge_.
|
||||
2. Delete `Hello World`.
|
||||
3. Create variables for the bridge and for the button.
|
||||
4. Create a **local function** that does the following the button is touched:
|
||||
- Prints `"button touched"`.
|
||||
- Changes button's color from red to green when touched.
|
||||
- Changes bridge's transparency to 0 to make it visible.
|
||||
- Makes the bridge usable by using the code `bridge.CanCollide = true`
|
||||
5. Connect the function to the button's `Touched` event.
|
||||
6. Test the script and make sure the bridge appears when the button is touched.
|
||||
|
||||
Code Solution
|
||||
Below is one possible code solution
|
||||
|
||||
```lua
|
||||
-- Insert this script into button
|
||||
-- Turns the button green when something touches the button.
|
||||
|
||||
local button = script.Parent
|
||||
local bridge = workspace.Bridge
|
||||
|
||||
local function buttonPressed()
|
||||
print("button touched")
|
||||
button.Color = Color3.fromRGB(0, 170, 0)
|
||||
bridge.Transparency = 0
|
||||
bridge.CanCollide = true
|
||||
end
|
||||
|
||||
button.Touched:Connect(buttonPressed)
|
||||
```
|
||||
|
||||
### Troubleshoot your code
|
||||
|
||||
**Issue: The bridge is already solid when the experience starts.**
|
||||
Make sure that the parts are Anchored and not touching anything. The parts might touch something, like terrain or another part, and cause the buttonPressed() function to fire accidentally.
|
||||
|
||||
**Issue: You get an error in the Output window saying: "Bridge is not a valid member of Workspace"**
|
||||
Check the following:
|
||||
|
||||
- The naming of your bridge. The bridge in your script must be named exactly like in the Explorer.
|
||||
- That `part.Touched:Connect(buttonPressed)` is outside the `buttonPressed()` function.
|
||||
|
||||
### Optional code challenge
|
||||
|
||||
The script in this lesson can also be used to keep doors that keep players out of specific areas. Practice your coding skills and do the following:
|
||||
|
||||
- Create a door part.
|
||||
- Create a button further away from the door.
|
||||
- Change the script in this lesson so it makes the door change transparency and so the player can't collide with it.
|
||||
|
||||
Your version might look something like this:
|
||||
|
||||
```lua
|
||||
local button = script.Parent
|
||||
-- Reminder: Replace the name of the part, Gate, with the one in your project
|
||||
local gate = workspace.Gate
|
||||
|
||||
local function buttonPressed()
|
||||
print("button touched")
|
||||
-- Changes button to red to give player feedback
|
||||
button.BrickColor = BrickColor.Red() -- CHANGE THIS
|
||||
-- Make the gate invisible
|
||||
gate.Transparency = 1
|
||||
-- Makes it so the player can walk through the gate
|
||||
gate.CanCollide = false
|
||||
end
|
||||
|
||||
button.Touched:Connect(buttonPressed)
|
||||
```
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
---
|
||||
title: Use parameters and events
|
||||
description: How to pass information into functions using parameters and arguments. Also covers connecting functions to events.
|
||||
next: /tutorials/fundamentals/coding-2/parameters-practice-buttons
|
||||
prev: /tutorials/fundamentals/coding-2/code-a-function
|
||||
---
|
||||
|
||||
Normally, functions can only use the information they have coded within them. Sometimes however, you might not know in advance what that information will be, or you want to be able to reuse the same function with multiple pieces of similar information. For example, if you wanted to use a function to display the name of the person who finished an obby course the fastest in giant letters to everyone. You won't know the name of the future winner until the race is finished.
|
||||
|
||||
**Parameters** are placeholders for information you want to give to the function at a later time. They're like windows that allow you to **pass** information to the function.
|
||||
|
||||
## Use parameters and events to set up a trap
|
||||
|
||||
This script will create a trap part that destroys whatever touches the part, including other parts. You'll have to use a parameter to set it up. Be careful to anchor the trap where it doesn't fall and destroy things unintentionally.
|
||||
|
||||
### Create a new part
|
||||
|
||||
A part needs to be set up that will destroy anything that touches it.
|
||||
|
||||
1. Create a new part that's not touching anything. If it's touching something it might go off too soon.
|
||||
2. In the Explorer, rename the part:TrapPart.
|
||||
3. **Anchor** the part.
|
||||
|
||||
### Set up the script
|
||||
|
||||
Use what you know about variables and the experience hierarchy to reference the trap part.
|
||||
|
||||
1. Add a new script into the trap part. Rename the script _TrapScript_.
|
||||
2. Delete Hello World and add a descriptive comment.
|
||||
3. Under the comment, create a new variable which finds the script's parent.
|
||||
|
||||
```lua
|
||||
-- Destroys whatever touches the parent
|
||||
local trap = script.Parent
|
||||
|
||||
```
|
||||
|
||||
### Create a function with a parameter
|
||||
|
||||
The trap will use a function to destroy whatever touched the part. To work, the function needs to know what touched the part. And that means using parameters. Parameters are typed inside the `()` that comes after a function's name. They look like this:
|
||||
|
||||
```lua
|
||||
local function functionName(parameterName)
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
The actual information that gets passed through the parameter is called an **argument**. You'll create a new function called `onTouch()` with a parameter called `objectTouched` that will track whatever touches the trap and then destroy the touching part.
|
||||
|
||||
1. Create a local function. It can be named anything, but this lesson will use `onTouch`
|
||||
|
||||
```lua
|
||||
local trap = script.Parent
|
||||
|
||||
local function onTouch()
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
2. Inside the `()`, type a name for the parameter. This lesson will use objectTouched.
|
||||
|
||||
```lua
|
||||
local trap = script.Parent
|
||||
|
||||
local function onTouch(objectTouched)
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
3. Between `local function onTouch()` and `end`, create a print statement. You'll use this to check if something is touching the part in the next section.
|
||||
|
||||
```lua
|
||||
local trap = script.Parent
|
||||
|
||||
local function onTouch(objectTouched)
|
||||
print("Something touched the trap")
|
||||
end
|
||||
```
|
||||
|
||||
### Use an event to call the function
|
||||
|
||||
We want the function to run whenever something touches the part. To make that happen, connect the function to the `Touched` event. **Events** are things that happen in the experience. Like a player touching a part or losing health. When a function is connected to an event, the function runs whenever the event happens.
|
||||
|
||||
The `Touched` event fires whenever one part touches another part and can be used to create buttons, traps, and other objects that players interact with.
|
||||
|
||||
1. Beneath the function's `end`, type `trap.Touched:Connect(onTouch)`
|
||||
|
||||
```lua
|
||||
local trap = script.Parent
|
||||
|
||||
local function onTouch(objectTouched)
|
||||
print("Something touched the trap")
|
||||
end
|
||||
|
||||
-- Connect the function to the Touched event
|
||||
trap.Touched:Connect(onTouch)
|
||||
```
|
||||
|
||||
2. Click Test and then touch the part. Check for your test print statement: `Something touched the trap`. If you can't see the string in the Output window, check the following:
|
||||
|
||||
- Make sure the string "Something touched the part!" is between local function onTouch() and end.
|
||||
- Check that Touched is capitalized.
|
||||
|
||||
3. Now that the function is correctly set up, use it to destroy whatever touches the part. Inside the function, after the string, type `objectTouched:Destroy()` The completed code should be:
|
||||
|
||||
```lua
|
||||
local trap = script.Parent
|
||||
|
||||
local function onTouch(objectTouched)
|
||||
print("Something touched the trap")
|
||||
-- Destroy the touching object
|
||||
objectTouched:Destroy()
|
||||
end
|
||||
|
||||
trap.Touched:Connect(onTouch)
|
||||
```
|
||||
|
||||
4. Test again and see what happens when the part is touched. Your avatar should end up missing feet or arms. If the part touches the avatar's head or neck, it might even be completely destroyed.
|
||||
|
||||
<video controls src="../../../assets/education/coding-2/parameters-and-events_trap.mp4" width="80%"></video>
|
||||
|
||||
## Summary
|
||||
|
||||
Parameters are used to pass information that would be normally out of scope (where a function can't see it), into a function. Meanwhile, events are special signals that go off inside of the experience when something important happens. Different objects have different events. Functions can be connected to events so that they are called each time the event gets fired. This little script connected a function to the trap's `Class.BasePart.Touched|Touched` event, and passed in what was touching the trap through the parameter.
|
||||
|
|
@ -0,0 +1,447 @@
|
|||
---
|
||||
title: Else/if practice with giving points
|
||||
description: Create a part that gives players points using if and else statements in Luau.
|
||||
next: /tutorials/fundamentals/coding-4/landing
|
||||
prev: /tutorials/fundamentals/coding-3/multiple-conditions
|
||||
---
|
||||
|
||||
This project will use conditional statements to create a part that will give or subtract points on a leaderboard depending on what color the part is when touched. If blue, then it'll give players a few points. If green, then it'll give a lot of points. Finally, if red, then it'll take away points.
|
||||
|
||||
<video controls src="../../../assets/education/coding-3/coding3_colorPointBlockFinalizedExample.mp4" width="100%"></video>
|
||||
|
||||
## Set up the project
|
||||
|
||||
The point giving part can be added into any project where points are relevant. For instance, an adventure game where players collect points.
|
||||
|
||||
### Point tracking
|
||||
|
||||
To setup this project, you'll need a leaderboard to track the points and a part that changes colors. Code for the leaderboard will be provided.
|
||||
|
||||
1. Create a new script in **ServerScriptService** named Leaderboard. Copy and paste the code below into the script.
|
||||
|
||||
```lua
|
||||
--In ServerScriptService, create a script named PlayerSetup with the contents below.
|
||||
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
local function onPlayerJoin(player)
|
||||
local leaderstats = Instance.new("Folder")
|
||||
leaderstats.Name = "leaderstats"
|
||||
leaderstats.Parent = player
|
||||
|
||||
-- Example of an IntValue
|
||||
local points = Instance.new("IntValue")
|
||||
points.Name = "Points"
|
||||
points.Value = 0
|
||||
points.Parent = leaderstats
|
||||
end
|
||||
|
||||
-- Run onPlayerJoin when the PlayerAdded event fires
|
||||
Players.PlayerAdded:Connect(onPlayerJoin)
|
||||
```
|
||||
|
||||
### Color changing part
|
||||
|
||||
The script will cycle through three different colors for the part. Each color will have a variable to store it's RGB value, a data type that includes a set of three numbers (red, green, blue) that create colors.
|
||||
|
||||
1. Create a part named PointPart with an attached script named PointScript.
|
||||
2. In PointScript, use `script.Parent` to refer to the part.
|
||||
|
||||
```lua
|
||||
local pointPart = script.Parent
|
||||
```
|
||||
|
||||
3. Create variables to store the different colors. Each variable should be set to `Datatype.Color3.fromRGB()`, which creates a color value.
|
||||
|
||||
- **Blue** (Some Points): (0, 0, 255)
|
||||
- **Green** (Many Points): (0, 255, 0)
|
||||
- **Red** (Lose Points): (255, 0, 0)
|
||||
|
||||
```lua
|
||||
local pointPart = script.Parent
|
||||
|
||||
-- Colors
|
||||
local blue = Color3.fromRGB(0, 0, 255)
|
||||
local green = Color3.fromRGB(0, 255, 0)
|
||||
local red = Color3.fromRGB(255, 0, 0)
|
||||
```
|
||||
|
||||
4. Add variables for a small amount of points, a larger amount of points, and a third for removing points.
|
||||
|
||||
```lua
|
||||
-- Colors
|
||||
local blue = Color3.fromRGB(0, 0, 255)
|
||||
local green = Color3.fromRGB(0, 255, 0)
|
||||
local red = Color3.fromRGB(255, 0, 0)
|
||||
|
||||
-- Points values
|
||||
local smallPoints = 10
|
||||
local largePoints = 50
|
||||
local losePoints = 100
|
||||
```
|
||||
|
||||
### Add the players service
|
||||
|
||||
To award points, you'll need to get access to the player's information which is stored in the Explorer under Players, and is separate from the character object. This is where information like leaderboard stats can be found.
|
||||
|
||||
You can do so by adding the **Players** service to your script. **Services** are additional sets of pre-built functions made by Roblox engineers to save you time.
|
||||
|
||||
1. Get the **Players** service by typing:
|
||||
|
||||
`local Players = game:GetService("Players")`
|
||||
|
||||
```lua
|
||||
-- Points values
|
||||
local smallPoints = 10
|
||||
local largePoints = 50
|
||||
local losePoints = 100
|
||||
|
||||
-- Services needed
|
||||
local Players = game:GetService("Players")
|
||||
```
|
||||
|
||||
### Functions and events
|
||||
|
||||
PointsScript will need two functions. The first function will give and subtract parts. The second function will check if a player has touched the part. These functions will then be connected with a touch event, which runs whenever that part is touched.
|
||||
|
||||
1. Create a new function named `givePoints()` and a parameter named `player`. Inside, add a print statement to use for testing.
|
||||
|
||||
```lua
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
-- Gives or subtracts points
|
||||
local function givePoints(player)
|
||||
print("Giving player points")
|
||||
end
|
||||
```
|
||||
|
||||
2. Under that, create a second function named `partTouched()` with a parameter named `otherPart`.
|
||||
|
||||
```lua
|
||||
-- Gives or subtracts points
|
||||
local function givePoints(player)
|
||||
print("Giving player points")
|
||||
end
|
||||
|
||||
-- Checks if player touched the part
|
||||
local function partTouched(otherPart)
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
3. Inside the function, use the function `GetPlayerFromCharacter()` to check if there's a player in the otherPart variable.
|
||||
|
||||
```lua
|
||||
-- Checks if player touched the part
|
||||
local function partTouched(otherPart)
|
||||
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
|
||||
end
|
||||
```
|
||||
|
||||
4. If a player touched the part, it'll be stored inside the player variable. If not, the variable will stay empty. On your own:
|
||||
|
||||
- Inside the function, check if player has a value. If there is, then call `givePoints(player)`.
|
||||
- Beneath the function, connect `partTouched()` to the Touched event of `pointPart`.
|
||||
|
||||
```lua
|
||||
-- Checks if player touched the part
|
||||
local function partTouched(otherPart)
|
||||
-- Gets the player if one touched the part
|
||||
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
|
||||
if player then
|
||||
givePoints(player)
|
||||
end
|
||||
end
|
||||
|
||||
pointPart.Touched:Connect(partTouched)
|
||||
```
|
||||
|
||||
5. **Run** the project. Whenever a player touches the part, you should see a message in the Output window saying: `"Giving player points"`
|
||||
|
||||
**Troubleshooting Tips:**
|
||||
|
||||
- Check that `"Players"` in `game:GetService("Players")` is capitalized and in quotations.
|
||||
- `partTouched()` should be connected to pointPart's `Touched` event.
|
||||
|
||||
## Create Looping Colors
|
||||
|
||||
To loop through colors, the script will use a while =loop that changes the part's color every few seconds. The condition for this loop will be true, so it can run indefinitely.
|
||||
|
||||
1. At the end of the script, create a new while loop where the condition is true, meaning the loop always runs.
|
||||
|
||||
```lua
|
||||
-- Checks if player touched the part
|
||||
local function partTouched(otherPart)
|
||||
-- Gets the player if one touched the part
|
||||
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
|
||||
if player then
|
||||
givePoints(player)
|
||||
end
|
||||
end
|
||||
|
||||
pointPart.Touched:Connect(partTouched)
|
||||
|
||||
-- Loops through colors
|
||||
while true do
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
If the while true do loop is not at the bottom of the script, any code below it will never be run. Since the while loop doesn't stop, it'll keep running the loop instead of any code below it.
|
||||
</Alert>
|
||||
|
||||
2. On your own, code a while true do loop that changes pointPart to the color variables you've created. Don't forget to use `Library.task.wait()` between colors. When finished, check your code against the version below.
|
||||
|
||||
```lua
|
||||
-- Loops through 3 colors, waiting between each color
|
||||
while true do
|
||||
pointPart.Color = blue
|
||||
task.wait(3)
|
||||
pointPart.Color = green
|
||||
task.wait(2)
|
||||
pointPart.Color = red
|
||||
task.wait(1)
|
||||
end
|
||||
```
|
||||
|
||||
3. Play-test and check that all three colors loop without stopping.
|
||||
|
||||
<img src="../../../assets/education/coding-3/colorPoint_loopingColors.gif" width="50%" />
|
||||
|
||||
### Troubleshooting tips
|
||||
|
||||
At this point, if the color looping doesn't work as intended, try one of the following below.
|
||||
|
||||
- Check that the while loop is at the **bottom** of the script, below the Touched event. If the loop is not at the bottom, it'll keep other parts of the script from running correctly.
|
||||
- Check that each color inside `Datatype.Color3.fromRGB()` is correctly written. There must be three numbers between 0 and 255 separated by commas, like `(255, 50, 0)`.
|
||||
|
||||
## Give players points
|
||||
|
||||
Players will be given points based on the current color of the part when they touch it.
|
||||
|
||||
### Find the current color
|
||||
|
||||
Whenever a player touches the part, the script will need to know the current color of the part to award points later.
|
||||
|
||||
1. Find `givePoints()`. Replace your testing message with a variable for the current color of pointPart. This variable will determine how many points the player gets (or loses).
|
||||
|
||||
```lua
|
||||
local function givePoints(player)
|
||||
local currentColor = pointPart.Color
|
||||
end
|
||||
```
|
||||
|
||||
2. To affect a player's points, that function needs access to the player's leaderboard. Create a variable to store it.
|
||||
|
||||
```lua
|
||||
local function givePoints(player)
|
||||
local currentColor = pointPart.Color
|
||||
|
||||
local playerStats = player:WaitForChild("leaderstats")
|
||||
end
|
||||
```
|
||||
|
||||
3. Now add a variable to get the player's Points value, which is a child of their leaderboard.
|
||||
|
||||
```lua
|
||||
local function givePoints(player)
|
||||
local currentColor = pointPart.Color
|
||||
|
||||
local playerStats = player:WaitForChild("leaderstats")
|
||||
local playerPoints = playerStats:WaitForChild("Points")
|
||||
end
|
||||
```
|
||||
|
||||
### Give or subtract points
|
||||
|
||||
Next, you'll use if and elseif to give or subtract points depending on the color of the part when touched. Remember that blue provides a small amount, green provides many, and red subtracts points.
|
||||
|
||||
1. Inside `givePoints()`, beneath the variables, use an if statement to check if the current color is blue and if so then add `smallPoints` to the player's current points value.
|
||||
|
||||
```lua
|
||||
local function givePoints(player)
|
||||
local currentColor = pointPart.Color
|
||||
|
||||
local playerStats = player:WaitForChild("leaderstats")
|
||||
local playerPoints = playerStats:WaitForChild("Points")
|
||||
|
||||
if currentColor == blue then
|
||||
playerPoints.Value += smallPoints
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
2. To check for green, add an else if condition. If green, then add the `largePoints` variable to the player's points.
|
||||
|
||||
```lua
|
||||
if currentColor == blue then
|
||||
playerPoints.Value += smallPoints
|
||||
elseif currentColor == green then
|
||||
playerPoints.Value += largePoints
|
||||
end
|
||||
```
|
||||
|
||||
3. Use an else statement to subtract points if pointsPart was neither blue nor green.
|
||||
|
||||
```lua
|
||||
if currentColor == blue then
|
||||
playerPoints.Value += smallPoints
|
||||
elseif currentColor == green then
|
||||
playerPoints.Value += largePoints
|
||||
else
|
||||
playerPoints.Value -= losePoints
|
||||
end
|
||||
```
|
||||
|
||||
4. Lastly, **destroy** the part after the if statement so that the script can't keep giving out points.
|
||||
|
||||
```lua
|
||||
if currentColor == blue then
|
||||
playerPoints.Value += smallPoints
|
||||
elseif currentColor == green then
|
||||
playerPoints.Value += largePoints
|
||||
else
|
||||
playerPoints.Value -= losePoints
|
||||
end
|
||||
|
||||
pointPart:Destroy()
|
||||
```
|
||||
|
||||
5. Playtest and check that each color gives points as expected. Be sure to test all **three** conditions.
|
||||
|
||||
<video controls src="../../../assets/education/coding-3/colorPoint_showPointChange_web.mp4" width="100%"></video>
|
||||
|
||||
## Give players feedback
|
||||
|
||||
The PointPart works, but players might not notice something happened unless they happen to be looking at their leaderboard. Fix that by creating particles when the PointPart is destroyed.
|
||||
|
||||
Adding feedback when players use a part, like sounds, shakes, or particles, makes interactions with objects more satisfying to players.
|
||||
|
||||
<video controls src="../../../assets/education/coding-3/colorPoint_showParticles_web.mp4" width="100%"></video>
|
||||
|
||||
### Create a particle effect
|
||||
|
||||
The particle effect will be the same color as the part when touched. Since the colors were stored in variables, it's easy to reuse them.
|
||||
|
||||
1. In `givePoints()` at the bottom, create a new **ParticleEmitter** instance. Make sure the instance name is spelled exactly as shown.
|
||||
|
||||
```lua
|
||||
local particle = Instance.new("ParticleEmitter")
|
||||
end
|
||||
```
|
||||
|
||||
2. ParticleEmitters use color sequences to control their Color property. Create a new ColorSequence and pass in the current part color.
|
||||
|
||||
```lua
|
||||
-- Destroy part
|
||||
pointPart:Destroy()
|
||||
|
||||
-- Create particles
|
||||
local particle = Instance.new("ParticleEmitter")
|
||||
particle.Color = ColorSequence.new(currentColor)
|
||||
```
|
||||
|
||||
3. The particle will need to be parented to player that touched it. Create a variable to get the player's Character model. Then, parent the particle to the player's head.
|
||||
|
||||
```lua
|
||||
local particle = Instance.new("ParticleEmitter")
|
||||
particle.Color = ColorSequence.new(currentColor)
|
||||
|
||||
local playerCharacter = player.Character
|
||||
particle.Parent = playerCharacter:WaitForChild("Head")
|
||||
```
|
||||
|
||||
4. Use `Library.task.wait()` for a quick second, then destroy the particles.
|
||||
|
||||
```lua
|
||||
local particle = Instance.new("ParticleEmitter")
|
||||
particle.Color = ColorSequence.new(currentColor)
|
||||
|
||||
local playerCharacter = player.Character
|
||||
particle.Parent = playerCharacter:WaitForChild("Head")
|
||||
|
||||
task.wait(1)
|
||||
particle:Destroy()
|
||||
```
|
||||
|
||||
5. Playtest the game and make sure particles briefly follow the player after touching each color.
|
||||
|
||||
<video controls src="../../../assets/education/coding-3/colorPoint_showParticles_web.mp4" width="100%"></video>
|
||||
|
||||
### Troubleshooting tips
|
||||
|
||||
At this point, if particles doesn't work as intended, try one of the following below.
|
||||
|
||||
- Make when creating a new instance that ParticleEmitter is spelled **exactly** as shown and inside quotations.
|
||||
- When parenting the particles, make sure to use `:` between `playerCharacter` and `WaitForChild()` with no spaces between.
|
||||
|
||||
## Complete PointScript
|
||||
|
||||
A finished version of the script can be referenced below.
|
||||
|
||||
```lua
|
||||
local pointPart = script.Parent
|
||||
--local storage = game:GetService("ServerStorage")
|
||||
|
||||
-- Gives some points
|
||||
local blue = Color3.fromRGB(0, 0, 255)
|
||||
-- Gives more points
|
||||
local green = Color3.fromRGB(0, 255, 0)
|
||||
-- Makes players lose points
|
||||
local red = Color3.fromRGB(255, 0, 0)
|
||||
|
||||
-- gold given to players
|
||||
local smallPoints = 10
|
||||
local largePoints = 50
|
||||
local losePoints = 100
|
||||
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
local function givePoints(player)
|
||||
local currentColor = pointPart.Color
|
||||
|
||||
local playerStats = player:WaitForChild("leaderstats")
|
||||
local playerPoints = playerStats:WaitForChild("Points")
|
||||
|
||||
-- Gives player gold based on the color of the part
|
||||
if currentColor == blue then
|
||||
playerPoints.Value += smallPoints
|
||||
elseif currentColor == green then
|
||||
playerPoints.Value += largePoints
|
||||
else
|
||||
playerPoints.Value -= losePoints
|
||||
end
|
||||
|
||||
-- Destroy the part, wait a second, and then destroy the particle
|
||||
pointPart:Destroy()
|
||||
|
||||
-- Creates a sparkles effect and destroys it
|
||||
local playerCharacter = player.Character
|
||||
local particle = Instance.new("ParticleEmitter")
|
||||
particle.Color = ColorSequence.new(currentColor)
|
||||
particle.Parent = playerCharacter:WaitForChild("Head")
|
||||
task.wait(1)
|
||||
particle:Destroy()
|
||||
end
|
||||
|
||||
local function partTouched(otherPart)
|
||||
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
|
||||
|
||||
if player then
|
||||
givePoints(player)
|
||||
end
|
||||
end
|
||||
|
||||
pointPart.Touched:Connect(partTouched)
|
||||
|
||||
-- Changes the color of the part based on variables. Needs to be at bottom of script.
|
||||
while true do
|
||||
pointPart.Color = blue
|
||||
task.wait(4)
|
||||
pointPart.Color = green
|
||||
task.wait(3)
|
||||
pointPart.Color = red
|
||||
task.wait(2)
|
||||
end
|
||||
```
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
---
|
||||
title: Intro to if statements
|
||||
description: Learn how to code if statements in Luau.
|
||||
next: /tutorials/fundamentals/coding-3/traps-with-if-statements
|
||||
prev: /tutorials/fundamentals/coding-3/landing
|
||||
---
|
||||
|
||||
In experiences, there are often many cause-and-effect relationships. For example:
|
||||
|
||||
- If a player scores 10 points, then they win the game.
|
||||
- If a player has a power-up, then they can run super fast.
|
||||
- If a player says "Happy Birthday" in chat, then confetti rains.
|
||||
|
||||
Scripts use conditional statements to handle these types of situations. **Conditional statements** are lines of code that only run if certain conditions are true. One type of conditional statement is an **if/then statement**. In Luau, the syntax pattern for if statements looks like this:
|
||||
|
||||
```lua title="if then syntax"
|
||||
if "something happens" then
|
||||
-- Make something else happen
|
||||
end
|
||||
```
|
||||
|
||||
Code chunks using conditionals are **control structures.** Control structures are like flow diagrams in code form and can have several conditional statements.
|
||||
|
||||
## If statement practice
|
||||
|
||||
These steps show how to create a script that changes a part's color if a statement is true.
|
||||
|
||||
1. In **ServerScriptService**, create a new script and name it `TruthChecker`. Add an appropriate comment to the script.
|
||||
|
||||
```lua
|
||||
-- Changes the part if a condition is true
|
||||
|
||||
```
|
||||
|
||||
2. Create a new part named LieDetector.
|
||||
|
||||
### Format if statements
|
||||
|
||||
**Conditions** can come in various forms but are often simple statements like math equations. For example, if 1+1 equals 2, then run some code. Like ordinary math equations, conditional can use **operators** such as plus (`+`) or less than (`<`) to evaluate statements.
|
||||
|
||||
One particular operator to be aware of is `==`; it stands for "is equal to." So the statement `2 + 2 == 4` can be read as "two plus two is equal to four". Be very careful not to mix it up with `=`, which assigns new values to objects like variables.
|
||||
|
||||
1. Set up the empty conditional. In the script, type `if then`, and press <kbd>Enter</kbd> to autocomplete the conditional. The keyword `then` will be underlined because the code is incomplete.
|
||||
|
||||
```lua
|
||||
if then
|
||||
-- empty code
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
2. After the keyword `if`, type a true statement such as `3 + 3 == 6`.
|
||||
|
||||
```lua
|
||||
if 3 + 3 == 6 then
|
||||
-- empty code
|
||||
end
|
||||
```
|
||||
|
||||
3. Within the conditional, reference the part you named LieDetector and change the part's `Color` property to green.
|
||||
|
||||
```lua
|
||||
if 3 + 3 == 6 then
|
||||
workspace.LieDetector.Color = Color3.fromRGB(0, 255, 0)
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
Indenting the lines of code within the conditional makes it easier to see where the code chunk starts and stops.
|
||||
</Alert>
|
||||
|
||||
4. **Test** your code. If three plus three is equal to six, the part will turn green.
|
||||
|
||||
## Check a false condition
|
||||
|
||||
Now, purposely change the statement to see what happens when the math equation is false.
|
||||
|
||||
1. In the if statement, change the equation to something inaccurate, such as `3 + 3 >= 10`.
|
||||
|
||||
```lua
|
||||
if 3 + 3 >= 10 then
|
||||
workspace.LieDetector.Color = Color3.fromRGB(0, 255, 0)
|
||||
end
|
||||
```
|
||||
|
||||
2. Test your code now. The part shouldn't turn green for a false statement.
|
||||
|
||||
### Math operators
|
||||
|
||||
The table below lists some common Luau operators. More information about operators can be found on [Luau Operators](../../../luau/operators.md).
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Symbol</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`+`</td>
|
||||
<td>Addition</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`-`</td>
|
||||
<td>Subtraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`*`</td>
|
||||
<td>Multiplication</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`/`</td>
|
||||
<td>Division</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Comparison operators
|
||||
|
||||
- `==` : Is equal to.
|
||||
- `~=` : Is not equal to.
|
||||
- `<` or `>` are used for less or greater than, respectively.
|
||||
- `<=` or `>=` are used for less/greater than or equal to, respectively.
|
||||
|
||||
## Variables and properties
|
||||
|
||||
Conditional statements are also used to evaluate the status of properties and variables. The following steps check whether a variable was successfully assigned a value.
|
||||
|
||||
1. Delete all of the code and copy the following snippet into the script. Test it, and a new error appears in Output.
|
||||
|
||||
```lua
|
||||
local mysteryPart = workspace.MysteryPart
|
||||
|
||||
-- Evaluates as true if MysteryPart was successfully assigned
|
||||
if mysteryPart then
|
||||
workspace.LieDetector.Color = Color3.fromRGB(0, 255, 0)
|
||||
end
|
||||
```
|
||||
|
||||
2. Insert a new part into the workspace named MysteryPart. Test again, and LieDetector should turn green.
|
||||
|
||||
3. Explore how properties can be evaluated with conditionals. Keep MysteryPart, but once again, delete your code and copy the code box below.
|
||||
|
||||
```lua
|
||||
local mysteryPart = workspace.MysteryPart
|
||||
|
||||
-- Evaluates as true if MysteryPart is fully opaque
|
||||
if mysteryPart.Transparency == 0 then
|
||||
workspace.LieDetector.Color = Color3.fromRGB(0, 255, 0)
|
||||
mysteryPart.Transparency = .2
|
||||
end
|
||||
```
|
||||
|
||||
4. Test the code, and if MysteryPart has the default transparency of 0, it will become ghostly while LieDetector turns green.
|
||||
|
||||
## Summary
|
||||
|
||||
Conditional statements check to see if a statement is accurate, and if so, run some code. If statements are a very common type of conditional statement. They use the pattern "If this is true, then do that."
|
||||
|
||||
Code chunks using conditional statements are called control structures. Control structures can hold multiple conditional statements.
|
||||
|
||||
In addition to evaluating if simple math statements are factual, conditionals are also used to check on the status of variables and properties.
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
title: Conditionals
|
||||
description: A tutorial series on how to use if statements in Luau within Roblox Studio.
|
||||
next: /tutorials/fundamentals/coding-3/intro-to-if-statements
|
||||
prev: /tutorials/fundamentals/coding-2/multiple-parameters-and-arguments
|
||||
---
|
||||
|
||||
### Series description
|
||||
|
||||
Many experiences have actions that only take place if a list of requirements are met. You may have seen rooms only specific teams could enter or inventory items only some players could purchase. This series will cover how to set up code that says, "If this happens, then do that."
|
||||
|
||||
### Objectives and prerequisites
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="20%"><b>Learning Objectives</b></td>
|
||||
<td>
|
||||
Understand the logic behind `if` `then` statements and how to set up multiple scenarios with the keywords `elseif` and `else`.
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Prerequisites</b></td>
|
||||
<td>
|
||||
Before beginning this course, readers should be able to navigate Roblox Studio, as well as declare new variables and functions.
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Series contents
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Article</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[Intro to If Statements](../coding-3/intro-to-if-statements.md)</td>
|
||||
<td>Learn how if statements work and how to code them in Luau.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[If Statement Practice: Trap Parts](../coding-3/traps-with-if-statements.md)</td>
|
||||
<td>Use conditionals to create better traps that only hurt avatars and humanoids.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[If Statement Practice: Power Ups](../coding-3/powerups-with-if-statements.md)</td>
|
||||
<td>Practice using `if` statements and create a part that increases the players' walking speed.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Multiple Conditions](../coding-3/multiple-conditions.md)</td>
|
||||
<td>Design code that accounts for multiple scenarios with `else` and `elseif`.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Multiple Conditions Practice: Awarding Points](../coding-3/give-points.md)</td>
|
||||
<td>Use everything learned about conditionals to create a part that can award points to players.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -0,0 +1,353 @@
|
|||
---
|
||||
title: Multiple conditions
|
||||
description: Learn how to use elseif and else to create more complex control structures in Luau.
|
||||
next: /tutorials/fundamentals/coding-3/give-points
|
||||
prev: /tutorials/fundamentals/coding-3/powerups-with-if-statements
|
||||
---
|
||||
|
||||
Control structures can have more than one condition. The keywords `else` and `elseif` can create additional scenarios for what should happen under several conditions. The syntax looks like:
|
||||
|
||||
```lua title="Shows syntax for elseif and else"
|
||||
if isGreen then
|
||||
print("Go")
|
||||
elseif isYellow then
|
||||
print("Slow")
|
||||
elseif isPedestrians then
|
||||
print("Wait")
|
||||
else
|
||||
print("stop")
|
||||
end
|
||||
```
|
||||
|
||||
In this project, `else` and `elseif` are used to code a parkour course where runners receive awards depending on their finishing time.
|
||||
<img src="../../../assets/education/coding-3/coding3Hero_ifElseIf.jpg" width="80%" />
|
||||
|
||||
## Code multiple conditions
|
||||
|
||||
For this project, you could write a unique if statement for each medal to award players, but that takes a lot of time. Take, for instance, the imaginary code below.
|
||||
|
||||
```lua title="All if statements"
|
||||
if finishTime < 5 then
|
||||
-- Get a gold medal
|
||||
end
|
||||
|
||||
if finishTime >= 5 and <= 10 then
|
||||
-- Get a silver medal
|
||||
end
|
||||
|
||||
if finishTime > 10 and <= 15 then
|
||||
-- Get a bronze medal
|
||||
end
|
||||
```
|
||||
|
||||
A more readable and efficient way to code this is to use a single if statement and use the keyword `elseif` to provide alternative conditions to test if the previous conditions aren't true.
|
||||
|
||||
```lua title="Uses elseif and else"
|
||||
if finishTime < 5 then
|
||||
-- Get a gold medal
|
||||
elseif finishTime >= 5 and <= 10 then
|
||||
-- Get a silver medal
|
||||
elseif finishTime > 10 and <= 15 then
|
||||
-- Get a bronze medal
|
||||
end
|
||||
```
|
||||
|
||||
When the if/then statement runs, it'll start at the top and only run the code for the **first** true condition it finds.
|
||||
|
||||
## Set up the race course
|
||||
|
||||
Start by placing the course's starting point and finish line, and then create a script to time the player and award different medals.
|
||||
|
||||
1. Create an anchored part named FinishLine. To make testing faster, place the start and end close together. You can move the finish line after finishing the script.
|
||||
|
||||
<GridContainer numColumns="2">
|
||||
<figure>
|
||||
<img src="../../../assets/education/coding-3/raceCourse_showPartCraeted.jpg" />
|
||||
<figcaption>Finish Part</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img src="../../../assets/education/coding-3/raceCourse_showDistanceBetween.jpg" />
|
||||
<figcaption>Entire Course</figcaption>
|
||||
</figure>
|
||||
</GridContainer>
|
||||
|
||||
2. In FinishLine, insert a script named RaceManager. Then, add one variable to store how many seconds have passed since the race started and a second variable to reference FinishLine.
|
||||
|
||||
```lua
|
||||
local finishLine = script.Parent
|
||||
local timePassed = 0
|
||||
```
|
||||
|
||||
3. Create a function named `finish()`.
|
||||
|
||||
```lua
|
||||
local timePassed = 0
|
||||
local finishLine = script.Parent
|
||||
|
||||
local function finish()
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
4. On your own:
|
||||
|
||||
- Code a function named `partTouched()` that runs `finish()` when a player touches it.
|
||||
- Connect the finish line part to `partTouched()`.
|
||||
- Compare your code to the example below.
|
||||
|
||||
```lua
|
||||
local function finish()
|
||||
print("touched the finish line")
|
||||
end
|
||||
|
||||
local function partTouched(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
if humanoid then
|
||||
finish()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
finishLine.Touched:Connect(partTouched)
|
||||
```
|
||||
|
||||
5. Playtest and check that `finish()` is called when you touch the finish line.
|
||||
|
||||
### Keep finish() from repeating
|
||||
|
||||
Right now, whenever a player touches the finish line, `finish()` gets continuously called as long as the player touches the part.
|
||||
|
||||
Use a **boolean**, a variable that stores true or false, to ensure that finish() is only called once.
|
||||
|
||||
1. Create a new variable named `raceActive` and set it to `true`.
|
||||
|
||||
```lua
|
||||
local timePassed = 0
|
||||
local finishLine = script.Parent
|
||||
|
||||
local raceActive = true
|
||||
|
||||
-- Runs whenever the player touches the finish line part
|
||||
local function finish()
|
||||
```
|
||||
|
||||
2. Add a second condition to the if statement to check if raceActive is true before calling `finish()`.
|
||||
|
||||
```lua
|
||||
local function partTouched(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
if humanoid and raceActive == true then
|
||||
finish()
|
||||
end
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
3. To stop `finish()` from being called again, set `raceActive` to `false`.
|
||||
|
||||
```lua
|
||||
local function finish()
|
||||
print("touched the finish line")
|
||||
raceActive = false
|
||||
end
|
||||
```
|
||||
|
||||
4. Playtest your experience to check that you only see your test print statement once.
|
||||
|
||||
### Keep track of time
|
||||
|
||||
Like an if statement, a while loop can also use a condition to see if it should run. To time the player, create a timer using a while true do loop that only runs when the `raceActive` boolean is true.
|
||||
|
||||
1. At the bottom of the script, type `while raceActive == true do`. Press Enter to auto-complete and add the `end`.
|
||||
|
||||
```lua
|
||||
finishLine.Touched:Connect(partTouched)
|
||||
|
||||
while raceActive == true do
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
Make sure the loop is at the **bottom** of the script. Even though this while true do loop, eventually stops, it should still stay at the bottom of the script. This ensures that the previous code runs before it reaches the loop.
|
||||
</Alert>
|
||||
|
||||
2. To time the players, in the loop, add 1 to the `timePassed` variable once every second. Include a print statement to test your work.
|
||||
|
||||
```lua
|
||||
finishLine.Touched:Connect(partTouched)
|
||||
|
||||
while raceActive == true do
|
||||
task.wait(1)
|
||||
timePassed += 1
|
||||
print(timePassed)
|
||||
end
|
||||
```
|
||||
|
||||
3. Playtest the experience and check that you see each second displayed in the **Output** window.
|
||||
|
||||
## Award player medals
|
||||
|
||||
To finish, use an if statement with multiple conditions to award players a different prize medal based on their performance. Use an if statement and two elseif statements to check the player's finish time and award them the correct medal.
|
||||
|
||||
1. To confirm each medal can be awarded, use print statements.
|
||||
|
||||
```lua
|
||||
local function finish()
|
||||
raceActive = false
|
||||
print("You finished in " .. timePassed)
|
||||
end
|
||||
```
|
||||
|
||||
2. To award a gold medal, code an if statement that compares `timePassed` to the desired finish time. This example checks if the player's time was less than or equal to 10 seconds.
|
||||
|
||||
```lua
|
||||
local function finish()
|
||||
raceActive = false
|
||||
print("You finished in " .. timePassed)
|
||||
|
||||
if timePassed <= 10 then
|
||||
print("You get a gold medal!")
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
3. Playtest and confirm the gold medal can be awarded.
|
||||
|
||||
### Add additional conditions
|
||||
|
||||
Now that you've tested for the gold medal, code conditions for the other medals using the `elseif` keyword.
|
||||
|
||||
1. For the silver medal, use `elseif` and the next desired time range. In this example, the range is greater than 10 seconds but less than or equal to 20 seconds.
|
||||
|
||||
```lua
|
||||
local function finish()
|
||||
raceActive = false
|
||||
print("You finished in " .. timePassed)
|
||||
|
||||
if timePassed <= 10 then
|
||||
print("You get a gold medal!")
|
||||
elseif timePassed > 10 and timePassed <= 20 then
|
||||
print("You get a silver medal!")
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
2. Use the same pattern for the bronze medal. Check your code with the example below.
|
||||
|
||||
```lua
|
||||
local function finish()
|
||||
raceActive = false
|
||||
print("You finished in " .. timePassed)
|
||||
|
||||
if timePassed <= 10 then
|
||||
print("You get a gold medal!")
|
||||
elseif timePassed > 10 and timePassed <= 20 then
|
||||
print("You get a silver medal!")
|
||||
elseif timePassed > 20 and timePassed <= 30 then
|
||||
print("You get a bronze medal!")
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
3. Playtest for the silver and bronze medals.
|
||||
|
||||
### Troubleshooting tips
|
||||
|
||||
If you don't see the silver and bronze metals appear, try one of the below.
|
||||
|
||||
- Each `elseif` should have a then after its condition.
|
||||
- In `partTouched()`, make sure the second condition of the if statement uses `==`, like in `raceActive == true`.
|
||||
- Check that each `elseif` is in scope. Each `elseif` condition must be between the first line of the if/then statement and it's last `end`.
|
||||
|
||||
### Add the else condition
|
||||
|
||||
If the player didn't earn any of the medals, you should encourage them to try again. In this case, you can use an `else` statement, which runs if **no other** conditions are true, to show them a message.
|
||||
|
||||
<Alert severity="info">
|
||||
It's recommended that every if statement has an else, just in case the code doesn't find anything true.
|
||||
</Alert>
|
||||
|
||||
1. Below the last `elseif` and above `end`, start a new line and type `else`. **Do not** add then. Beneath else, use a print statement to prompt them to try again.
|
||||
|
||||
```lua
|
||||
local function finish()
|
||||
raceActive = false
|
||||
print("You finished in " .. timePassed)
|
||||
|
||||
if timePassed <= 10 then
|
||||
print("You get a gold medal!")
|
||||
elseif timePassed > 10 and timePassed <= 20 then
|
||||
print("You get a silver medal!")
|
||||
elseif timePassed > 20 and timePassed <= 30 then
|
||||
print("You get a bronze medal!")
|
||||
else
|
||||
print("Try again!")
|
||||
end
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
An `else` statement should always be the **last** check in an a control structure.
|
||||
</Alert>
|
||||
|
||||
2 . Playtest to see the else message.
|
||||
|
||||
## Summary
|
||||
|
||||
Control structures can have more than one scenario. Use if statements to set up the initial statement to check, and then add as many `elseif` conditions as necessary. Finally, use `else` to state what should happen if all given conditions are false.
|
||||
|
||||
Starting at the top, all conditions will be checked, and only the first true condition will run the code. The remaining conditions will not be checked, nor will their code run.
|
||||
|
||||
After finishing the project, you can expand upon the script to add new elements in a few extra ways.
|
||||
|
||||
- Add code so players can repeat the race by touching the start line when they finish.
|
||||
- Design a way to display time during a race. You can either display the time on a part using a Surface GUI, like in the
|
||||
[Create a Timed Bridge tutorial](../coding-4/create-a-timed-bridge.md).
|
||||
|
||||
```lua title ="Completed script"
|
||||
local timePassed = 0
|
||||
local finishLine = script.Parent
|
||||
|
||||
-- Used to keep finish() and timer from repeating when race is over
|
||||
local raceActive = true
|
||||
|
||||
-- Runs when the player touches the finish line and shows them an award
|
||||
local function finish()
|
||||
raceActive = false
|
||||
print("You finished in " .. timePassed)
|
||||
|
||||
if timePassed <= 10 then
|
||||
print("You get a gold medal!")
|
||||
elseif timePassed > 10 and timePassed <= 20 then
|
||||
print("You get a silver medal!")
|
||||
elseif timePassed > 20 and timePassed <= 30 then
|
||||
print("You get a bronze medal!")
|
||||
else
|
||||
print("Try again!")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Checks if a player touches the part when a race is active
|
||||
local function partTouched(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
if humanoid and raceActive == true then
|
||||
finish()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
finishLine.Touched:Connect(partTouched)
|
||||
|
||||
-- Keeps track of race time while the race is active. Needs to be at script bottom.
|
||||
while raceActive == true do
|
||||
task.wait(1)
|
||||
timePassed += 1
|
||||
print(timePassed)
|
||||
end
|
||||
```
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
---
|
||||
title: Evaluate multiple statements
|
||||
description: How to use the and keyword to evaluate more than one statement at a time in Roblox Luau.
|
||||
next: /tutorials/fundamentals/coding-3/multiple-conditions
|
||||
prev: /tutorials/fundamentals/coding-3/traps-with-if-statements
|
||||
---
|
||||
|
||||
If statements can have multiple requirements that need to be true before running code. The keyword `and` allows you to combine statements. The following code evaluates first if two plus two equals six and then if four does not equal six. If both statements are true, the code will run.
|
||||
|
||||
```lua
|
||||
-- will not run
|
||||
if 2 + 2 == 6 and 4 ~= 6 then
|
||||
print("Both statements are true")
|
||||
end
|
||||
|
||||
-- will run
|
||||
if 4 + 2 == 6 and 4 ~= 6 then
|
||||
print("Both statements are true")
|
||||
end
|
||||
```
|
||||
|
||||
## Create a powerup
|
||||
|
||||
Powerups are in-experience items that give players special abilities like flying, invisibility, or speed. This powerup will boost the player's walking speed every time the powerup is touched. Continuously applying boosts can make the player go way too fast, so `and` will be used to control the upper walking speed limit.
|
||||
|
||||
### Set up the powerup
|
||||
|
||||
Use this code with a simple part or a model, such as a crystal, coin, or glowing neon orb.
|
||||
|
||||
1. Create a new part named **Powerup** and insert a script named **WalkSpeedManager**.
|
||||
|
||||
2. Declare a variable named `speedBoost` and assign the script's parent object.
|
||||
|
||||
```lua
|
||||
-- Gives a temporary speed boost when touched
|
||||
local speedBoost = script.Parent
|
||||
```
|
||||
|
||||
3. Set up a function named `onTouch` and connect it to the parent object's `Touched` event. Then playtest and check your work.
|
||||
|
||||
```lua
|
||||
local speedBoost = script.Parent
|
||||
|
||||
local function onTouch(otherPart)
|
||||
print("Something touched speedBoost")
|
||||
end
|
||||
|
||||
speedBoost.Touched:Connect(onTouch)
|
||||
```
|
||||
|
||||
4. The WalkSpeed property is found on Humanoid objects. Use the same pattern used when creating a trap part and create a conditional that checks for Humanoid objects.
|
||||
|
||||
```lua title="Looks for Humanoid parts"
|
||||
local function onTouch(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
|
||||
if humanoid then
|
||||
print("A Humanoid was found")
|
||||
end
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
## Speed players up
|
||||
|
||||
The speed boost will make avatars walk faster every time the speed boost is touched. That will quickly become very, very fast. The keyword `and` will ensure players can't go too fast by only enabling the speed boost if the player is under a certain speed.
|
||||
|
||||
1. If a Humanoid is found, take the current WalkSpeed value and add 10 to it. Playtest, and your avatar will get faster every time it touches the speed boost.
|
||||
|
||||
```lua title="Increases current WalkSpeed"
|
||||
local function onTouch(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
|
||||
if humanoid then
|
||||
humanoid.WalkSpeed += 10
|
||||
end
|
||||
end
|
||||
|
||||
speedBoost.Touched:Connect(onTouch)
|
||||
```
|
||||
|
||||
2. In the if statement, use the keyword `and` to add a second condition that the current WalkSpeed value is less than 50. After adding the boost, the fastest WalkSpeed value will be 60.
|
||||
|
||||
```lua title="Checks if current WalkSpeed is 50 or less"
|
||||
if humanoid and humanoid.WalkSpeed <= 50 then
|
||||
humanoid.WalkSpeed += 10
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
### Fine tune the speed boost
|
||||
|
||||
OnTouch is called every time the speed boost is touched. Every step or slightest bounce triggers the Touched event and calls the connected function. The part's property, `CanTouch` can keep the Touched event from firing. Take advantage of CanTouch and turn off the speed boost for one second every time it's been activated.
|
||||
|
||||
1. After applying the boost, set the part's CanTouch property to false. Playtest and make sure the boost only applies once.
|
||||
|
||||
```lua title="Disables the speed boost"
|
||||
local speedBoost = script.Parent
|
||||
|
||||
local function onTouch(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
|
||||
if humanoid and humanoid.WalkSpeed <= 50 then
|
||||
humanoid.WalkSpeed += 10
|
||||
speedBoost.CanTouch = false
|
||||
end
|
||||
end
|
||||
|
||||
speedBoost.Touched:Connect(onTouch)
|
||||
|
||||
```
|
||||
|
||||
2. Use `task.wait(1)` to pause the script for one second, then set CanTouch to true. Playtest and make sure the speed boost can be reapplied after one second.
|
||||
|
||||
```lua title="Finished script"
|
||||
local speedBoost = script.Parent
|
||||
|
||||
local function onTouch(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
|
||||
if humanoid and humanoid.WalkSpeed <= 50 then
|
||||
humanoid.WalkSpeed += 10
|
||||
speedBoost.CanTouch = false
|
||||
task.wait(1)
|
||||
speedBoost.CanTouch = true
|
||||
end
|
||||
end
|
||||
|
||||
speedBoost.Touched:Connect(onTouch)
|
||||
```
|
||||
|
||||
3. Play with the values in the finished script. WalkSpeed can go up to 100. The default WalkSpeed value is 16.
|
||||
|
||||
## Summary
|
||||
|
||||
The keyword `and` can be used to require multiple conditions before running a code chunk, such as a value being more than 0 and less than 100. Or that if there is a Humanoid and its WalkSpeed is less or equal to 50.
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
---
|
||||
title: If/then practice with traps
|
||||
description: Create a trap that sets the player's health to zero with Luau.
|
||||
next: /tutorials/fundamentals/coding-3/powerups-with-if-statements
|
||||
prev: /tutorials/fundamentals/coding-3/intro-to-if-statements
|
||||
---
|
||||
|
||||
Traps that decrease players' health are a fun game-play element that can be coded with conditional statements. Practice using conditionals by creating a part that sets the player's health to zero when touched.
|
||||
|
||||
<video controls src="../../../assets/education/coding-3/trap-exampleFinal.mp4" width="80%"></video>
|
||||
|
||||
## Set up the trap
|
||||
|
||||
Traps work exceptionally well in experiences with movement-based challenges, like obbies. These steps will start by setting up the necessary variables and functions. Do as much as you can without looking at the code boxes first.
|
||||
|
||||
1. Create and name a trap part. Insert a script into the part.
|
||||
2. In the script, add a descriptive comment and then use a variable to reference the script's parent.
|
||||
|
||||
```lua
|
||||
-- If a player touches this part, set their health to 0
|
||||
|
||||
local trapPart = script.Parent
|
||||
```
|
||||
|
||||
3. Create a function named `onTouch()` with a parameter named `otherPart`.
|
||||
|
||||
```lua
|
||||
-- If a player touches this part, set their health to 0
|
||||
|
||||
local trapPart = script.Parent
|
||||
|
||||
local function onTouch(otherPart)
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
4. Connect the function to the trap part's `Touched` event to run whenever something touches the part.
|
||||
|
||||
```lua
|
||||
local trapPart = script.Parent
|
||||
|
||||
local function onTouch(otherPart)
|
||||
|
||||
end
|
||||
|
||||
trapPart.Touched:Connect(onTouch)
|
||||
```
|
||||
|
||||
## Check for player touch
|
||||
|
||||
Remember, the parameter `otherPart` records whatever touches the trap part, which might be a part of a player or just the baseplate.
|
||||
|
||||
To ensure the trap will only destroy players and won't destroy random decor items, use an if/then statement to check if whatever is in `otherPart` contains a Humanoid object.
|
||||
|
||||
<Alert severity="info">
|
||||
Humanoids are present in player avatars and many NPCs. Humanoids have several unique properties. One such property is Health.
|
||||
</Alert>
|
||||
|
||||
### Find a specific object
|
||||
|
||||
The function `FindFirstChildWhichIsA()` can be used to look for specific object types, which is handy because we're looking for a Humanoid-type object. Players will likely touch the trap with only a part of their avatar, so a variable must be set up to find the parent of the touching part and search it for a Humanoid.
|
||||
|
||||
1. In `onTouch()`, type `local character = otherPart.Parent`.
|
||||
|
||||
```lua
|
||||
local trapPart = script.Parent
|
||||
|
||||
local function onTouch(otherPart)
|
||||
-- Finds otherPart's parent object
|
||||
local character = otherPart.Parent
|
||||
|
||||
end
|
||||
|
||||
trapPart.Touched:Connect(onTouch)
|
||||
|
||||
```
|
||||
|
||||
2. Check to see if `character` has a `Class.Humanoid` by typing:
|
||||
|
||||
`local humanoid = character:FindFirstChildWhichIsA("Humanoid")`
|
||||
|
||||
```lua
|
||||
local trapPart = script.Parent
|
||||
|
||||
local function onTouch(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
end
|
||||
trapPart.Touched:Connect(onTouch)
|
||||
```
|
||||
|
||||
### Check with an if statement
|
||||
|
||||
If a Humanoid is found, then set the Humanoid's Health to zero.
|
||||
|
||||
1. Use an if statement to check if a Humanoid was successfully assigned to `local humanoid`.
|
||||
|
||||
```lua
|
||||
local trapPart = script.Parent
|
||||
|
||||
local function onTouch(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
|
||||
-- Evaluates if a Humanoid was found
|
||||
if humanoid then
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
trapPart.Touched:Connect(onTouch)
|
||||
```
|
||||
|
||||
2. Add a print statement and check the code so far.
|
||||
|
||||
```lua
|
||||
local trapPart = script.Parent
|
||||
|
||||
local function onTouch(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
|
||||
-- Evaluates if a Humanoid was found
|
||||
if humanoid then
|
||||
print("Found a Humanoid")
|
||||
end
|
||||
end
|
||||
|
||||
trapPart.Touched:Connect(onTouch)
|
||||
```
|
||||
|
||||
3. **Run** the code and check that you can see the output whenever a player touches the part.
|
||||
|
||||
## Change the player's health
|
||||
|
||||
If the statement is true, you can use the same humanoid variable to set the player's health to 0.
|
||||
|
||||
1. Between `then` and `end`, type `humanoid.Health = 0`.
|
||||
|
||||
```lua title="Completed script"
|
||||
local trapPart = script.Parent
|
||||
|
||||
local function onTouch(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
|
||||
-- Evaluates if a Humanoid was found
|
||||
if humanoid then
|
||||
print("Found a Humanoid")
|
||||
humanoid.Health = 0
|
||||
end
|
||||
end
|
||||
|
||||
trapPart.Touched:Connect(onTouch)
|
||||
```
|
||||
|
||||
2. Test the trap.
|
||||
|
||||
## Summary
|
||||
|
||||
This trap part used conditionals to detect Humanoid parts and set the Humanoid's health to zero. This script is an improvement on the previous trap script, which destroyed any touching object no matter what it was.
|
||||
|
||||
It does, however, still have a few flaws. Humanoids aren't just in players. Humanoids are also found in non-playable characters. The script is also only good at setting the player's health to zero. You can experiment with subtracting a small amount of health, but it's likely to subtract the health faster than desired. Later lessons provide further improvements to give greater control over how much health is subtracted from players.
|
||||
|
|
@ -0,0 +1,320 @@
|
|||
---
|
||||
title: Loops practice - create a timed bridge
|
||||
description: Make a bridge that disappears to add challenge to a Roblox experience. Combine for loops and while loops in this computer science practice.
|
||||
next: /tutorials/fundamentals/coding-4/nested-loops
|
||||
prev: /tutorials/fundamentals/coding-4/glow-lights-with-for-loops
|
||||
---
|
||||
|
||||
This project is another example of using for loops in a practical way. For this bridge, players will touch a button to make a bridge walkable for a limited time before it disappears. To create a timer and show the remaining time to a player, you'll use for loops.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/timedBridgePresentation.mp4" width="100%"></video>
|
||||
|
||||
## Set up the project
|
||||
|
||||
This bridge can be included in any Roblox project with movement-based challenges, like an obby.
|
||||
|
||||
### Create parts
|
||||
|
||||
1. Find a place to build a bridge, like a river or a large gap in an obby. Create three **anchored** parts like below.
|
||||
|
||||
- TimerDisplay
|
||||
- Bridge
|
||||
- ButtonBridge
|
||||
|
||||
<img src="../../../assets/education/coding-4/forLoopBridge_bridgeSetup.png" width="100%" />
|
||||
|
||||
2. When inactive, the bridge will be semi-transparent. To do so, select the **Bridge** and change it's properties.
|
||||
|
||||
- **Transparency** = 0.8
|
||||
- **CanCollide** = False
|
||||
|
||||
### Create the timer display
|
||||
|
||||
When crossing the bridge, players will need to see how many seconds are left before the bridge disappears. One way to display images or text is by adding an object called a Surface GUI to a part. **Surface GUIs** can also be used to create in-game signs, custom health bars, and inventory systems. This tutorial will go through this quickly, but more information can be found in the [Tutorials](../../../tutorials/index.md) section.
|
||||
|
||||
1. Select TimerDisplay and add a **SurfaceGui**. Then, parented to the Surface Gui, add a **TextLabel**.
|
||||
|
||||
<img src="../../../assets/education/coding-4/forLoopBridge_addTextLabel.png" />
|
||||
|
||||
2. Select the Surface GUI. In the Properties, make the following changes:
|
||||
|
||||
- Change the **Face** so you can see the text label on the front of the timer where the player is looking.
|
||||
|
||||
3. Select the TextLabel. In the Properties, make the following changes:
|
||||
- Set **Size** to `{1, 0},{1, 0}`.
|
||||
- Set **TextScaled** to true.
|
||||
- Set **Text** to be blank. Text will be updated using the script.
|
||||
|
||||
### Set up the script
|
||||
|
||||
Now that the timer is in place, create a script to control the bridge and display the countdown number to players.
|
||||
|
||||
1. In the Bridge part, add a new script named TimedBridge. In that script, create the following variables.
|
||||
|
||||
```lua
|
||||
local bridge = script.Parent
|
||||
local button = workspace.ButtonBridge
|
||||
local timerText = workspace.TimerDisplay.SurfaceGui.TextLabel
|
||||
|
||||
-- How long the bridge will stay solid
|
||||
local timerDuration = 5
|
||||
```
|
||||
|
||||
## Code the touch interaction
|
||||
|
||||
To use the bridge, you'll need to create two functions. One function will make the bridge walkable and display the timer. The other function will listen for if a player touches the button that activates the bridge.
|
||||
|
||||
1. Create a new function named `startTimer()` with a print statement inside. You'll use the print statement to test your code.
|
||||
|
||||
```lua
|
||||
local timerDuration = 5
|
||||
|
||||
local function startTimer()
|
||||
print("Countdown started")
|
||||
end
|
||||
```
|
||||
|
||||
2. Code a function named `buttonPressed()` to check if a humanoid touches the button. The function should accept a parameter of `partTouched`, and then have an empty if statement if a humanoid is detected in that part.
|
||||
|
||||
```lua
|
||||
local function startTimer()
|
||||
print("Countdown started")
|
||||
end
|
||||
|
||||
local function buttonPressed(partTouched)
|
||||
local character = partTouched.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
|
||||
if humanoid then
|
||||
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
3. To start the timer, in the `if` statement, call the `startTimer()` function.
|
||||
|
||||
```lua
|
||||
local function buttonPressed(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
if humanoid then
|
||||
startTimer()
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
4. Under the end of `buttonPressed()`, connect the `buttonPressed()` function to the button's `Touched` event.
|
||||
|
||||
```lua
|
||||
local function buttonPressed(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
if humanoid then
|
||||
startTimer()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
button.Touched:Connect(buttonPressed)
|
||||
```
|
||||
|
||||
5. Run the project. Touch the part and check in the Output window to see the print statement.
|
||||
|
||||
### Troubleshooting tips
|
||||
|
||||
At this point, if the bridge doesn't work as intended, try one of the following below.
|
||||
|
||||
**Issue**: Error message saying: `"... is not a valid member of workspace"`.
|
||||
|
||||
- In the TimedBridge script, check that all parts are spelled exactly as they're seen in the Explorer.
|
||||
|
||||
**Issue**: Can't see the parts.
|
||||
|
||||
- Make sure all three parts are Anchored.
|
||||
- Check the Transparency property for the bridge.
|
||||
|
||||
## Create the timer
|
||||
|
||||
Whenever players step on the bridge, `startTimer()` will make the bridge walkable and start the timer. Once the timer reaches 0, the bridge will become unwalkable, causing anyone who's not fast enough to fall.
|
||||
|
||||
### Make the bridge walkable
|
||||
|
||||
To start, the script will need to make the bridge solid, or collidable and then start a timer until it becomes unwalkable.
|
||||
|
||||
1. To make the bridge walkable, in `startTimer()`, change the bridge's Transparency property to 0 (opaque) and the CanCollide property to true.
|
||||
|
||||
```lua
|
||||
local function startTimer()
|
||||
-- Make the bridge visible and walkable
|
||||
bridge.Transparency = 0
|
||||
bridge.CanCollide = true
|
||||
end
|
||||
```
|
||||
|
||||
2. To create a timer that counts down, create a for loop with the following values.
|
||||
|
||||
- **Control Variable**: named `count`, set to `timerDuration`.
|
||||
- **End**: 0
|
||||
- **Increment**: -1
|
||||
|
||||
```lua
|
||||
local function startTimer()
|
||||
-- Make the bridge visible and walkable
|
||||
bridge.Transparency = 0
|
||||
bridge.CanCollide = true
|
||||
|
||||
for count = timerDuration, 0, -1 do
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
3. To show the timer to players, change the text in `timerText` to display count by typing `timerText.Text = count`. Each time the for loop goes through an iteration, it'll show players the next number in the timer.
|
||||
|
||||
```lua
|
||||
for count = timerDuration, 0, -1 do
|
||||
timerText.Text = count
|
||||
end
|
||||
```
|
||||
|
||||
4. Use a task.wait function to make the for loop run only once a second.
|
||||
|
||||
```lua
|
||||
for count = timerDuration, 0, -1 do
|
||||
timerText.Text = count
|
||||
task.wait(1)
|
||||
end
|
||||
```
|
||||
|
||||
5. Run the experience. When you touch the button, the bridge should appear and the timer will start, then complete.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/forLoopBridge-finishedCountdown.mp4" width="100%"></video>
|
||||
|
||||
## Keep the bridge from restarting
|
||||
|
||||
Notice though, if you move around on the button, the timer will keep restarting.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/forLoop_outputError.mp4" width="100%"></video>
|
||||
|
||||
This is because the for loop is being called each time you touch the button and starting the for loop from the beginning. To keep the timer from constantly restarting, you'll need to add a boolean, a type of variable, that will control whether or not `startTimer()` is allowed to be called again.
|
||||
|
||||
**Booleans** are written the same way as other variables, but instead of using numbers or strings, they can only be set to true or false. In this situation, the script will use a boolean to check if the timer is currently running before starting it.
|
||||
|
||||
1. At the top of your script, under your variables, create a variable named `timerActive` and set it to `false` since nobody has pressed the button yet.
|
||||
|
||||
```lua
|
||||
local timerDuration = 5
|
||||
local timerActive = false
|
||||
|
||||
local function startTimer()
|
||||
```
|
||||
|
||||
2. To makes sure the timer only starts when the `timerActive` boolean is false, add a second condition to the if statement in `buttonPressed()`.
|
||||
|
||||
```lua
|
||||
local function buttonPressed(otherPart)
|
||||
local character = otherPart.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
if humanoid and timerActive == false then
|
||||
startTimer()
|
||||
end
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
3. To keep `startTimer()` from running again before the timer runs out, set the boolean `timerActive` to true.
|
||||
|
||||
```lua
|
||||
local function startTimer()
|
||||
timerActive = true
|
||||
bridge.Transparency = 0
|
||||
bridge.CanCollide = true
|
||||
```
|
||||
|
||||
4. In the `startTimer()` function, **after** the for loop, set the bridge back to its original properties by changing the bridge's transparency to 0.8 and CanCollide to false.
|
||||
|
||||
```lua
|
||||
local function startTimer()
|
||||
timerActive = true
|
||||
bridge.Transparency = 0
|
||||
bridge.CanCollide = true
|
||||
|
||||
-- For loop that counts down from timerDuration
|
||||
for count = timerDuration, 0, -1 do
|
||||
timerText.Text = count
|
||||
task.wait(1)
|
||||
end
|
||||
|
||||
-- Make the bridge not walkable
|
||||
bridge.Transparency = 0.8
|
||||
bridge.CanCollide = false
|
||||
end
|
||||
```
|
||||
|
||||
5. One last thing to reset the bridge is to change the `timerText` to an empty string like how it was originally. Then, set the `timerActive` boolean to false.
|
||||
|
||||
```lua
|
||||
bridge.Transparency = 0.8
|
||||
bridge.CanCollide = false
|
||||
timerText.Text = ""
|
||||
timerActive = false
|
||||
```
|
||||
|
||||
6. Playtest and check to make sure the bridge can be used multiple times.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/timedBridgePresentation.mp4" width="100%"></video>
|
||||
|
||||
## Complete timed bridge script
|
||||
|
||||
```lua
|
||||
local bridge = script.Parent
|
||||
-- Gets the button as it's typed in the Explorer
|
||||
local button = workspace.ButtonBridge
|
||||
|
||||
-- Gets the part for the display
|
||||
local timerPart = workspace.TimerDisplay
|
||||
-- Gets the Text that will display the timer
|
||||
local timerText = timerPart.SurfaceGui.TextLabel
|
||||
|
||||
-- How long players have to cross the bridge
|
||||
local timerDuration = 5
|
||||
local timerActive = false
|
||||
|
||||
local function startTimer()
|
||||
print("Countdown started")
|
||||
timerActive = true
|
||||
bridge.Transparency = 0
|
||||
bridge.CanCollide = true
|
||||
|
||||
-- For loop that counts down from timerDuration
|
||||
for count = timerDuration, 0, -1 do
|
||||
timerText.Text = count
|
||||
task.wait(1)
|
||||
end
|
||||
|
||||
-- Make the bridge not walkable
|
||||
bridge.Transparency = 0.8
|
||||
bridge.CanCollide = false
|
||||
timerText.Text = ""
|
||||
timerActive = false
|
||||
|
||||
end
|
||||
|
||||
local function buttonPressed(partTouched)
|
||||
local character = partTouched.Parent
|
||||
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
||||
print("part touched")
|
||||
|
||||
if humanoid and timerActive == false then
|
||||
print("starting timer")
|
||||
startTimer()
|
||||
end
|
||||
end
|
||||
|
||||
button.Touched:Connect(buttonPressed)
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Loops can be combined with different means of interaction to create fun gameplay moments. In this tutorial, a timed bridge is created using a for loop that functions as a countdown. During the countdown, players are given a limited time to get across.
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
---
|
||||
title: Glow lights with for loops
|
||||
description: Create glowing lights in Roblox Studio using a for loop. This practical example teaches computer science with Roblox.
|
||||
next: /tutorials/fundamentals/coding-4/creating-a-timed-bridge
|
||||
prev: /tutorials/fundamentals/coding-4/intro-to-for-loops
|
||||
---
|
||||
|
||||
To practice for loops, you'll create a lamp that gradually glows brighter and then dims over time. This script can then be applied to any other lights in a project, whether it's a street light or glowing crystal.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/glowing-light-finished.mp4" width="100%"></video>
|
||||
|
||||
## Set up the part and script
|
||||
|
||||
The lamp will be a part with an attached light and script.
|
||||
|
||||
1. To make it easier to see the light, change the 3D world to **night time**. In the **Explorer** ⟩ **Lighting**, change **ClockTime** to `0`.
|
||||
|
||||
<img src="../../../assets/education/coding-4/glowing-lights-setClockTime.png" alt = "image" />
|
||||
|
||||
2. Create a new part or model named Lamp.
|
||||
|
||||
<img src="../../../assets/education/coding-4/glowing-lights-lightPart.jpg" width="75%" />
|
||||
|
||||
3. Select Lamp, and add a **light**, such as a PointLight or SpotLight. You'll work with the brightness property of the light to create a glowing lamp.
|
||||
|
||||
<img src="../../../assets/education/coding-4/florLoop_lightAdded.png" width="50%" />
|
||||
|
||||
4. In Lamp, add a new script named GlowScript. In that script, create variables to store the lamp part and the point light.
|
||||
|
||||
```lua
|
||||
local lightPart = script.Parent
|
||||
local light = lightPart.SpotLight
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
The specific path to the light and part might differ based on the model you're using. Be sure to double check in the Explorer.
|
||||
</Alert>
|
||||
|
||||
5. Next, create a variable to hold how much the light's brightness will change each time the loop runs. Then, add another variable for how many seconds the loops will wait before running again.
|
||||
|
||||
```lua
|
||||
-- How much the light's brightness will change each time
|
||||
local brightnessChange = 1
|
||||
-- How often in seconds the light will change brightness
|
||||
local timeChange = 1
|
||||
```
|
||||
|
||||
## Make the lamp glow
|
||||
|
||||
The lamp will use two **for loops**, one that counts up to make the lamp brighter, and one that counts down to dim it. Each for loop will have a control variable called currentBrightness. That way, as the for loop's control variable goes up and down, so will the brightness of the light.
|
||||
|
||||
### First loop (light increase)
|
||||
|
||||
Remember, a for loop starts with keyword `for` followed by a control variable. This script will set the brightness value of the light to value in the control variable.
|
||||
|
||||
1. Code the for loop using the following values. Remember to separate the control variable and end values with a comma.
|
||||
|
||||
- **Control variable**: `currentBrightness`
|
||||
- **Start value**: 0
|
||||
- **End value**: 5
|
||||
- **Increment Value**: `brightnessChange`
|
||||
|
||||
```lua
|
||||
local timeChange = 1
|
||||
|
||||
for currentBrightness = 0, 5, brightnessChange do
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
2. In scope of the for loop, set the brightness property of the light to the value in the control variable by typing `light.Brightness = currentBrightness`. Now, when the loop runs, the light will become brighter.
|
||||
|
||||
```lua
|
||||
for currentBrightness = 0, 5, brightnessChange do
|
||||
light.Brightness = currentBrightness
|
||||
end
|
||||
```
|
||||
|
||||
3. So the change doesn't happen all at once, add a wait function using the value in `timeChange`.
|
||||
|
||||
```lua
|
||||
for currentBrightness = 0, 5, brightnessChange do
|
||||
light.Brightness = currentBrightness
|
||||
task.wait(timeChange)
|
||||
end
|
||||
```
|
||||
|
||||
4. Run the experience to see the light increase in brightness each second.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/glowing-light-increase.mp4" width="100%"></video>
|
||||
|
||||
<Alert severity="info">
|
||||
Depending on the lighting in your project, you make need to adjust the brightness variables, or the environment's lighting.
|
||||
</Alert>
|
||||
|
||||
If you can't see the brightness change over time in the first loop:
|
||||
|
||||
- Make sure that `light.Brightness = currentBrightness` is between the do and end of your for loop.
|
||||
- Check that `timeChange` is at least 1 or higher. Smaller numbers will make the brightness change faster, but be harder to see over time.
|
||||
- Make sure that the first line of your for loop has two total commas separating the control variable, end value, and increment value.
|
||||
|
||||
### Second loop (light decrease)
|
||||
|
||||
To dim the light, use a second for loop. The values of this loop will be reversed so the light starts bright and each second, gets dimmer.
|
||||
|
||||
1. Code a second for loop that decreases the brightness over time. The solution is in the code box below. Use the following values:
|
||||
|
||||
- **Control Variable** - `currentBrightness` set to 5, the end of the last loop.
|
||||
- **End** - 0, turning off the light.
|
||||
- **Increment** - subtract `brightnessChange`.
|
||||
|
||||
```lua
|
||||
-- Second loop dims lamp
|
||||
for currentBrightness = 5, 0, -brightnessChange do
|
||||
light.Brightness = currentBrightness
|
||||
task.wait(timeChange)
|
||||
end
|
||||
```
|
||||
|
||||
2. Run your experience; you should see the light brighten and then dim.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/glowing-light-singleLoop.mp4" width="100%"></video>
|
||||
|
||||
### Make the light repeat
|
||||
|
||||
Right now, the light only turns on and off once. To make the lamp continuously glow on and off, the for loops will be placed inside a repeating while loop.
|
||||
|
||||
1. Under the for loops, create a new while loop.
|
||||
|
||||
```lua
|
||||
while true do
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
2. Place both for loops inside a while loop. Indent the for loops to make them easier to tell apart from the while loop.
|
||||
|
||||
```lua
|
||||
while true do
|
||||
for currentBrightness = 0, 5, brightnessChange do
|
||||
light.Brightness = currentBrightness
|
||||
task.wait(timeChange)
|
||||
end
|
||||
|
||||
for currentBrightness = 5, 0, -brightnessChange do
|
||||
light.Brightness = currentBrightness
|
||||
task.wait(timeChange)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
3. Run the experience to see the light turn bright and dim continuously.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/glowing-light-finished.mp4" width="100%"></video>
|
||||
|
||||
## Finished light script
|
||||
|
||||
A finished version of the script can be referenced below.
|
||||
|
||||
```lua
|
||||
-- Stores the light attached to this lamp
|
||||
lightPart = script.Parent
|
||||
light = lightPart.SpotLight
|
||||
|
||||
-- How much the light's brightness will change each time
|
||||
local brightnessChange = 1
|
||||
-- How often in seconds the light will change brightness
|
||||
local timeChange = 0.2
|
||||
|
||||
while true do
|
||||
for count = 0, 5, brightnessChange do
|
||||
light.Brightness = count
|
||||
task.wait(timeChange)
|
||||
end
|
||||
|
||||
-- Second loop to turn off light
|
||||
for count = 5, 0, -brightnessChange do
|
||||
light.Brightness = count
|
||||
task.wait(timeChange)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
To create complex effects in a project, scripts can use multiple loops, and even combinations of different types of loops. To code a glowing light, two loops are nested within a while loop. As coders add in more loops, be sure to check indentation so code can be easy to read.
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
---
|
||||
title: Intro to for loops
|
||||
description: Use for loops to repeat code in this lesson for Luau. This lesson explains how for loops work and includes practice scripts.
|
||||
next: /tutorials/fundamentals/coding-4/glow-lights-with-for-loops
|
||||
prev: /tutorials/fundamentals/coding-4/repeat-code-with-while-loops
|
||||
---
|
||||
|
||||
There are different ways to make code run over and over. If you want the code to only run a certain amount of times, use a **for loop**. This article will cover the logic behind for loops and demonstrate some practical examples, such as coding a countdown.
|
||||
|
||||
## How for loops work
|
||||
|
||||
For loops use three values to control how many times they run: a **control** variable, an **end** value, and an **increment** value. Starting from the value of the control variable, the for loops will either count up or down each time it runs code inside the loop until it passes the end value. Positive increment values count up, and negative increment values count down.
|
||||
|
||||
<img src="../../../assets/education/coding-4/forLoop_annotatedExample.png" width="50%" />
|
||||
|
||||
<Alert severity="info">
|
||||
Different computer languages might use other terminology with for loops. For instance, in C# or JavaScript, the end value might be called the condition.
|
||||
</Alert>
|
||||
|
||||
## Steps in a for loop
|
||||
|
||||
To understand for loops, it helps to see a flow chart diagram showing the logic of how they progress.
|
||||
|
||||
First, the for loop compares the control variable with the end value.
|
||||
|
||||
<img src="../../../assets/education/coding-4/forLoopDiagram_generic1.png" width="75%" />
|
||||
|
||||
After running the code, the increment value is added to the control variable. The loop then checks the control variable and starts over.
|
||||
|
||||
<img src="../../../assets/education/coding-4/forLoopDiagram_generic2.png" width="75%" />
|
||||
|
||||
Once the control variable passes the end value, the loop will stop. For example, if a loop has an end value of 10, once the control variable has passed 10, the for loop will stop.
|
||||
|
||||
<img src="../../../assets/education/coding-4/forLoopDiagram_generic3.png" width="75%" />
|
||||
|
||||
## Code a countdown
|
||||
|
||||
To see how a for loop works, use these steps to code a for loop that starts at 10 and counts down to 0, one number at a time. Every time the loop runs, it'll print the current value inside the control variable.
|
||||
|
||||
1. In **ServerScriptService**, create a new script named PracticeLoop. In the script, start by typing the keyword `for`.
|
||||
|
||||
```lua
|
||||
for
|
||||
```
|
||||
|
||||
2. Create a **control variable** named `count` and set a starting value of 10.
|
||||
|
||||
```lua
|
||||
for count = 10
|
||||
```
|
||||
|
||||
3. Set the **end value** to 0, by typing `, 0`. Make sure to include a comma to separate the values.
|
||||
|
||||
```lua
|
||||
for count = 10, 0
|
||||
```
|
||||
|
||||
4. Create an **increment value** of -1 by typing `, -1`. After the loop has finished its action, it'll add the increment value to the control variable, count. Because the increment is negative, it'll be subtracted when added to the control variable.
|
||||
|
||||
```lua
|
||||
for count = 10, 0, -1
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
A for loop doesn't explicitly need an increment. Without one, the loop will, by default, add 1 after each loop.
|
||||
|
||||
`for count = 10, 0`
|
||||
</Alert>
|
||||
|
||||
5. To finish the for loop, type do and press <kbd>Enter</kbd> to add `end`. Any code typed between `do` and `end` will run each time the loop repeats.
|
||||
|
||||
```lua
|
||||
for count = 10, 0, -1 do
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
6. Inside the loop, create a countdown by printing the value of the control variable, `count`, and then delay the script with a wait function.
|
||||
|
||||
```lua
|
||||
for count = 10, 0, -1 do
|
||||
-- Prints the current number the for loop is on
|
||||
print(count)
|
||||
-- Wait 1 second
|
||||
task.wait(1)
|
||||
end
|
||||
```
|
||||
|
||||
7. Run the project and watch the Output window to see the for loop.
|
||||
|
||||
Notice that the loop will print out the current value of count each time it goes through an **iteration**. An iteration is the complete process of checking the control value, running code, and updating the increment value. Because the control variable starts at 0 and has to go pass 10, the loop will go through 11 iterations before stopping.
|
||||
|
||||
### Troubleshooting tips
|
||||
|
||||
At this point, if the loop doesn't work as intended, try one of the following below.
|
||||
|
||||
- Check that you have **two commas** separating the numbers in your for loop. Having extra or missing commas will make the loop not start.
|
||||
- If the for loop prints all at once, make sure that there is a wait function that uses at least 1 second.
|
||||
|
||||
## Different for loop examples
|
||||
|
||||
Changing the three values of a for loop will change how the loop functions. Below are different examples of for loops with different start, end, and increment values. Try putting them into scripts and see what happens.
|
||||
|
||||
### Count up by one
|
||||
|
||||
```lua
|
||||
for count = 0, 5, 1 do
|
||||
print(count)
|
||||
task.wait(1)
|
||||
end
|
||||
```
|
||||
|
||||
### Count up in even numbers
|
||||
|
||||
```lua
|
||||
for count = 0, 10, 2 do
|
||||
print(count)
|
||||
task.wait(1)
|
||||
end
|
||||
```
|
||||
|
||||
### If for loops don't run at all
|
||||
|
||||
If the control variable starts out **beyond** the end value, like in the example below, the for loop won't run at all.
|
||||
|
||||
```lua
|
||||
for count = 10, 0, 1 do
|
||||
print(count)
|
||||
task.wait(1)
|
||||
end
|
||||
```
|
||||
|
||||
In this case, the for loop is counting up and checking if count is greater than 0. When the for loop does it's first check, it sees that 10 is greater than 0, and so it'll stop the loop without printing anything.
|
||||
|
||||
## Summary
|
||||
|
||||
A for loop is a common type of loop that's used when a set of instructions should repeat a specific amount of times. To create a for loop, use three variables with the syntax below:
|
||||
|
||||
```lua
|
||||
for count = 0, 10, 1 do
|
||||
print(count)
|
||||
end
|
||||
```
|
||||
|
||||
In the example above, the loop will start at 0. For each loop, it will print the count variable, add 1 to count, and finally finish looping when count is equal to 10.
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
title: Loops
|
||||
description: Learn how to use loops like while and for loops in this tutorial series for Roblox Studio. Great for beginners learning Luau or computer science.
|
||||
next: /tutorials/fundamentals/coding-4/repeat-code-with-while-loops
|
||||
prev: /tutorials/fundamentals/coding-3/give-points
|
||||
---
|
||||
|
||||
### Series description
|
||||
|
||||
In computer science, loops are a common feature in many scripts, often used to repeat sets of code. This series will cover two of the most common loops: for and while loops.
|
||||
|
||||
### Objectives and prerequisites
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="20%"><b>Learning objectives</b></td>
|
||||
<td>
|
||||
Understand situations where loops are useful as opposed to alternative forms of writing a script.
|
||||
|
||||
Be able to write out for and while loops, while identifying the syntax for both.
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Prerequisites</b></td>
|
||||
<td>
|
||||
Have a general understanding of variables in Luau.
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Series Contents
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Article</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[Repeat code with while Loops](./repeat-code-with-while-loops.md)</td>
|
||||
<td>Learn how to repeat code to create a color changing part.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Intro to for loops](./intro-to-for-loops.md)</td>
|
||||
<td>Use a common loop that repeats instructions for a set amount of times.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Loops practice: glowing lights with for loops](./glow-lights-with-for-loops.md)</td>
|
||||
<td>Practice using for loops by making lights glow.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Loops Practice: Creating a Timed Bridge](./create-a-timed-bridge.md)</td>
|
||||
<td>A more advanced implementation of a for loop that makes a bridge disappear and reappear.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Nesting loops](./nested-loops.md)</td>
|
||||
<td>Add a loop within a loop for more complex behavior and code.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -0,0 +1,362 @@
|
|||
---
|
||||
title: Nested loops
|
||||
description: Learn how to use nested loops. This computer science lesson uses Luau to combine multiple nested for loops.
|
||||
next: /tutorials/fundamentals/coding-5/landing
|
||||
prev: /tutorials/fundamentals/coding-4/create-a-timed-bridge
|
||||
---
|
||||
|
||||
Nesting loops allows you to repeat tasks in batches. For example, baking three batches of six cupcakes, or assigning weapons to players on two teams.
|
||||
|
||||
## How nested loops run
|
||||
|
||||
When loops are nested, scripts go line by line until it reaches the next loop. The inner loop will run until it's condition is met before returning to the outer loop.
|
||||
|
||||
### Nested loop logic
|
||||
|
||||
The following diagram shows the steps a loop takes.
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Outer loop: code runs line-by-line until it reaches the inner loop.</li>
|
||||
<li>Outer loop: code runs line-by-line until it reaches the inner loop.</li>
|
||||
<li>Outer loop: code runs line-by-line until it reaches the inner loop.</li>
|
||||
</ul>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<img src="../../../assets/education/coding-4/NestedLoopsDiagram300x500.png" width="100%" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Nested loop example
|
||||
|
||||
Nested loops can seem somewhat abstract, so a visual example can help. For this exercise, copy and paste a sample script and run it in Studio. This script will create towers of parts. The outer loop will control how many parts to make, while the inner loop will create the actual batch.
|
||||
|
||||
1. Create a new script in **ServerScriptService** named PartMaker. Copy the code below.
|
||||
|
||||
```lua
|
||||
local numberOfBatches = 7
|
||||
local partsPerBatch = 5
|
||||
local partsMade = 0
|
||||
|
||||
-- Makes a single cube
|
||||
local function createPart()
|
||||
local part = Instance.new("Part")
|
||||
part.Size = Vector3.new(2, 2, 2)
|
||||
part.CFrame = CFrame.new(20, 0, 20)
|
||||
part.Color = currentColor
|
||||
part.Parent = workspace
|
||||
end
|
||||
|
||||
-- Outer loop
|
||||
for partBatch = 1, numberOfBatches do
|
||||
print("Top outer loop: part batch " .. partBatch)
|
||||
currentColor = Color3.fromRGB(math.random(0, 255), math.random(0, 255), math.random(0, 255))
|
||||
|
||||
-- Inner loop
|
||||
for partNumber = 1, partsPerBatch do
|
||||
createPart()
|
||||
print("Inner loop: part " .. partNumber)
|
||||
partsMade += 1
|
||||
task.wait(0.5)
|
||||
end
|
||||
|
||||
print("Bottom outer loop: " .. partsMade .. " parts made so far.")
|
||||
|
||||
task.wait(2)
|
||||
end
|
||||
```
|
||||
|
||||
2. Watch as the script spawns a different batch of colored parts. After going through one batch, it'll pause for 2 seconds. The print statement in the outer loop will run only one time per completed inner loop.
|
||||
|
||||
## Nested for loop tower
|
||||
|
||||
Each loop has its own set of code, so can be responsible for different tasks. One thing nested loops can do is change the placement of where an object spawns to create a tower like the one in this video. There's three different loops, one each for controlling where along the width, length, and height of the tower the cube spawns.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/LoopingTower2_Compressed.mp4" width="100%"></video>
|
||||
|
||||
## Code a cube maker script
|
||||
|
||||
To practice nested loops, you'll make a script that creates a tower of cubes. For the cube tower script, first code a function that spawns a single cube. The tower will be built by repeatedly calling this function.
|
||||
|
||||
### Set up the script
|
||||
|
||||
For the cube tower script, first code a function that spawns a single cube. The tower will be built by repeatedly calling this function.
|
||||
|
||||
1. **Delete** the PartMaker script or disable it (in the script properties, check Disabled). If you don't, there will be two scripts making parts at the same time in the same place.
|
||||
|
||||
2. Create a new script named TowerBuilder. Add variables for tower size and cube size at the top.
|
||||
|
||||
```lua
|
||||
local TOWER_SIZE = 4
|
||||
local CUBE_SIZE = 2
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
Notice how the variables above are all capitalized. These are called **constants**, or variables that don't change. To set them apart from variables that will be changed within the script, type them using capitals and underscores.
|
||||
</Alert>
|
||||
|
||||
3. Add a local function named `makeCube()` that creates a single square cube using `CUBE_SIZE`.
|
||||
|
||||
```lua
|
||||
local TOWER_SIZE = 4
|
||||
local CUBE_SIZE = 2
|
||||
|
||||
-- Creates individual cubes
|
||||
local function makeCube()
|
||||
local cube = Instance.new("Part")
|
||||
cube.Size = Vector3.new(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE)
|
||||
end
|
||||
```
|
||||
|
||||
4. Set the cube's color to a variable which will be updated in the nested loops.
|
||||
|
||||
```lua
|
||||
local function makeCube()
|
||||
local cube = Instance.new("Part")
|
||||
cube.Size = Vector3.new(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE)
|
||||
cube.Color = currentColor
|
||||
end
|
||||
```
|
||||
|
||||
5. Lastly, **parent** the new cube to the workspace so it appears.
|
||||
|
||||
```lua
|
||||
local function makeCube()
|
||||
local cube = Instance.new("Part")
|
||||
cube.Size = Vector3.new(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE)
|
||||
cube.Color = currentColor
|
||||
cube.Parent = workspace
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
In Roblox code, once an object is created by script, it's recommended to parent it at the end. It's faster to make changes to an instance before there is a physical object in the 3D world.
|
||||
</Alert>
|
||||
|
||||
### Spawn in different directions
|
||||
|
||||
To create a tower, spawn cubes at specific points by setting the X, Y, Z properties of each new cube. X and Z are side to side. Y is up and down.
|
||||
|
||||
1. In `makeCube()`, add parameters for `spawnX`, `spawnY`, and `spawnZ`. These numbers will set each new cube's spawn location.
|
||||
|
||||
```lua
|
||||
-- Creates individual cubes
|
||||
local function makeCube(spawnX, spawnY, spawnZ)
|
||||
local cube = Instance.new("Part")
|
||||
cube.Size = Vector3.new(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE)
|
||||
cube.Color = currentColor
|
||||
cube.Parent = workspace
|
||||
end
|
||||
```
|
||||
|
||||
2. Inside the function, set the cube's CFrame property to a new CFrame using the `spawnX`, `spawnY`, `spawnZ` parameters.
|
||||
|
||||
```lua
|
||||
local function makeCube(spawnX, spawnY, spawnZ)
|
||||
local cube = Instance.new("Part")
|
||||
cube.Size = Vector3.new(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE)
|
||||
cube.Color = currentColor
|
||||
cube.CFrame = CFrame.new(spawnX, spawnY, spawnZ)
|
||||
cube.Parent = workspace
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
In Roblox, CFrame is a data type used to store 3D position and orientation. It's used to place objects in a world.
|
||||
</Alert>
|
||||
|
||||
### Spawn with nested loops
|
||||
|
||||
The script will have three loops total, one each for the length, width, and height of the tower. To complete an entire floor before moving upwards, start with setting the Y coordinate in the first, outermost loop.
|
||||
|
||||
1. Under the `makeCube()` function, Create a for loop to set how **high** each cube spawns.
|
||||
|
||||
- **Control variable**: `heightIndex = 1`
|
||||
- **End point**: `TOWER_SIZE`
|
||||
- Inside the loop, add: local spawnY = (heightIndex - 1) \* CUBE_SIZE
|
||||
|
||||
```lua
|
||||
-- Builds tower
|
||||
for heightIndex = 1, TOWER_SIZE do
|
||||
local spawnY = (heightIndex - 1) * CUBE_SIZE
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
The calculation for `spawnY` makes sure the first cube spawns at ground height and then moves over the space of a single cube every time. Ground level is at 0, which is why 1 needs to be subtracted from the `heightIndex`.
|
||||
</Alert>
|
||||
|
||||
2. With the first loop for height finished, start on the second. Inside the first for loop, add a new for loop for where to place the cube along the length of the tower.
|
||||
|
||||
- **Control variable**: lengthIndex = 1
|
||||
- **End point**: `TOWER_SIZE`
|
||||
- Inside that loop add: local spawnX = lengthIndex \* CUBE_SIZE
|
||||
|
||||
```lua
|
||||
for heightIndex = 1, TOWER_SIZE do
|
||||
local spawnY = (heightIndex - 1) * CUBE_SIZE
|
||||
|
||||
for lengthIndex = 1, TOWER_SIZE do
|
||||
local spawnX = lengthIndex * CUBE_SIZE
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
When working with nested loops, it's important to make sure code is well indented. This helps make your code readable and organized.
|
||||
</Alert>
|
||||
|
||||
3. Inside the **second** loop, add a **third** for loop for the tower **width**. In this final loop, call `makeCube()` and pass in the X,Y, Z parameters.
|
||||
|
||||
- **Control variable**: `widthIndex = 1`
|
||||
- **End point**: `TOWER_SIZE`
|
||||
- Inside the loop add:
|
||||
- `local spawnZ = widthIndex * CUBE_SIZE`
|
||||
- `makeCube(spawnX, spawnY, spawnZ)`
|
||||
- A wait time of 0.25 so you can watch the tower be built.
|
||||
|
||||
```lua
|
||||
-- Builds tower
|
||||
for heightIndex = 1, TOWER_SIZE do
|
||||
local spawnY = (heightIndex - 1) * CUBE_SIZE
|
||||
|
||||
for lengthIndex = 1, TOWER_SIZE do
|
||||
local spawnX = lengthIndex * CUBE_SIZE
|
||||
|
||||
for widthIndex = 1, TOWER_SIZE do
|
||||
local spawnZ = widthIndex * CUBE_SIZE
|
||||
makeCube(spawnX, spawnY, spawnZ)
|
||||
task.wait(0.25)
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
4. To have each floor be a random color, change `currentColor` to random `RGB` numbers in the same loop in which you create a new floor.
|
||||
|
||||
```lua
|
||||
for heightIndex = 1, TOWER_SIZE do
|
||||
local spawnY = (heightIndex - 1) * CUBE_SIZE
|
||||
currentColor = Color3.fromRGB(math.random(0, 255), math.random(0, 255), math.random(0, 255))
|
||||
for lengthIndex = 1, TOWER_SIZE do
|
||||
local spawnX = lengthIndex * CUBE_SIZE
|
||||
for widthIndex = 1, TOWER_SIZE do
|
||||
local spawnZ = widthIndex * CUBE_SIZE
|
||||
makeCube(spawnX, spawnY, spawnZ)
|
||||
task.wait(0.25)
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
5. Run the project and wait to see that a full tower has been created without any errors in the Output window.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/nestedLoop-finalExample.mp4" width="100%"></video>
|
||||
|
||||
## Optional challenges
|
||||
|
||||
Below are different self-directed challenges that use nested loops in different ways. Try and code on your own before looking at the solution.
|
||||
|
||||
### Fade away parts
|
||||
|
||||
As the tower is built, have the parts fade in transparency from left to right.
|
||||
|
||||
<img src="../../../assets/education/coding-4/Fade_480x320.png" width="60%" />
|
||||
|
||||
The code solution is below.
|
||||
|
||||
```lua
|
||||
local TOWER_SIZE = 6
|
||||
local CUBE_SIZE = 2
|
||||
|
||||
-- Creates individual cubes
|
||||
local function makeCube(spawnX, spawnY, spawnZ)
|
||||
local cube = Instance.new("Part")
|
||||
cube.Size = Vector3.new(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE)
|
||||
cube.Color = currentColor
|
||||
cube.Transparency = cubeTransparency -- Sets transparency
|
||||
cube.CFrame = CFrame.new(spawnX, spawnY, spawnZ)
|
||||
cube.Parent = workspace
|
||||
end
|
||||
|
||||
-- Builds tower
|
||||
for heightIndex = 1, TOWER_SIZE do
|
||||
local spawnY = (heightIndex - 1) * CUBE_SIZE
|
||||
currentColor = Color3.fromRGB(math.random(0, 255), math.random(0, 255), math.random(0, 255))
|
||||
|
||||
for lengthIndex = 1, TOWER_SIZE do
|
||||
local spawnX = lengthIndex * CUBE_SIZE
|
||||
cubeTransparency = (lengthIndex - 1) * 0.10 --Updates every loop starting at 0
|
||||
|
||||
for widthIndex = 1, TOWER_SIZE do
|
||||
local spawnZ = widthIndex * CUBE_SIZE
|
||||
makeCube(spawnX, spawnY, spawnZ)
|
||||
task.wait(0.05)
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Rain down objects
|
||||
|
||||
Instead of parts, try spawning an actual object. The example here used cupcakes.
|
||||
|
||||
On your own, see if you can:
|
||||
|
||||
- Create an object from base parts. Make sure to weld all parts together so the object doesn't fall apart.
|
||||
- Place the object in ServerStorage
|
||||
- Modify the PartMaker found in the [Nested Loop Example](#nested-loop-example)to use your object instead of parts.
|
||||
|
||||
A sample is shown here.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/CupCakeBloopers_Compressed.mp4" width="100%"></video>
|
||||
|
||||
A code solution using cupcakes is included.
|
||||
|
||||
```lua
|
||||
local numberOfBatches = 30
|
||||
local cupcakesPerBatch = 6
|
||||
|
||||
local cupcakesBaked = 0
|
||||
|
||||
--Makes a single cupcake
|
||||
local function makeCupcake()
|
||||
local ServerStorage = game:GetService("ServerStorage")
|
||||
local cupcake = ServerStorage.Cupcake:Clone()
|
||||
local cup = cupcake.Cup
|
||||
local frosting = cupcake.Frosting
|
||||
cupcake:SetPrimaryPartCFrame(CFrame.new(0, 20, 0) * CFrame.Angles(0, 0, -90))
|
||||
frosting.Color = frostingColor
|
||||
cup.Color = cupColor
|
||||
cupcake.Parent = workspace
|
||||
end
|
||||
|
||||
|
||||
-- Outer loop
|
||||
for cupcakeBatch = 1, numberOfBatches do
|
||||
print("Top outer loop: cupcake batch " .. cupcakeBatch)
|
||||
frostingColor = Color3.fromRGB(math.random(0, 255), math.random(0, 255), math.random(0, 255))
|
||||
cupColor = Color3.fromRGB(math.random(0, 255), math.random(0, 255), math.random(0, 255))
|
||||
|
||||
-- Inner loop
|
||||
for cupcakeNumber = 1, cupcakesPerBatch do
|
||||
makeCupcake()
|
||||
print("Inner loop: cupcake " .. cupcakeNumber)
|
||||
-- Track muffins baked
|
||||
cupcakesBaked += 1
|
||||
task.wait(0.5)
|
||||
end
|
||||
|
||||
print("Bottom outer loop: " .. cupcakesBaked .. " cupcakes baked so far.")
|
||||
end
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
To accomplish more complex tasks, coders will find it helpful to combine multiple loops, and even different types of loops. All loops can be nested, meaning that one loop is inside another. Nested loops follow the same logic as any other loop. It starts in the first, outermost loop, runs tasks through inner loops, and then cycles back to the first loop if applicable.
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
---
|
||||
title: Repeat code with while loops
|
||||
description: Learn how to use while loops with Roblox's Luau language in this computer science lesson.
|
||||
next: /tutorials/fundamentals/coding-4/intro-to-for-loops
|
||||
prev: /tutorials/fundamentals/coding-4/landing
|
||||
---
|
||||
|
||||
Many things in computer science or game development often repeat. For instance, an app might update content in a feed every few seconds, or a game might reward players a prize every day they're logged in. To accomplish this behavior, coders often use **loops**.
|
||||
|
||||
In computer science, a **loop** is a coding pattern that repeats a set of instructions, often until a specific condition is met. To practice this, you'll code a part that changes colors indefinitely. Later lessons will show how to stop the looping.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/loops-and-parts-finishedPart.mp4" width="100%"></video>
|
||||
|
||||
## Set up the part and script
|
||||
|
||||
Use any Roblox project for this exercise. When finished, this part can be used as a way of decorating an environment.
|
||||
|
||||
1. Create a new part with a descriptive name. This lesson uses **LoopingPart**.
|
||||
2. In **ServerScriptService**, add a new script named LoopingScript.
|
||||
3. In the script, delete `Hello World` and write a **comment** stating the purpose of this script.
|
||||
|
||||
```lua
|
||||
-- Changes the color of LoopingPart every few seconds
|
||||
```
|
||||
|
||||
## Use variables to store a part
|
||||
|
||||
Variables can also hold references to objects besides strings. For example, when a script knows the reference to a part, the script can change it.
|
||||
|
||||
Rather than typing `workspace.NameOfYourPart` over and over, that entire line can be stored inside a local variable. Local variables are created by typing `local` and then the name of the variable.
|
||||
|
||||
For example: `local nameOfVariable`.
|
||||
|
||||
<Alert severity="info">
|
||||
A local variable only works in the script where it was created. If a local variable named `part1` is created in Script1, it cannot be used in Script2. Most variables you use will be local variables.
|
||||
</Alert>
|
||||
|
||||
1. Under the comment, create a local variable by typing `local loopingPart`.
|
||||
|
||||
```lua
|
||||
-- Changes the color of LoopingPart every few seconds
|
||||
local loopingPart
|
||||
```
|
||||
|
||||
2. Set the variable to the looping part by typing `= workspace.LoopingPart` on the same line. Remember that the `=` operator sets the value of a variable to whatever is on the right of it.
|
||||
|
||||
```lua
|
||||
-- Changes the color of LoopingPart every few seconds
|
||||
local loopingPart = workspace.LoopingPart
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
Remember that the `=` operator sets the value of a variable to whatever is on the right of it.
|
||||
</Alert>
|
||||
|
||||
## While loops
|
||||
|
||||
Before creating the while loop for the color changing part, it's worthwhile to explain its syntax. A while loop has three components:
|
||||
|
||||
- The `while` keyword.
|
||||
- A condition, always after the keyword.
|
||||
- Instructions, between the `do` and `end` keywords.
|
||||
|
||||
In loops, conditions can be a variety of logical statements. Some examples might be if two numbers are the same. A loop will run if its condition is true.
|
||||
|
||||
Notice in the sample below, the condition is true, meaning this loop will run forever. In later lessons, you'll code specific conditions that stop.
|
||||
|
||||
```lua
|
||||
while true do
|
||||
print("This loop is running")
|
||||
end
|
||||
```
|
||||
|
||||
## Code a while loop
|
||||
|
||||
Next, you'll set up the while loop for the color changing part.
|
||||
|
||||
1. On the next line type `while true do`. Then, press <kbd>Enter</kbd> to autocomplete and add the word `end`.
|
||||
|
||||
```lua
|
||||
-- Changes the color of loopingPart every few seconds
|
||||
local loopingPart = workspace.LoopingPart
|
||||
|
||||
-- Looping Code
|
||||
while true do
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
You might have noticed the editor automatically added `end` to the script and indented the next line of code. Indenting makes code easier to read. Instructions in a loop should **always** be indented.
|
||||
</Alert>
|
||||
|
||||
### Add code in the loop
|
||||
|
||||
With the while loop created, instructions can be added to change the part's color over time. Inside the loop, add a line of code for each color. Each color will use RGB values, a way of storing colors as numbers in computer science.
|
||||
|
||||
1. Between `while true do` and `end`, set the Color property of the part to `Datatype.Color3.fromRGB()`.
|
||||
|
||||
```lua
|
||||
local loopingPart = workspace.LoopingPart
|
||||
|
||||
while true do
|
||||
loopingPart.Color = Color3.fromRGB()
|
||||
end
|
||||
```
|
||||
|
||||
2. Setting the color can be done using a color picker in Studio. To do so, left click inside the `()` next to `fromRGB`. Then, click on the color wheel icon. Once you have a desired color, press OK to automatically add the color value in the code.
|
||||
|
||||
```lua
|
||||
local loopingPart = workspace.LoopingPart
|
||||
|
||||
while true do
|
||||
loopingPart.Color = Color3.fromRGB(82, 227, 255)
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
If desired, a color can be created manually by assigning a value in each number from 0 to 255.
|
||||
</Alert>
|
||||
|
||||
### Make the script wait
|
||||
|
||||
If you add a second line of color changing code right now, it would change the brick's color so fast you might not even see the first color go by. To make the script wait before running the next line of code, use a `Library.task.wait()` function.
|
||||
|
||||
1. On the line after changing the brick color, type `task.wait(3)`. Whatever number placed inside the `()` is how many seconds the script will wait.
|
||||
|
||||
```lua
|
||||
local loopingPart = workspace.LoopingPart
|
||||
|
||||
while true do
|
||||
loopingPart.Color = Color3.fromRGB(82, 227, 255)
|
||||
task.wait(3)
|
||||
end
|
||||
```
|
||||
|
||||
2. Under the wait function, repeat the same process of adding a new color. Finish it with an additional wait function.
|
||||
|
||||
```lua
|
||||
while true do
|
||||
loopingPart.Color = Color3.fromRGB(82, 227, 255)
|
||||
task.wait(3)
|
||||
loopingPart.Color = Color3.fromRGB(177, 52, 255)
|
||||
task.wait(3)
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
As you add more code in the loop, make sure it's all in **scope**, meaning code is in the right place. In order for code to run in the loop, it has to be between the `while true do` and before `end`.
|
||||
</Alert>
|
||||
|
||||
3. Test the code and see if the colors change.
|
||||
|
||||
<video controls src="../../../assets/education/coding-4/loops-and-parts-finishedPart.mp4" width="100%"></video>
|
||||
|
||||
**Troubleshooting Notes**
|
||||
At this point, if the color changing part doesn't work as intended, try one of the following below.
|
||||
|
||||
**Issue**: Colors are skipped
|
||||
|
||||
- Make sure you have a wait function between each color change, especially at the last line.
|
||||
- Check that all the color change and wait code is between the `while true do` and `end` sections.
|
||||
|
||||
**Issue**: Part is still gray or doesn't change color as intended
|
||||
|
||||
- Make sure all RGB values have numbers from 0 to 255, are whole or decimals, and are separated by commas.
|
||||
- The numbers inside the `()` of a wait function should be greater than 1. It's possible that if a wait is too short, you may not see that color.
|
||||
|
||||
## Complete color looping part script
|
||||
|
||||
```lua
|
||||
-- Create a variable to store the part
|
||||
local loopingPart = workspace.LoopingPart
|
||||
|
||||
-- Looping Code
|
||||
while true do
|
||||
-- Changes loopingPart's color
|
||||
loopingPart.Color = Color3.fromRGB(82, 227, 255)
|
||||
-- Wait 3 seconds before next instruction
|
||||
task.wait(3)
|
||||
loopingPart.Color = Color3.fromRGB(177, 52, 255)
|
||||
task.wait(3)
|
||||
end
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Loops are a common element in most computer languages. They are used to repeat instructions, sometimes until specific conditions are met. In this article, the while loop is used to repeat instructions forever. To create a while loop that repeats forever, use the syntax below, being sure to include instructions between the `do` and `end` keywords.
|
||||
|
||||
```lua
|
||||
while true do
|
||||
-- Instructions
|
||||
end
|
||||
```
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
---
|
||||
title: Intro to arrays
|
||||
description: Learn how to use arrays in Luau to store multiple values at a time. This tutorial shows how to create and change arrays while making an interactive NPC in Roblox.
|
||||
next: /tutorials/fundamentals/coding-5/loops-and-arrays
|
||||
prev: /tutorials/fundamentals/coding-5/landing
|
||||
---
|
||||
|
||||
**Data structures** are how coders store and organize entire sets of data. In Luau, data structures are created with tables. **Tables** can hold any number of values.
|
||||
|
||||
This article covers using **arrays**, a specific table type, to create a talking character.
|
||||
|
||||
<img src="../../../assets/education/coding-5/coding4_introToTables.jpg" width="75%" />
|
||||
|
||||
## Tables
|
||||
|
||||
**Tables** are data types that can hold multiple values. Unlike other data types that store a single value, tables don't have a fixed size and can hold a mix of different value types. With tables, you can store items in a player's inventory or create a list of thousands of player names.
|
||||
|
||||
### Arrays
|
||||
|
||||
There are different types of tables. One type is an **array**, which stores lists of values in a specific order. To create an array, create a variable and assign it curly brackets `{ }`. Separate values within the brackets with commas like below:
|
||||
|
||||
`local myArray = {"item1", "item2", 10, workspace.Part, myVariable}`
|
||||
|
||||
### Create a talking character
|
||||
|
||||
To explore arrays, you'll work with a non-playable character (NPC) that, when clicked, shows a different line of dialogue.
|
||||
|
||||
<video controls src="../../../assets/education/coding-5/introArrays_projectTotal_optimized.mp4" width="80%"></video>
|
||||
|
||||
This project will use a pre-made NPC model, which includes a partial script and Prompt Detector but lacks dialogue.
|
||||
|
||||
1. Download the template NPC.
|
||||
|
||||
<a href="../../../assets/education/coding-5/TemplateNPC.rbxm">
|
||||
<Button variant="contained">Download</Button>
|
||||
</a>
|
||||
|
||||
2. In Explorer, import the NPC by right-clicking on **Workspace** ⟩ **Insert From File** and select the downloaded file.
|
||||
|
||||
## Code a dialogue array
|
||||
|
||||
These steps use an array to store different phrases for the NPC to say when players interact with it.
|
||||
|
||||
1. In the **Explorer**, go to **NPC** ⟩ **ProximityPrompt** ⟩ **ChatManager**.
|
||||
|
||||
2. In ChatManager, where marked in the script, create an **empty array** to store dialogue options.
|
||||
|
||||
```lua
|
||||
-- Cycles through chat dialogue when prompt is used
|
||||
|
||||
local Chat = game:GetService("Chat")
|
||||
|
||||
local prompt = script.Parent
|
||||
|
||||
local npc = prompt.Parent
|
||||
local characterParts = npc.CharacterParts
|
||||
local head = characterParts.Head
|
||||
|
||||
-- Add array here
|
||||
local dialogueArray = {}
|
||||
|
||||
local function speak()
|
||||
local dialogue = "I've got one thing to say!"
|
||||
Chat:Chat(head, dialogue)
|
||||
end
|
||||
|
||||
prompt.Triggered:Connect(speak)
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
This lesson uses the legacy chat API and is strictly for demonstrating how to use arrays. In real experiences, use `Class.TextChatService`.
|
||||
</Alert>
|
||||
|
||||
3. Within the brackets `{}` of the array just created, type at least three strings of dialogue, separated by commas.
|
||||
|
||||
```lua
|
||||
local dialogueArray = {"Hi!", "Do I know you?", "Goodbye!"}
|
||||
```
|
||||
|
||||
## Use array indexes
|
||||
|
||||
Each value in the array is assigned an `index` number. Indexes are assigned to values in the order in which the values are stored. The first value is at index 1, the second at index 2, and so forth.
|
||||
|
||||
Some coding languages, like Java, start indexes at 0.
|
||||
|
||||
In the array just created, `"Hi"` is at index 1, and `"Goodbye!"` is at index 3.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Index</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>Hi</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>Today's a great day!</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>Good bye!</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Use specific index values
|
||||
|
||||
Use index values to assign specific pieces of dialogue to the NPC. To use a value at a specific index, add the index in brackets directly after the array's name, like `dialogueArray[1]`.
|
||||
|
||||
1. Replace the `dialogue` variable's default string value with index 2.
|
||||
|
||||
```lua
|
||||
local dialogueArray = {"Hi!", "Do I know you?", "Goodbye!"}
|
||||
|
||||
local function speak()
|
||||
local dialogue = dialogueArray[2]
|
||||
Chat:Chat(head, dialogue)
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
If an index doesn't exist, a `nil` error will display in Output. For example, since this array only has three values, using `dialogueArray[4]` will result in an error.
|
||||
</Alert>
|
||||
|
||||
2. Playtest and click the NPC. The second array value should appear in the chat bubble. Try changing the code to test out each value in the table.
|
||||
|
||||
<img src="../../../assets/education/coding-5/introArrays_showSpeech.jpg" width="75%" />
|
||||
|
||||
## Change dialogue lines
|
||||
|
||||
When the player interacts with the NPC, the NPC will always say the same line. That's boring. Instead, use a variable to update which index value to use.
|
||||
|
||||
Whenever a player interacts with the NPC, increment the variable value by 1 to display the following line of dialogue.
|
||||
|
||||
1. To keep track of the current index, add a new variable named `dialogueIndex`. Set the variable to 1 to start at the beginning of the array.
|
||||
|
||||
```lua
|
||||
local dialogueArray = {"Hi!", "Do I know you?", "Goodbye!"}
|
||||
local dialogueIndex = 1
|
||||
```
|
||||
|
||||
2. In `speak()`, **replace** the index number in `dialogueArray[2]` with the variable you just created.
|
||||
|
||||
```lua
|
||||
local function speak()
|
||||
local dialogue = dialogueArray[dialogueIndex]
|
||||
Chat:Chat(head, dialogue)
|
||||
end
|
||||
```
|
||||
|
||||
3. At the bottom of the function, add 1 to `dialogueIndex`. The next time `speak()` is called, the dialogue will display the next string.
|
||||
|
||||
```lua
|
||||
local function speak()
|
||||
local dialogue = dialogueArray[dialogueIndex]
|
||||
Chat:Chat(head, dialogue)
|
||||
|
||||
dialogueIndex += 1
|
||||
end
|
||||
```
|
||||
|
||||
4. Playtest and click the NPC to see each dialogue string from the array.
|
||||
|
||||
<video controls src="../../../assets/education/coding-5/introArray_showDialogIndexes_optimized.mp4" width="75%"></video>
|
||||
|
||||
Notice there's an **error** in the Output window once the script reaches the end of the array.
|
||||
|
||||
You'll fix this in the next section so the dialogue restarts from the beginning after it shows the last string.
|
||||
|
||||
## Array sizes
|
||||
|
||||
You can use the size of the array to know when to reset the desired index to 1. Find the **size** of an array by typing `#`, without spaces, before an array's name.
|
||||
|
||||
For example: `#dialogueArray`
|
||||
|
||||
Check the array's size against the variable's current value to know when it's time to start back at the beginning.
|
||||
|
||||
### Restart the dialogue
|
||||
|
||||
Use the array size to check when it's time to cycle back to the first piece of dialogue.
|
||||
|
||||
1. Add an if statement and check if `dialogueIndex` equals `#dialogueArray`, the total size of this array. If so, then set `dialogueIndex` to 1.
|
||||
|
||||
```lua
|
||||
local function speak()
|
||||
local dialogue = dialogueArray[dialogueIndex]
|
||||
Chat:Chat(head, dialogue)
|
||||
|
||||
if dialogueIndex == #dialogueArray then
|
||||
dialogueIndex = 1
|
||||
end
|
||||
|
||||
dialogueIndex += 1
|
||||
end
|
||||
```
|
||||
|
||||
2. If `dialogueIndex` isn't at the end, it should still add 1 to `dialogueIndex`. Move `dialogueIndex += 1` under an else statement.
|
||||
|
||||
```lua
|
||||
local function speak()
|
||||
local dialogue = dialogueArray[dialogueIndex]
|
||||
Chat:Chat(head, dialogue)
|
||||
|
||||
dialogueIndex = if dialogueIndex == #dialogueArray then 1 else dialogueIndex + 1
|
||||
end
|
||||
```
|
||||
|
||||
3. Play and confirm you can cycle through and restart the dialogue.
|
||||
|
||||
<video controls src="../../../assets/education/coding-5/introArrays_showFullLoopIndexes_optimized.mp4" width="75%"></video>
|
||||
|
||||
## Summary
|
||||
|
||||
Data structures are how sets of data are stored. Luau uses tables to create data structures. Arrays are a type of table that can hold ordered lists of information. Each value within the array is assigned an index number, starting with index 1.
|
||||
|
||||
This script used an array to create a list of possible dialogue lines for a Non-Playable Character (NPC).
|
||||
|
||||
```lua title="Completed script"
|
||||
-- Cycles through chat dialogue when prompt is used
|
||||
|
||||
local Chat = game:GetService("Chat")
|
||||
|
||||
local prompt = script.Parent
|
||||
|
||||
local npc = prompt.Parent
|
||||
local characterParts = npc.CharacterParts
|
||||
local head = characterParts.Head
|
||||
|
||||
-- Add array here
|
||||
local dialogueArray = {"Hi!", "Do I know you?", "Goodbye!"}
|
||||
local dialogueIndex = 1
|
||||
|
||||
local function speak()
|
||||
local dialogue = dialogueArray[dialogueIndex]
|
||||
Chat:Chat(head, dialogue)
|
||||
|
||||
dialogueIndex = if dialogueIndex == #dialogueArray then 1 else dialogueIndex + 1
|
||||
end
|
||||
|
||||
prompt.Triggered:Connect(speak)
|
||||
```
|
||||
|
||||
### Troubleshooting tips
|
||||
|
||||
If the character doesn't go through the array of dialogue, try the following troubleshooting tips.
|
||||
|
||||
- Check the if statement that `dialogueIndex` is set back to 1. In the else statement, check that `dialogueIndex` has 1 added to itself.
|
||||
- When getting the array's size, ensure there are no spaces after the # in `#dialogueArray`.
|
||||
|
||||
## Optional challenges
|
||||
|
||||
Try one of the optional challenges below.
|
||||
|
||||
- Code the script so the NPC's dialogue goes backward through the array. The dialogue index should start at the array length and subtract each time instead of adding.
|
||||
- Instead of showing dialogue in order, have the NPC show a random line of dialogue each time using `Datatype.Random.new()`. A sample script is included below to reference
|
||||
|
||||
```lua
|
||||
local randomGenerator = Random.new()
|
||||
|
||||
-- Shows a new dialogue whenever the NPC is clicked
|
||||
local function speak()
|
||||
local randomIndex = randomGenerator:NextInteger(1, #dialogueArray)
|
||||
local dialogue = dialogueArray[randomIndex]
|
||||
Chat:Chat(head, dialogue)
|
||||
end
|
||||
```
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
---
|
||||
title: Intro to dictionaries
|
||||
description: Learn how to use a dictionary table to tag values within data sets.
|
||||
next: /tutorials/fundamentals/coding-5/pairs-and-ipairs
|
||||
prev: /tutorials/fundamentals/coding-5/make-changes-to-arrays
|
||||
---
|
||||
|
||||
Dictionaries are tables that associate names or **keys** with a value instead of an index.
|
||||
|
||||
Example:
|
||||
|
||||
```lua title="Luau dictionary syntax"
|
||||
local pet = {
|
||||
Name = "Bobbie",
|
||||
Type = "Dog",
|
||||
}
|
||||
```
|
||||
|
||||
Use dictionaries when you need to label values, not just list them in order as an array does. Practice using dictionaries in this tutorial by manipulating values associated with a player.
|
||||
|
||||
## Dictionary syntax
|
||||
|
||||
Like arrays, dictionaries are assigned to a variable with curly brackets `{}`. **Key-value pairs** are stored on separate lines followed by a comma. Keys and values can be any data type, including strings, numbers, and variable names.
|
||||
|
||||
```lua
|
||||
local playerNames = {
|
||||
player1 = "Zap",
|
||||
player2 = "Kel",
|
||||
}
|
||||
print(playerNames["player1"])
|
||||
```
|
||||
|
||||
To reference parts or other instanced objects as keys, use brackets.
|
||||
|
||||
```lua
|
||||
local greenPart = workspace.GreenPart
|
||||
local redPart = workspace.RedPart
|
||||
|
||||
local partList = {
|
||||
[greenPart] = true,
|
||||
[redPart] = false,
|
||||
}
|
||||
print(partList[redPart])
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
Use consistent data types for dictionary keys. Mixing data types, such as using both strings and variables for keys, can lead to inconsistent results when manipulating the array and confuse other coders.
|
||||
</Alert>
|
||||
|
||||
## Create a dictionary
|
||||
|
||||
One everyday use of dictionaries is organizing player or character information. These steps explore how a theoretical enemy character's information can be stored and accessed.
|
||||
|
||||
1. In a new script, create a dictionary named `enemy`.
|
||||
|
||||
```lua
|
||||
local enemy = {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
2. The first key in the dictionary will track the enemy's name with a variable called `Name`.
|
||||
|
||||
```lua
|
||||
local enemy = {
|
||||
Name
|
||||
}
|
||||
```
|
||||
|
||||
3. Assign an enemy name to the key, followed by a comma.
|
||||
|
||||
```lua
|
||||
local enemy = {
|
||||
Name = "Spike",
|
||||
}
|
||||
```
|
||||
|
||||
4. Add a second key-value pair for how much health the enemy should have. Remember, keys should always use the same data type, but values don't have to.
|
||||
|
||||
```lua
|
||||
local enemy = {
|
||||
Name = "Spike",
|
||||
Health = 1000,
|
||||
}
|
||||
```
|
||||
|
||||
### Use dictionary values
|
||||
|
||||
There are two ways to access dictionary values:
|
||||
|
||||
- `tableName["keyName"]` (importantly, note the quotations)
|
||||
- `tableName.keyName`
|
||||
|
||||
```lua
|
||||
local enemy = {
|
||||
Name = "Spike",
|
||||
Health = 1000,
|
||||
}
|
||||
|
||||
print("The villain " .. enemy["Name"] .. " approaches!")
|
||||
print("The villain " .. enemy.Name .. " approaches!")
|
||||
```
|
||||
|
||||
Which style to use usually depends on the purpose of the table. For tables holding a collection of values like a list of players in a server, coders will usually use `tableName["keyName"]`. For a dictionary used to describe an object, coders are more likely to use `tableName.keyName`.
|
||||
|
||||
## Change a dictionary value
|
||||
|
||||
Changing a key's value is the same as any other variable; use the equal `=` operator.
|
||||
|
||||
1. Beneath the `enemy` table, set the enemy's name to something else.
|
||||
|
||||
```lua
|
||||
local enemy = {
|
||||
Name = "Spike",
|
||||
Health = 1000,
|
||||
}
|
||||
|
||||
enemy.Name = "Rana"
|
||||
|
||||
print("The enemy's name is " .. enemy.Name)
|
||||
```
|
||||
|
||||
2. Playtest and check the Output window.
|
||||
|
||||
## Pre-existing variables as keys
|
||||
|
||||
Dictionaries can interact with pre-existing variables declared in other parts of a script. The following coding example uses a variable to add a player's name as a key when they join the experience and then sets their points value to 0.
|
||||
|
||||
1. In **ServerScriptService**, create a new script named PlayerPoints. In the script, get the Players Service and create an empty dictionary named `playerPoints`.
|
||||
|
||||
```lua
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
local playerPoints = {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
2. Code a local function for setting player points with a parameter for a new player variable. Connect the function to the `Class.Players.PlayerAdded` event.
|
||||
|
||||
```lua
|
||||
local playerPoints = {
|
||||
|
||||
}
|
||||
|
||||
local function setPoints(newPlayer)
|
||||
|
||||
end
|
||||
|
||||
Players.PlayerAdded:Connect(setPoints)
|
||||
```
|
||||
|
||||
3. In the function, add a variable to get the player's `Name`, a property in every **Player** object, and a print statement for testing.
|
||||
|
||||
```lua
|
||||
local function setPoints(newPlayer)
|
||||
local name = newPlayer.Name
|
||||
print("hello " .. name)
|
||||
end
|
||||
```
|
||||
|
||||
4. Insert `name` into the `playerPoints` dictionary as a key, and set the value, the player's points, to 0.
|
||||
|
||||
```lua
|
||||
local function setPoints(newPlayer)
|
||||
local name = newPlayer.Name
|
||||
print("hello " .. name)
|
||||
playerPoints[name] = 0
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
Since `name` was created as a variable, it can be accessed with the actual variable name. If `name` were a key name, it would need to be accessed the same as other strings: `playerPoints["name"]`.
|
||||
</Alert>
|
||||
|
||||
5. Use `name` to print the name of the player and `playerPoints[name]` to print the value of the key matching the variable.
|
||||
|
||||
```lua
|
||||
local function setPoints(newPlayer)
|
||||
local name = newPlayer.Name
|
||||
print("hello " .. name)
|
||||
playerPoints[name] = 0
|
||||
print(name .. " has " .. playerPoints[name] .. " points.")
|
||||
end
|
||||
```
|
||||
|
||||
6. Run the project and observe the output.
|
||||
|
||||
```lua title="Finished script"
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
local playerPoints = {
|
||||
|
||||
}
|
||||
|
||||
local function setPoints(newPlayer)
|
||||
local name = newPlayer.Name
|
||||
print("hello " .. name)
|
||||
playerPoints[name] = 0
|
||||
print(name .. " has " .. playerPoints[name] .. " points.")
|
||||
end
|
||||
|
||||
Players.PlayerAdded:Connect(setPoints)
|
||||
```
|
||||
|
||||
### Optional challenges
|
||||
|
||||
Below are some challenges that apply to using dictionaries in different ways. See if you can build out the code for these.
|
||||
|
||||
- Create a trap part that does damage over time to a player. Once a player touches the trap, damage them, wait, then allow them to be damaged again.
|
||||
- Create a function that checks which of two players has the most points by accessing a dictionary.
|
||||
- Create a cipher, a system of swapping one string for another to create a "secret" code. For example, the letter "A" can be swapped with "G," or the word "apple" can be swapped with "orange."
|
||||
|
||||
## Dictionaries and pairs()
|
||||
|
||||
`pairs()` is a function that's often used to iterate through **dictionaries**. An example is seen below.
|
||||
|
||||
```lua
|
||||
local myDictionary = {
|
||||
["Blue Player"] = "Ana",
|
||||
["Gold Player"] = "Binh",
|
||||
["Red Player"] = "Cate",
|
||||
}
|
||||
|
||||
for key, value in pairs(myDictionary) do
|
||||
print(key .. " is " .. value)
|
||||
end
|
||||
```
|
||||
|
||||
`pairs()` can be used to work with a dictionary element's key, value, or both. In the for loop below, the first variable is the key. The second variable is the value. The dictionary that you want to work with is passed in to `pairs()`.
|
||||
|
||||
```lua
|
||||
local inventory = {
|
||||
["Gold Bricks"] = 43,
|
||||
Carrots = 3,
|
||||
Torches = 2,
|
||||
}
|
||||
|
||||
print("You have:")
|
||||
|
||||
for itemName, itemValue in pairs(inventory) do
|
||||
print(itemValue, itemName)
|
||||
end
|
||||
```
|
||||
|
||||
When executed, the code will print the following:
|
||||
|
||||
```lua
|
||||
You have:
|
||||
43 Gold Bricks
|
||||
3 Carrots
|
||||
2 Torches
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Dictionaries are tables that use key-value pairs instead of indexed values. Dictionaries and arrays start similarly by assigning curly brackets to a variable. Keep entries separated with commas.
|
||||
|
||||
All keys within a dictionary should use the same data type, but the values can mix data types without issue.
|
||||
|
||||
The way in which a dictionary is accessed can convey its purpose. A dictionary of enemy properties will likely be accessed with the dot operator, while a list of names will likely use `tableName[keyName]`.
|
||||
|
||||
When using brackets, be careful; key names created within the table must be treated as strings: `tableName["keyName"]`. However, when referencing objects like parts, the quotations are not needed: `tableName[keyName]`.
|
||||
|
||||
Many scripts need to go through dictionaries or arrays, but you may not always know the start and end of these data structures. For example, a dictionary of players may be changing, or players may have an array inventory of varying sizes.
|
||||
|
||||
In these situations, you can use `pairs()` and `ipairs()` in a `for` loop to go through each element without known start and end points. You can also use general iteration through the `in` keyword to loop through elements without the need for `pairs()` or `ipairs()`.
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
---
|
||||
title: Arrays and dictionaries
|
||||
description: Learn how to store data in tables with arrays and dictionaries in Luau.
|
||||
next: /tutorials/fundamentals/coding-5/intro-to-arrays
|
||||
prev: /tutorials/fundamentals/coding-4/nested-loops
|
||||
---
|
||||
|
||||
### Series description
|
||||
|
||||
Data structures are how coders store and organize entire sets of data. In Luau, data structures are tables. Unlike variables, tables can hold any number of values. Tables can store a list of high scores, a player's inventory, or all of an object's properties. Two types of tables covered in this series are **dictionaries** and **arrays**.
|
||||
|
||||
### Objectives and prerequisites
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="20%"><b>Learning Objectives</b></td>
|
||||
<td>
|
||||
Learn common structures for storing sets of information, such as arrays and dictionaries, and use cases for each structure.
|
||||
|
||||
Be able to manipulate data structures, such as adding, removing, or returning values from a structure like an array.
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Prerequisites</b></td>
|
||||
<td>
|
||||
Have a general understanding of variables in Luau.
|
||||
|
||||
Feel comfortable using conditional statements (`if` and `else`) and loops (`for` and `while`).
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Series contents
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Article</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[Intro to arrays](../coding-5/intro-to-arrays.md)</td>
|
||||
<td>Learn how to store like groupings of data together with arrays.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Loops and arrays](../coding-5/loops-and-arrays.md)</td>
|
||||
<td>Combine arrays with loops to repeat code with a disappearing path trap.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Make changes to arrays](../coding-5/make-changes-to-arrays.md)</td>
|
||||
<td>Add and remove values in arrays by coding a script to manage a player's inventory</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Intro to dictionaries](../coding-5/intro-to-dictionaries.md)</td>
|
||||
<td>Organize complex sets of data with pairs using dictionaries.</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
---
|
||||
title: Loops and arrays
|
||||
description: Learn how to iterate, or go through, arrays in Luau using loops.
|
||||
next: /tutorials/fundamentals/coding-5/make-changes-to-arrays
|
||||
prev: /tutorials/fundamentals/coding-5/intro-to-arrays
|
||||
---
|
||||
|
||||
**Arrays** can be combined with loops, such as **while** and **for**, to repeat the same code for each indexed value. For example, teleporting each player in an array to a new place or making an array of parts catch fire.
|
||||
|
||||
To explore looping through arrays, create a disappearing bridge path where parts are placed into an array and then made to vanish one by one.
|
||||
|
||||
<video controls src="../../../assets/education/coding-5/disappearingHero_16_9web.mp4" width="75%"></video>
|
||||
|
||||
## Loop through an array
|
||||
|
||||
For the project, find or create a set of three parts to make disappear. The parts must all be anchored.
|
||||
|
||||
1. Create three parts. Name the parts in the order they should disappear, Part1, Part2, Part3.
|
||||
|
||||
2. In ServerScriptService, insert a new script and create an array to store the parts.
|
||||
|
||||
```lua
|
||||
local pathArray = {
|
||||
}
|
||||
```
|
||||
|
||||
3. On a single line each, type the name of the parts in the order they should disappear. Using a new line for each value makes it easier to read.
|
||||
|
||||
```lua
|
||||
local pathArray = {
|
||||
workspace.Part1,
|
||||
workspace.Part2,
|
||||
workspace.Part3,
|
||||
}
|
||||
```
|
||||
|
||||
### Use a for loop with an array
|
||||
|
||||
Use a for loop to go through the array and control how fast the parts should disappear in the order the parts are indexed within the array.
|
||||
|
||||
1. To control how often a part disappears in seconds, create a variable named `VANISH_RATE`. For testing, it's best to keep it to a small number.
|
||||
|
||||
```lua
|
||||
local VANISH_RATE = 1.5
|
||||
|
||||
local pathArray = {
|
||||
workspace.Part1,
|
||||
workspace.Part2,
|
||||
workspace.Part3
|
||||
}
|
||||
```
|
||||
|
||||
<Alert severity='info'>
|
||||
**Constants** are variables that shouldn't be changed by any other code in the script. They're likely to need adjusting and are put at the top of the script in `ALL_CAPS` to make them easy to spot.
|
||||
</Alert>
|
||||
|
||||
2. Create a for loop with the following: **Start:** `partIndex = 1`, the index of the first value in the array. **End:** `#pathArray`, the size of that array.
|
||||
|
||||
```lua
|
||||
for partIndex = 1, #pathArray do
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
3. So there's a delay before a part disappears, in the loop, add a `Library.task.wait()` using `VANISH_RATE`.
|
||||
|
||||
```lua
|
||||
for partIndex = 1, #pathArray do
|
||||
task.wait(VANISH_RATE)
|
||||
end
|
||||
```
|
||||
|
||||
4. To get a part to disappear, create a new variable named `whichPart` and set it equal to `partsArray[partIndex]`. Then, to disappear that part, set it's `CanCollide` property to false and `Transparency` to 1.
|
||||
|
||||
```lua
|
||||
for partIndex = 1, #pathArray do
|
||||
task.wait(VANISH_RATE)
|
||||
local whichPart = pathArray[partIndex]
|
||||
whichPart.CanCollide = false
|
||||
whichPart.Transparency = 1
|
||||
end
|
||||
```
|
||||
|
||||
5. Check that parts of the path disappear over time.
|
||||
|
||||
<video controls src="../../../assets/education/coding-5/showPathDisappearFirst_web.mp4" width="100%"></video>
|
||||
|
||||
### Troubleshooting tips
|
||||
|
||||
If the bridge doesn't disappear, check the possible issues below:
|
||||
|
||||
**Issue:** Parts disappear too fast or are all gone at the start.
|
||||
|
||||
- Depending on how fast your character loads into the experience, the first parts may already be invisible. To address this, add a small wait, such as `task.wait(2)`, at the start of the script.
|
||||
|
||||
### Code the second loop
|
||||
|
||||
Right now, the parts disappear forever. To make them reappear, create a second for loop that will go through each part and instantly make each piece walkable.
|
||||
|
||||
1. After the first loop, add a `Library.task.wait()` to create a short delay before the path reappears.
|
||||
|
||||
```lua
|
||||
for partIndex = 1, #pathArray do
|
||||
task.wait(VANISH_RATE)
|
||||
local whichPart = pathArray[partIndex]
|
||||
whichPart.CanCollide = false
|
||||
whichPart.Transparency = 1
|
||||
end
|
||||
|
||||
task.wait(1)
|
||||
```
|
||||
|
||||
2. **On your own**, try coding a second for loop that makes the path usable again by changing each part's CanCollide property to true and Transparency to 0. When finished, check your work against the code below.
|
||||
|
||||
```lua
|
||||
-- Reset the path by making all parts walkable again
|
||||
for partIndex = 1, #pathArray do
|
||||
local whichPart = pathArray[partIndex]
|
||||
whichPart.CanCollide = true
|
||||
whichPart.Transparency = 0
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity='warning'>
|
||||
Unanchored parts will fall through the baseplate when CanCollide is false. If the parts aren't reappearing, and there are no Output errors, anchor the parts and test again.
|
||||
</Alert>
|
||||
|
||||
3. Test the project to confirm that once all parts disappear, they come back.
|
||||
|
||||
<video controls src="../../../assets/education/coding-5/showPathDisappearIndexed_web.mp4" width="100%"></video>
|
||||
|
||||
## Repeat with a while loop
|
||||
|
||||
The parts disappear and reappear, but only once. To make the code keep repeating, nest all of the code within a while loop.
|
||||
|
||||
1. At the bottom of the script, create a new while true do loop. Then, **move both** for loops into the while loop.
|
||||
|
||||
```lua
|
||||
while true do
|
||||
-- Make a part disappear from the array in order
|
||||
for partIndex = 1, #pathArray do
|
||||
task.wait(VANISH_RATE)
|
||||
local whichPart = pathArray[partIndex]
|
||||
whichPart.CanCollide = false
|
||||
whichPart.Transparency = 1
|
||||
end
|
||||
|
||||
-- Wait for a second before making the path reappear
|
||||
task.wait(1)
|
||||
|
||||
-- Reset the path by making all parts walkable again
|
||||
for partIndex = 1, #pathArray do
|
||||
local whichPart = pathArray[partIndex]
|
||||
whichPart.CanCollide = true
|
||||
whichPart.Transparency = 0
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
2. Check that once all parts disappear, they reappear.
|
||||
|
||||
<video controls src="../../../assets/education/coding-5/showPathDisappearIndexed_web.mp4" width="80%"></video>
|
||||
|
||||
A finished version of the project can be downloaded.
|
||||
|
||||
```lua title="Completed script"
|
||||
local VANISH_RATE = 1.0
|
||||
|
||||
local pathArray = {
|
||||
workspace.Part1,
|
||||
workspace.Part2,
|
||||
workspace.Part3,
|
||||
}
|
||||
|
||||
while true do
|
||||
-- Make a part disappear from the array in order
|
||||
for partIndex = 1, #pathArray do
|
||||
task.wait(VANISH_RATE)
|
||||
local whichPart = pathArray[partIndex]
|
||||
whichPart.CanCollide = false
|
||||
whichPart.Transparency = 1
|
||||
end
|
||||
|
||||
-- Wait for a second before making the path reappear
|
||||
task.wait(1.0)
|
||||
|
||||
-- Reset the path by making all parts walkable again
|
||||
for partIndex = 1, #pathArray do
|
||||
local whichPart = pathArray[partIndex]
|
||||
whichPart.CanCollide = true
|
||||
whichPart.Transparency = 0
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Arrays and ipairs()
|
||||
|
||||
`ipairs()` is used with **arrays**. The "i" in `ipairs()` stands for "index." ipairs() can be used to quickly repeat an operation on a lot of objects, like, say, a folder full of parts.
|
||||
|
||||
This will be demonstrated by quickly adding particles to a whole folder of parts.
|
||||
|
||||
1. In Workspace, create a folder named PartsFolder. Add as many parts as you like.
|
||||
|
||||
2. In ServerScriptService, Create a new script and reference the folder.
|
||||
|
||||
3. Use GetChildren() to automatically get an array listing all the objects in the folder.
|
||||
|
||||
```lua
|
||||
local partsFolder = workspace.PartsFolder
|
||||
|
||||
-- Gets an array listing the parts in PartsFolder
|
||||
local partsArray = partsFolder:GetChildren()
|
||||
```
|
||||
|
||||
4. Use `in ipairs(ArrayToUse)` with the for loop to go through partsArray and add particles.
|
||||
|
||||
```lua title="Completed script"
|
||||
-- Gets an array listing the parts in PartsFolder
|
||||
local partsArray = partsFolder:GetChildren()
|
||||
|
||||
-- Adds particles to every part in the array
|
||||
for index, part in ipairs(partsArray) do
|
||||
local particles = Instance.new("ParticleEmitter")
|
||||
particles.Parent = part
|
||||
end
|
||||
```
|
||||
|
||||
Playtest and watch the particles float up from every part in the folder.
|
||||
|
||||
## Summary
|
||||
|
||||
Loops can be combined with arrays to work with any number of values quickly. If you want to have exact control over what happens to a few parts and in what order, an array must be hard-coded with specific values.
|
||||
|
||||
To work with many parts where order doesn't matter, GetChildren() can create an array of an object's children. Utilizing `ipairs()`, the list can be quickly iterated over without knowing the array's size.
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
---
|
||||
title: Make changes to arrays
|
||||
description: Learn how to add, remove, and find values in an array in Luau using tables.
|
||||
next: /tutorials/fundamentals/coding-5/intro-to-dictionaries
|
||||
prev: /tutorials/fundamentals/coding-5/loops-and-arrays
|
||||
---
|
||||
|
||||
An array's contents will often have to be changed, like when needing to remove an item from a player's inventory. Luau has **built-in functions** for use with tables to make this easier.
|
||||
|
||||
This article will outline prebuilt functions for tables like add and remove while describing how to search for a value.
|
||||
|
||||
To apply these skills, you'll create a script that helps to manage a player's inventory.
|
||||
|
||||
<img src="../../../assets/education/coding-5/coding4_arrayFunctions.jpg" width="80%" />
|
||||
|
||||
## Add values to arrays
|
||||
|
||||
To add a new value to an array, use `table.insert(array, valueToInsert)`. The second parameter can be any value such as a string, number, or entire object, like `Class.Player` or `Class.IntValue`.
|
||||
|
||||
To practice, you'll create a script that stores player items in a table, then add to it. Since this example is just a script, it can be used with any file or project. Testing the code will be done using the Output window.
|
||||
|
||||
1. Create an empty array named `playerItems`.
|
||||
|
||||
```lua
|
||||
playerItems = {}
|
||||
```
|
||||
|
||||
2. Add inventory items to the array by typing `Library.table.insert()`. In the parenthesis, type `playerItems`, the table to add to, followed by a string for each item. Insert at least three values.
|
||||
|
||||
```lua
|
||||
playerItems = {}
|
||||
|
||||
table.insert(playerItems, "Potion")
|
||||
table.insert(playerItems, "Bread")
|
||||
table.insert(playerItems, "Sleeping Bag")
|
||||
|
||||
print(playerItems)
|
||||
```
|
||||
|
||||
3. Run the project. In Output, expand the three dots `...` to see the printed table.
|
||||
|
||||
## Remove values from arrays
|
||||
|
||||
To remove a value, like if a player used an item or someone in a list of active players leaves an experience, use `Library.table.remove()`. Depending on the parameters provided, the function can either remove the last value of a table, or at a specific index.
|
||||
|
||||
### Remove the last value
|
||||
|
||||
Sometimes a script needs to remove a specific item. For instance, removing the first item in a player's inventory, or picking the first player in a list. To remove the last value in an array, use `Library.table.remove(arrayName)`. In this use case, the only parameter needed is the table itself.
|
||||
|
||||
1. Use the array of items from the previous example. Then, to remove the last value from the table, in this case `"Sleeping Bag"`, type `Library.table.remove(playerItems)`
|
||||
|
||||
```lua
|
||||
playerItems = {}
|
||||
|
||||
table.insert(playerItems, "Potion")
|
||||
table.insert(playerItems, "Bread")
|
||||
table.insert(playerItems, "Sleeping bag")
|
||||
|
||||
table.remove(playerItems)
|
||||
|
||||
print(playerItems)
|
||||
```
|
||||
|
||||
2. Run the project. In the Output window, the last value, `"Sleeping Bag"`, shouldn't print.
|
||||
|
||||
### Remove by index
|
||||
|
||||
To remove a value at a specific point in the array, input in the second parameter the index to remove, such as `table.remove(arrayName, 1)`.
|
||||
|
||||
1. Using the same table, type `Library.table.remove()`. In the parameters, input the name of the table and `1`, the value to remove.
|
||||
|
||||
```lua
|
||||
playerItems = {}
|
||||
|
||||
table.insert(playerItems, "Potion")
|
||||
table.insert(playerItems, "Bread")
|
||||
table.insert(playerItems, "Sleeping bag")
|
||||
|
||||
table.remove(playerItems, 1)
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
The second parameter for `Library.table.remove()` only accepts a numerical index. Typing something like `"Potion"` will create an error.
|
||||
</Alert>
|
||||
|
||||
2. Run the project. Check that the first value, "Potion" was removed.
|
||||
|
||||
<Alert severity="info">
|
||||
Notice also that all the index values changed or have been pushed. Removing a value from an array will change the array size and shift index values **down** after the one removed. `"Bread"` is now index 1, and `"Sleeping Bag"` is now index 2.
|
||||
</Alert>
|
||||
|
||||
## Search for values in an array
|
||||
|
||||
To find specific values in arrays, like the name of a winning player, use the `Library.table.find()` function. Alternatively, you can code your own search function using `for` loops and `if` statements.
|
||||
|
||||
### Find and return a single value
|
||||
|
||||
To find a value in an array, create a function named `findValue()` that goes through an array and stops the first time it finds a matching value.
|
||||
|
||||
Once it finds the value, the function will use the `return` keyword to return that value's index. With an index, you can remove it from the array.
|
||||
|
||||
1. Copy the array named `playerItems` below.
|
||||
|
||||
```lua
|
||||
local playerItems = {
|
||||
"Potion",
|
||||
"Bread",
|
||||
"Bread",
|
||||
"Sleeping Bag"
|
||||
}
|
||||
```
|
||||
|
||||
2. Code a new function named findValue() with two parameters:
|
||||
|
||||
- `whichArray` - the array to search through.
|
||||
- `itemName` - the specific string to check for.
|
||||
|
||||
```lua
|
||||
local function findValue(whichArray, itemName)
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
3. In `findValue()`, use a for loop to check if any value in the array matches `itemName`. If the value matches, use the keyword `return` to return the value found in `currentIndex`.
|
||||
|
||||
```lua
|
||||
local function findValue(whichArray, itemName)
|
||||
for currentIndex = 1, #whichArray do
|
||||
if whichArray[currentIndex] == itemName then
|
||||
return currentIndex
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
4. Test the search function by creating a variable named `valueFound` and calling `findValue()`. Pass in the array to search, and what value it should search for. **Run** the code to confirm that the expected output is index 2.
|
||||
|
||||
```lua
|
||||
local function findValue(whichArray, itemName)
|
||||
for currentIndex = 1, #whichArray do
|
||||
if whichArray[currentIndex] == itemName then
|
||||
--Sends the value of currentIndex back
|
||||
return currentIndex
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local valueFound = findValue(playerItems, "Bread")
|
||||
|
||||
print("The value is at index " .. valueFound)
|
||||
```
|
||||
|
||||
### Remove a value
|
||||
|
||||
If a value was found using the find function, it can be removed. Check if a value was found with an if statement.
|
||||
|
||||
1. Check if a value is inside `valueFound`; if so, remove the value using `Library.table.remove()`.
|
||||
|
||||
```lua
|
||||
if valueFound then
|
||||
table.remove(playerItems, valueFound)
|
||||
end
|
||||
```
|
||||
|
||||
2. Print out the array using the code below.
|
||||
|
||||
```lua
|
||||
for index = 1, #playerItems do
|
||||
local itemString = playerItems[index]
|
||||
print("Index " .. index .. ": " .. itemString)
|
||||
end
|
||||
```
|
||||
|
||||
3. Playtest and check that the first `"Bread"` value was removed from the array. Try removing other values by changing the second parameter in `findValue()`.
|
||||
|
||||
Notice that because this function was called once, only the first instance of `"Bread"` was removed. The following section will cover how to find and remove all instances.
|
||||
|
||||
## Find and remove all of a specific value
|
||||
|
||||
While the previous code could only remove the first instance of a value found, this code snippet will find and remove all occurrences from an array. For example, if, say, a player wanted to sell all their bread at an in-game store.
|
||||
|
||||
1. Use an array named `playerItems` with at least four values and a set of **duplicates**.
|
||||
|
||||
```lua
|
||||
local playerItems = {
|
||||
"Potion",
|
||||
"Bread",
|
||||
"Bread",
|
||||
"Sleeping Bag"
|
||||
}
|
||||
```
|
||||
|
||||
2. To go through the array, create a for loop that goes **backward** through `playerItems`, starting at `#playerItems`, ending at 1, and incrementing by -1.
|
||||
|
||||
```lua
|
||||
for index = #playerItems, 1, -1 do
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
Remember, removing items causes later indexes to shift. By starting at the end, you avoid skipping a value that may have shifted if you started at the beginning.
|
||||
</Alert>
|
||||
|
||||
3. In the loop, use an if statement to check if the value inside `playerItems[index]` is equal to `"Bread"`, and if so, remove the item.
|
||||
|
||||
```lua
|
||||
for index = #playerItems, 1, -1 do
|
||||
if playerItems[index] == "Bread" then
|
||||
table.remove(playerItems, index)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
4. Use the code below to add a second for loop that prints the array.
|
||||
|
||||
```lua
|
||||
for index = 1, #playerItems do
|
||||
local itemString = playerItems[index]
|
||||
print("Index " .. index .. ": " .. itemString)
|
||||
end
|
||||
```
|
||||
|
||||
5. Run the script and check that all values named "Bread" are removed.
|
||||
|
||||
## Summary
|
||||
|
||||
Values can be removed or added to an array, but be careful of indexes shifting doing so. Use loops to iterate through a table to remove all instances of a value, or just the first instance found.
|
||||
|
||||
The keyword `return` can be used to stop a loop, and send information back where needed.
|
||||
|
||||
A finished version of the script can be referenced below.
|
||||
|
||||
The following project includes all scripts in this tutorial. Download [here](../../../assets/education/coding-5/Making_Changes_to_Arrays_-_Final_Project.rbxl).
|
||||
|
||||
Note all scripts are in **ServerScriptService** and **disabled**. To use a script, in its properties, uncheck the Disabled field and run Studio.
|
||||
|
||||
<Alert severity="info">
|
||||
For complete list of all table functions, go to `Library.table|Table API`
|
||||
</Alert>
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
---
|
||||
title: pairs and ipairs
|
||||
description: pairs() and ipairs() are used to go through Luau tables. This lesson covers how to code them for a script and when to use them.
|
||||
next: /tutorials/fundamentals/coding-5/return-values-from-tables
|
||||
prev: /tutorials/fundamentals/coding-5/intro-to-dictionaries
|
||||
---
|
||||
|
||||
Many scripts will often need to go through dictionaries or arrays. But sometimes, you may not know the start and end of these data structures. For example, a dictionary of players may be changing, or players may have an array inventory of varying sizes.
|
||||
|
||||
In these situations, you can use `pairs()` and `ipairs()`. These can be used with a for loop to go through each element without known start and end points.
|
||||
|
||||
This article will cover using them, and have a practical script example where you track restaurant orders in a cooking game.
|
||||
|
||||
## Dictionaries and pairs()
|
||||
|
||||
`pairs()` is used with **dictionaries**. An example is seen below.
|
||||
|
||||
```lua
|
||||
local myDictionary = {
|
||||
["Blue Player"] = "Ana",
|
||||
["Gold Player"] = "Binh",
|
||||
["Red Player"] = "Cate",
|
||||
}
|
||||
|
||||
for key, value in pairs(myDictionary) do
|
||||
print(key .. " is " .. value)
|
||||
end
|
||||
```
|
||||
|
||||
`pairs()` can be used to work with a dictionary element's key, value, or both. In the for loop below, the first variable is the key. The second variable is the value. The dictionary that you want to work with is passed in to `pairs()`.
|
||||
|
||||
```lua
|
||||
local inventory = {
|
||||
["Gold Bricks"] = 43,
|
||||
Carrots = 3,
|
||||
Torches = 2,
|
||||
}
|
||||
|
||||
print("You have:")
|
||||
|
||||
for itemName, itemValue in pairs(inventory) do
|
||||
print(itemValue, itemName)
|
||||
end
|
||||
```
|
||||
|
||||
When executed, the code will print the following:
|
||||
|
||||
```lua
|
||||
You have:
|
||||
43 Gold Bricks
|
||||
3 Carrots
|
||||
2 Torches
|
||||
```
|
||||
|
||||
## Arrays and ipairs()
|
||||
|
||||
`ipairs()` is used with **arrays**. The "i" in `ipairs()` stands for "index." Use ipairs() and arrays in combination with a for loop to work with ordered values like leaderboards. An example is below.
|
||||
|
||||
```lua
|
||||
local players = {"Ali", "Ben", "Cammy"}
|
||||
|
||||
for playerRank, playerName in ipairs(players) do
|
||||
print("Winner #" .. playerRank .. " is " .. playerName)
|
||||
end
|
||||
```
|
||||
|
||||
When executed, the code will print the following:
|
||||
|
||||
```lua
|
||||
Winner #1 is Ali
|
||||
Winner #2 is Ben
|
||||
Winner #3 is Cammy
|
||||
```
|
||||
|
||||
## Practice - Restaurant Soup Simulator
|
||||
|
||||
Let's make some soup for a restaurant simulator where players pick from a list of possible soup ingredients. The ingredients will be stored as keys, and the values will start off as false so the players only get what they select.
|
||||
|
||||
Use `pairs()` to see what was picked, and then `ipairs()` to print the list of ingredients.
|
||||
|
||||
1. Create a new **dictionary** named `menu`. Add 3 - 5 key-value pairs where the key is the ingredient and the value is false.
|
||||
|
||||
```lua
|
||||
local menu = {
|
||||
cabbage = false,
|
||||
beef = false,
|
||||
tomato = false,
|
||||
noodles = false,
|
||||
}
|
||||
```
|
||||
|
||||
2. Beneath the menu dictionary, add an **empty array** which will be filled with the customer's choices later.
|
||||
|
||||
```lua
|
||||
-- Customer's soup
|
||||
local selectedIngredients = {}
|
||||
```
|
||||
|
||||
3. Use `pairs()` to check if each ingredient in the dictionary is marked true or false. If true, add the ingredient to soup.
|
||||
|
||||
```lua
|
||||
-- Customer's soup
|
||||
local selectedIngredients = {}
|
||||
|
||||
-- Adds customer's choices to their soup
|
||||
for menuChoice, value in pairs(menu) do
|
||||
if value then
|
||||
table.insert(selectedIngredients, menuChoice)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
4. Repeat the order back to the customer. In the script, code the following below.
|
||||
|
||||
- Check if there is a menu item in `selectedIngredients`. If so, print `"You ordered soup with: "`.
|
||||
- Use `ipairs()` to go through the `selectedIngredients` array and print each ingredient.
|
||||
- Test by changing at least one menu item to true.
|
||||
|
||||
```lua
|
||||
-- Prints soup order from "selectedIngredients"
|
||||
if #selectedIngredients > 0 then
|
||||
print("You ordered soup with: ")
|
||||
for index, soupIngredient in ipairs(selectedIngredients) do
|
||||
print(soupIngredient)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
5. In the if statement that checks if there is a menu item, add an else condition which tells customers if no ingredients were selected.
|
||||
|
||||
```lua
|
||||
if #selectedIngredients > 0 then
|
||||
print("You ordered soup with: ")
|
||||
for index, soupIngredient in ipairs(selectedIngredients) do
|
||||
print(soupIngredient)
|
||||
end
|
||||
else
|
||||
print("Nothing was selected. Are you not hungry?")
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="info">
|
||||
The above step is an example of error checking in computer science. It's always a good practice to code what happens if there's a missing value possible in your code. If not, it's possible there might be an error during run time.
|
||||
</Alert>
|
||||
|
||||
## Optional challenges
|
||||
|
||||
Below are some challenges that apply using pairs and ipairs in different ways. Try seeing if you can build out the code for these.
|
||||
|
||||
**Challenge**: Create a Waiter NPC
|
||||
Instead of using the Output window, use the NPC from [Intro To Arrays](../coding-5/intro-to-arrays.md) to create a waiter to take customer orders.
|
||||
|
||||
**Challenge**: Allow Players to Place Orders
|
||||
Allow players to select an ingredient by touching a physical part such as a proximity prompt. For more information, see [Proximity Prompts](../../../ui/proximity-prompts.md).
|
||||
|
||||
**Advanced Challenge**: Make Me Some Soup Simulator
|
||||
Create a restaurant simulator where players are the chefs! Players will have to put together ingredients to match the order given to them by the waiter.
|
||||
|
||||
1. Create in-game props for 3 - 5 different ingredients.
|
||||
2. Create 3 - 5 recipes using dictionaries similar to the one in this lesson.
|
||||
3. Create an array that holds all of the recipes.
|
||||
4. Randomly select a recipe and use an NPC to tell players what the ingredients are.
|
||||
5. Create a new dictionary to make a recipe based off which prop ingredients the player touches.
|
||||
6. Compare the player's recipe to the recipe chosen by the NPC.
|
||||
7. Increase the challenge by adding an extra condition, such as a timer.
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
title: Return values from tables
|
||||
description: Learn how to write a search function using pairs and ipairs to return values from tables in Luau.
|
||||
next: /tutorials/fundamentals/coding-6/landing
|
||||
prev: /tutorials/fundamentals/coding-5/pairs-and-ipairs
|
||||
---
|
||||
|
||||
A common need in many data structures is to return values. This article will cover searching a table using `pairs()` or `ipairs()` for half of any table element, such as the key or value, to find and return the other half.
|
||||
|
||||
The example uses an array listing ships waiting to be repaired. `ipairs()` is used to return a ship's place in line.
|
||||
|
||||
```lua
|
||||
local shipToFind = "Void Racer"
|
||||
|
||||
-- Ships waiting for repair
|
||||
local waitingShips = {"Battle Sun", "Void Racer", "The Big Slow"}
|
||||
|
||||
-- Get place in line
|
||||
local function getPlaceInLine(shipName)
|
||||
for placeInLine, ship in ipairs(waitingShips) do
|
||||
if ship == shipName then
|
||||
return placeInLine
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Print place in line
|
||||
local placeInLine = getPlaceInLine(shipToFind)
|
||||
print("Your place in line is " .. placeInLine)
|
||||
```
|
||||
|
||||
## Dictionary search example
|
||||
|
||||
Have you ever searched for a lost pet in house going room by room? On your own code a function to search through a dictionary named house to see which room holds a lost puppy.
|
||||
|
||||
1. Copy the dictionary below to act as the house.
|
||||
|
||||
```lua
|
||||
local house = {
|
||||
kitchen = "pile of Junk",
|
||||
livingRoom = "kitten",
|
||||
bedroom1 = "nobody there",
|
||||
bedroom2 = "puppy",
|
||||
}
|
||||
```
|
||||
|
||||
2. Create a new function called `findPet()` to search the dictionary. Include parameters for what dictionary to search, and what value to search for.
|
||||
3. Use `pairs()` to iterate through the dictionary. Try coding your own before checking your work in the solution below.
|
||||
|
||||
```lua
|
||||
local function findPet(whereToSearch, searchFor)
|
||||
for place, value in pairs(whereToSearch) do
|
||||
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
4. As the for loop iterates through the dictionary, use `return` to pass back the room where the pet was found.
|
||||
|
||||
```lua
|
||||
local function findPet(whereToSearch, searchFor)
|
||||
for place, value in pairs(whereToSearch) do
|
||||
if value == searchFor then
|
||||
return place
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
title: Coding concept - abstraction
|
||||
description: Abstractions in computer science are simplified representations of a larger idea or concept. This is used for computer science AP CSP lessons.
|
||||
next: /tutorials/fundamentals/coding-6/coding-concept-algorithms
|
||||
prev: /tutorials/fundamentals/coding-6/create-with-module-scripts
|
||||
---
|
||||
|
||||
**Abstractions** in computer science provide a simplified representation of something larger. They pull out only the most necessary information and hide everything else.
|
||||
|
||||
**Functions** are reusable abstractions. When called, users get the benefits of the function without having to rewrite or even look at the code for the entire function.
|
||||
|
||||
A common example in coding languages is `print()`. Most of its code is hidden, so the coder can focus on what needs to be printed and not the rest of the code.
|
||||
|
||||
## Why create abstractions
|
||||
|
||||
Abstractions keeps programs organized, reduces complexity, and makes code easier to update.
|
||||
|
||||
### Shop example
|
||||
|
||||
Say that you have an in-game shop that sells just two different backpacks. The code for the second backpack was copied with slight changes, such as a different name and selling price.
|
||||
|
||||
<GridContainer numColumns="2">
|
||||
<figure>
|
||||
<img src="../../../assets/education/coding-6/coding-concept-abstraction/backpack-yellow.png" />
|
||||
<figcaption>Yellow Backpack - 10 Robux</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img src="../../../assets/education/coding-6/coding-concept-abstraction/backpack-violet.png" />
|
||||
<figcaption>Violet Backpack - 25 Robux</figcaption>
|
||||
</figure>
|
||||
</GridContainer>
|
||||
|
||||
Here, the code is **not** abstracted. Each backpack has a script of its own. What would happen if you tried to add the following?
|
||||
|
||||
- 20 more backpacks.
|
||||
|
||||
- The ability for some bags to hold more items than other bags.
|
||||
|
||||
- A holiday sale, 25% off all backpacks.
|
||||
|
||||
## Design abstractions
|
||||
|
||||
Having separate backpack scripts makes adding and updating backpacks time consuming. Instead, create an abstraction so you don't have to make updates in so many different places.
|
||||
|
||||
To design an abstraction decide:
|
||||
|
||||
- Which parts of the code will be reused.
|
||||
|
||||
- What elements will be different each time.
|
||||
|
||||
The abstraction should pull out the information that changes, and hide the rest. In the backpack example, the differences are the backpack's name, price, and number of items it can carry. So an example of an abstraction, you can design is a function that takes in the backpack's name and returns it's price and capacity.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<img src="../../../assets/education/coding-6/coding-concept-abstraction/no-abstraction-backpacks.png" width="100%" />
|
||||
</td>
|
||||
<td>
|
||||
<img src="../../../assets/education/coding-6/coding-concept-abstraction/abstraction-backpacks.png" width="100%" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
**No Abstraction**
|
||||
</td>
|
||||
<td>
|
||||
**Abstraction**
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Four different backpacks, four different places to update.
|
||||
</td>
|
||||
<td>
|
||||
Use a function to search a table for unique information. Only one place to update.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<Alert severity="info">
|
||||
<AlertTitle>Check for Understanding - Using Abstractions</AlertTitle>
|
||||
What are other game mechanics you can create abstractions for?
|
||||
|
||||
Possible Examples
|
||||
|
||||
- Trap parts - Allowing for different harm values
|
||||
- Creating a function for awarding random power-ups
|
||||
- Creating character classes
|
||||
|
||||
</Alert>
|
||||
|
||||
## Summary
|
||||
|
||||
**Abstractions** provide a simplified representation of something larger by leaving out details. When deciding whether to create an abstraction, look for code that is often reused but with small changes each time. For example, a generic item like a backpack can be abstracted to a reusable function that looks up price and capacity.
|
||||
|
||||
Taking time to plan and structure code with abstractions helps coders focus on what's important. This investment in time keeps programs better organized and makes updating them easier.
|
||||
|
||||
<Alert severity="info">
|
||||
Galactic Speedway - The Settings script has only the variables for unique features of the driftspeeder. The rest of the code is hidden. This allows students new to coding to stay focused without getting lost.
|
||||
|
||||
Story Game Creator Challenge - Students call `getInput()` from the StoryMaker module script to create questions for players to answer. Students can practice typing strings and ask as many questions as they like, but don't need to see the code in the StoryMaker module.
|
||||
</Alert>
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
---
|
||||
title: Coding concept - algorithms
|
||||
description: Algorithms in computer science are a series of steps used to determine an outcome. This is used for computer science AP CSP lessons.
|
||||
prev: /tutorials/fundamentals/coding-6/coding-concept-abstraction
|
||||
---
|
||||
|
||||
An **algorithm** uses a series of steps to determine an outcome. Steps can be a set of directions, comparisons, or even a mathematical formula.
|
||||
|
||||
Your daily life is full of algorithms that you use without thinking about it. They help you make decisions, create things, and solve problems.
|
||||
|
||||
**Real life examples:**
|
||||
|
||||
- Checking if you have enough money to buy a snack.
|
||||
- Getting dressed in the morning.
|
||||
- Drawing stick figures.
|
||||
|
||||
**Coding examples:**
|
||||
|
||||
- Checking if a skill level is high enough to use an item.
|
||||
- Sorting a list of items into alphabetical order.
|
||||
- A player standing on lava loses 5 health every second. If they reach 0, they respawn.
|
||||
|
||||
<Alert severity="success">
|
||||
For an offline activity, try using this combination of art and computer science to create an algorithm that makes stick figures.
|
||||
|
||||
- Have everyone draw a stick figure.
|
||||
- Have everyone write down the steps they took.
|
||||
- Pair up students and have one student direct the second student using the directions they wrote down previously.
|
||||
|
||||
</Alert>
|
||||
|
||||
## Create algorithms in code
|
||||
|
||||
In real life, we don't usually think about the algorithms we use everyday. Computers however, need algorithms to be coded step-by-step and use at least one of three methods to solve a problem or produce an outcome.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="50%">Methodology</th>
|
||||
<th width="50%">Example</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>**Selection** - Uses conditional statements such as if/then to determine an output.</td>
|
||||
<td>
|
||||
```lua
|
||||
if time == 0 then
|
||||
stopLightColor = red
|
||||
end
|
||||
```
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
**Sequencing** - A set of precise steps.
|
||||
</td>
|
||||
<td>
|
||||
```lua
|
||||
local function createBridge()
|
||||
create new block
|
||||
size block
|
||||
set color
|
||||
rotate
|
||||
set location
|
||||
parent to workspace
|
||||
end
|
||||
```
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
**Iteration** - Repeats parts of the code as necessary, such as in for loops or multiplication.
|
||||
</td>
|
||||
<td>
|
||||
```lua
|
||||
for countDown = 10, 1, -1 do
|
||||
time -= 1
|
||||
task.wait(1)
|
||||
end
|
||||
```
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Combine algorithms
|
||||
|
||||
Much like larger problems can be broken into smaller problems, some algorithms can be broken down into a series of smaller algorithms.
|
||||
|
||||
<img src="../../../assets/education/coding-6/coding-concept-algorithms/square-and-child-squares.png" width="50%" />
|
||||
|
||||
Think of your real-life morning time algorithm to get dressed. If that's your main algorithm, it might use one algorithm for picking out your clothes, and a second algorithm for putting clothes on.
|
||||
|
||||
```lua title="Getting Dressed Pseudocode"
|
||||
-- First algorithm for picking clothes
|
||||
local function pickClothes()
|
||||
pick top clothing
|
||||
pick bottom clothing
|
||||
pick Socks
|
||||
pick Shoes
|
||||
end
|
||||
|
||||
-- Second algorithm for putting clothes on
|
||||
|
||||
local function putOnClothes()
|
||||
put on top clothing
|
||||
put on bottom clothing
|
||||
put on socks
|
||||
put on shoes
|
||||
end
|
||||
|
||||
-- Main algorithm, calls pickClothes()and putOnClothes()
|
||||
local function getDressed()
|
||||
pickClothes()
|
||||
putOnClothes()
|
||||
end
|
||||
```
|
||||
|
||||
<Alert severity="success">
|
||||
For an optional challenge, try and figure out what are additional algorithms `pickClothes()` might use?
|
||||
|
||||
- Check the weather.
|
||||
- Check if clothes are clean.
|
||||
- Check if clothes match.
|
||||
|
||||
</Alert>
|
||||
|
||||
## Summary
|
||||
|
||||
**Algorithms** are predefined steps that provide an outcome. In daily life, algorithms solve problems like getting dressed, going to work, or making a cake. In code, algorithms solve problems like managing websites, handling traffic congestion, or running game mechanics. To complete their goal, algorithms will often call on other algorithms.
|
||||
|
||||
Algorithms use three different ways to come to a conclusion; **selection**, **iteration**, and **sequencing**. Selection uses conditionals such as if/then statements. Iteration repeats parts of the code as necessary. Sequencing uses a series of steps to produce a result.
|
||||
|
|
@ -0,0 +1,520 @@
|
|||
---
|
||||
title: Create with module scripts
|
||||
description: Apply your knowledge of modular scripts in Roblox with this practical example.
|
||||
next: /tutorials/fundamentals/coding-6/coding-concept-abstraction
|
||||
prev: /tutorials/fundamentals/coding-6/intro-to-module-scripts
|
||||
---
|
||||
|
||||
<img src="../../../assets/education/coding-6/creating-with-module-scripts/creating-modules-hero.jpeg" />
|
||||
|
||||
To apply your knowledge of module scripts, create a module script that allows players to pick up keys and use them to open treasure chests.
|
||||
|
||||
<video controls src="../../../assets/education/coding-6/creating-with-module-scripts/final-example.mp4"></video>
|
||||
|
||||
## Project setup
|
||||
|
||||
This project includes a starter map with leaderboard and scripted pickup objects for the keys and treasure chests.
|
||||
|
||||
### Load the starter project
|
||||
|
||||
1. Download the starter project.
|
||||
|
||||
<a href="../../../assets/education/coding-6/creating-with-module-scripts/Intro_to_Module_Scripts_-_Starter_Project.rbxl">
|
||||
<Button variant="contained">Download</Button>
|
||||
</a>
|
||||
|
||||
2. In Roblox Studio, open the downloaded file: **Intro to Module Scripts - Starter Project.rbxl**.
|
||||
<img src="../../../assets/education/coding-6/creating-with-module-scripts/module-template-example.jpeg" width="50%" />
|
||||
|
||||
### Create a module script
|
||||
|
||||
So players can get treasure from chests, create a module script named TreasureManager. Using a module script will connect the pickups and leaderboards together.
|
||||
|
||||
1. In **ServerStorage**, create a new **ModuleScript** and rename it **TreasureManager**.
|
||||
|
||||
<img src="../../../assets/education/coding-6/creating-with-module-scripts/create-module-script.png" width="35%" />
|
||||
|
||||
2. In **TreasureManager**, rename the default module table by replacing `module` with `TreasureManager` in both places.
|
||||
|
||||
```lua
|
||||
local TreasureManager = {}
|
||||
|
||||
return TreasureManager
|
||||
```
|
||||
|
||||
## Use functions in module scripts
|
||||
|
||||
To test how functions work in module scripts, create a new function named `getKey()`. When the `getKey()` function is called from another script, it'll receive a key part to destroy and add 1 to the number of keys in the player's inventory.
|
||||
|
||||
### Create a module function for keys
|
||||
|
||||
1. This module script will use a combination of module and local functions, type **two** comments to help you keep them separated.
|
||||
|
||||
```lua
|
||||
local TreasureManager = {}
|
||||
|
||||
------------------ Local Functions
|
||||
|
||||
------------------ Module Functions
|
||||
|
||||
return TreasureManager
|
||||
```
|
||||
|
||||
2. Under the **Module Functions** comment, add a new module function to `TreasureManager` named `getKey()`.
|
||||
|
||||
Use two parameters:
|
||||
|
||||
- `keyPart` - the part to destroy.
|
||||
- `whichCharacter` - the player that touched the key part.
|
||||
|
||||
```lua
|
||||
local TreasureManager = {}
|
||||
|
||||
------------------ Local Functions
|
||||
|
||||
------------------ Module Functions
|
||||
function TreasureManager.getKey(keyPart, whichCharacter)
|
||||
|
||||
end
|
||||
|
||||
return TreasureManager
|
||||
```
|
||||
|
||||
3. In `getKey()`, destroy `keyPart`.
|
||||
|
||||
```lua
|
||||
function TreasureManager.getKey(keyPart, whichCharacter)
|
||||
keyPart:Destroy()
|
||||
end
|
||||
```
|
||||
|
||||
### Use the module function
|
||||
|
||||
Now, the module function `getKey()` can be used in other scripts. To test that function, you'll open a premade script and call it.
|
||||
|
||||
1. Open the key script in **Workspace** ⟩ **Keys** ⟩ **KeyScript**.
|
||||
|
||||
2. In keyScript, store the module script in a variable named `treasureManager` and set it equal to:
|
||||
`require(ServerStorage:WaitForChild("TreasureManager"))`
|
||||
|
||||
```lua
|
||||
local ServerStorage = game:GetService("ServerStorage")
|
||||
-- Require the module script below ⯆
|
||||
local treasureManager = require(ServerStorage:WaitForChild("TreasureManager"))
|
||||
|
||||
local keys = script.Parent
|
||||
local keysFolder = keys.Parts
|
||||
local keysArray = keysFolder:GetChildren()
|
||||
```
|
||||
|
||||
<Alert severity="success">
|
||||
|
||||
Prevent errors by using `WaitForChild()` instead of the dot operator to make the script wait until `TreasureManager` has loaded before moving on. For scripts in ServerScriptService or ServerStorage, it's safe to use the dot operator instead, like in `Class.ServerStorage.TreasureManager`.
|
||||
</Alert>
|
||||
|
||||
3. There's already a function named `partTouched()` to check for a player touching the part. Inside `partTouched()`:
|
||||
|
||||
- Call the `getKey()` module function to destroy the key.
|
||||
- Pass in `keyPart` and `whichCharacter`.
|
||||
|
||||
```lua
|
||||
local ServerStorage = game:GetService("ServerStorage")
|
||||
-- Require the module script below ⯆
|
||||
local treasureManager = require(ServerStorage:WaitForChild("TreasureManager"))
|
||||
|
||||
local keys = script.Parent
|
||||
local keysFolder = keys.Parts
|
||||
local keysArray = keysFolder:GetChildren()
|
||||
|
||||
local function partTouched(otherPart, keyPart)
|
||||
local whichCharacter = otherPart.Parent
|
||||
local humanoid = whichCharacter:FindFirstChildWhichIsA("Humanoid")
|
||||
if humanoid then
|
||||
-- Give the player a key and destroy the key part
|
||||
-- =============================================
|
||||
treasureManager.getKey(keyPart, whichCharacter)
|
||||
-- =============================================
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
4. Run the project and check that touching a key destroys it.
|
||||
|
||||
<video controls src="../../../assets/education/coding-6/creating-with-module-scripts/get-first-key.mp4" width="75%"></video>
|
||||
|
||||
### Troubleshooting tips
|
||||
|
||||
**Issue:** Get an error message including: `"Infinite yield possible"`.
|
||||
|
||||
- Check the spelling of your module script in a script. If a module script, like **TreasureManager**, is spelled differently, there will be an error.
|
||||
|
||||
**Issue:** Get an error message including: `"attempt to index global"`.
|
||||
|
||||
- Check the line that includes the require for the module script in **keyScript**. If the module does not include require, it can't use functions and variables from that module script.
|
||||
|
||||
**Issue:** Script doesn't run or can't pick up keys.
|
||||
|
||||
- In the module script, make sure that all the code is between `local TreasureManager = {}` and `return TreasureManager`. The return must be the last line of code in a Module Script.
|
||||
|
||||
- Check that there are two parenthesis at the end of the line with require, like in `WaitForChild("TreasureManager"))`.
|
||||
|
||||
## Create a Local Function
|
||||
|
||||
Right now, a leaderboard keeps track of a player's keys and treasure. To change the leaderboard numbers, use a local function in the module script. A local function is used because changing a player's key or treasure values will only be needed in the TreasureManager script, not anywhere else.
|
||||
|
||||
1. In **ServerStorage**, open the **TreasureManager** script.
|
||||
|
||||
2. Create local variables to do the following:
|
||||
|
||||
- Get the Players service so the script can work with player's leaderboard stats.
|
||||
|
||||
- Store the number of keys the player receives after touching **keyPart**.
|
||||
|
||||
```lua
|
||||
local TreasureManager = {}
|
||||
local Players = game:GetService("Players")
|
||||
local keyDrop = 1
|
||||
|
||||
------------------ Local Functions
|
||||
|
||||
------------------ Module Functions
|
||||
function TreasureManager.getKey(keyPart, whichCharacter)
|
||||
keyPart:Destroy()
|
||||
end
|
||||
|
||||
return TreasureManager
|
||||
```
|
||||
|
||||
3. Copy and paste these two local functions into the **Local Functions** section.
|
||||
|
||||
- `getPlayerKeys()` returns the value of the player's `Lockpicks` leaderstat.
|
||||
|
||||
- `getPlayerTreasure()` returns the value of the player's `Treasure` leaderstat.
|
||||
|
||||
```lua
|
||||
------------------ Local Functions
|
||||
local function getPlayerKeys(whichCharacter)
|
||||
local player = Players:GetPlayerFromCharacter(whichCharacter)
|
||||
local leaderstats = player:FindFirstChild("leaderstats")
|
||||
return leaderstats:WaitForChild("Lockpicks")
|
||||
end
|
||||
local function getPlayerTreasure(whichCharacter)
|
||||
local player = Players:GetPlayerFromCharacter(whichCharacter)
|
||||
local leaderstats = player:FindFirstChild("leaderstats")
|
||||
return leaderstats:WaitForChild("Treasure")
|
||||
end
|
||||
------------------ Module Functions
|
||||
```
|
||||
|
||||
4. To add to the player's keys, in the `getKey()` module function:
|
||||
|
||||
- Create a `local` variable to call `getPlayerKeys(whichCharacter)`.
|
||||
|
||||
- Add the value of `keyDrop` to `playerKeys`.
|
||||
|
||||
```lua
|
||||
------------------ Module Functions
|
||||
function TreasureManager.getKey(keyPart, whichCharacter)
|
||||
local playerKeys = getPlayerKeys(whichCharacter)
|
||||
playerKeys.Value = playerKeys.Value + keyDrop
|
||||
keyPart:Destroy()
|
||||
end
|
||||
```
|
||||
|
||||
5. Run the project. Check that touching a key destroys it and adds 1 to the player's keys in the leaderboard.
|
||||
|
||||
<img src="../../../assets/education/coding-6/creating-with-module-scripts/show-leaderboard-key.jpg" />
|
||||
|
||||
If needed, check your script against the one below for any troubleshooting issues.
|
||||
|
||||
```lua title = "Current TreasureManager Script"
|
||||
local TreasureManager = {}
|
||||
local Players = game:GetService("Players")
|
||||
local keyDrop = 1
|
||||
|
||||
------------------ Local Functions
|
||||
local function getPlayerKeys(whichCharacter)
|
||||
local player = Players:GetPlayerFromCharacter(whichCharacter)
|
||||
local leaderstats = player:FindFirstChild("leaderstats")
|
||||
return leaderstats:WaitForChild("Lockpicks")
|
||||
end
|
||||
|
||||
local function getPlayerTreasure(whichCharacter)
|
||||
local player = Players:GetPlayerFromCharacter(whichCharacter)
|
||||
local leaderstats = player:FindFirstChild("leaderstats")
|
||||
return leaderstats:WaitForChild("Treasure")
|
||||
end
|
||||
|
||||
------------------ Module Functions
|
||||
function TreasureManager.getKey(keyPart, whichCharacter)
|
||||
local playerKeys = getPlayerKeys(whichCharacter)
|
||||
playerKeys.Value = playerKeys.Value + keyDrop
|
||||
keyPart:Destroy()
|
||||
end
|
||||
|
||||
return TreasureManager
|
||||
```
|
||||
|
||||
## Get information from module scripts
|
||||
|
||||
The **TreasureManager** module script will be used when players touch a treasure chest to check if they have at least one key before opening it and giving them gold.
|
||||
|
||||
### Check if chests can be opened
|
||||
|
||||
1. First in **ServerStorage** ⟩ **TreasureManager** script, set up variables for how many keys it costs to open a chest, and how much gold each chest contains.
|
||||
|
||||
```lua
|
||||
local TreasureManager = {}
|
||||
|
||||
local Players = game:GetService("Players")
|
||||
local keyDrop = 1
|
||||
local chestPickCost = 1
|
||||
local chestReward = 100
|
||||
|
||||
------------------ Local Functions
|
||||
local function getPlayerKeys(whichCharacter)
|
||||
local player = Players:GetPlayerFromCharacter(whichCharacter)
|
||||
local leaderstats = player:FindFirstChild("leaderstats")
|
||||
return leaderstats:WaitForChild("Lockpicks")
|
||||
end
|
||||
```
|
||||
|
||||
2. To create a function that checks if a player can open a chest, in the **Module Functions** section, add a new function to the `TreasureManager` table named `canOpenChest()` with the parameter `whichCharacter`.
|
||||
|
||||
```lua
|
||||
------------------ Module Functions
|
||||
function TreasureManager.canOpenChest(whichCharacter)
|
||||
|
||||
end
|
||||
|
||||
function TreasureManager.getKey(keyPart, whichCharacter)
|
||||
local playerKeys = getPlayerKeys(whichCharacter)
|
||||
playerKeys.Value = playerKeys.Value + keyDrop
|
||||
keyPart:Destroy()
|
||||
end
|
||||
```
|
||||
|
||||
3. Copy and paste the code below into `canOpenChest()` to return `true` if the player has enough keys, and `false` if they don't.
|
||||
|
||||
```lua
|
||||
function TreasureManager.canOpenChest(whichCharacter)
|
||||
local playerKeys = getPlayerKeys(whichCharacter)
|
||||
if playerKeys.Value >= chestPickCost then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Give players treasure
|
||||
|
||||
So the player can open a chest, create a function in **TreasureManager** that awards them treasure.
|
||||
|
||||
1. Add a new module function to `TreasureManager` named `openChest()`.
|
||||
|
||||
Pass in two arguments:
|
||||
|
||||
- `chestPart` - the chest part to destroy.
|
||||
- `whichCharacter` - the player to give treasure.
|
||||
|
||||
```lua
|
||||
function TreasureManager.openChest(chestPart, whichCharacter)
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
2. To subtract a player's keys and award them treasure, copy and paste the code below in `openChest()`. This code uses the variables created previously, like `chestReward`, the amount of treasure given per chest.
|
||||
|
||||
```lua
|
||||
function TreasureManager.openChest(chestPart, whichCharacter)
|
||||
local playerKeys = getPlayerKeys(whichCharacter)
|
||||
local playerTreasure = getPlayerTreasure(whichCharacter)
|
||||
playerKeys.Value = playerKeys.Value - chestPickCost
|
||||
playerTreasure.Value = playerTreasure.Value + chestReward
|
||||
chestPart.Parent:Destroy()
|
||||
end
|
||||
```
|
||||
|
||||
### Call the chest functions
|
||||
|
||||
Now that the two module functions, `canOpenChest()` and `openChest()`, have been created, they can be called by the Chest parts whenever a player touches them using the premade `partTouched()` function.
|
||||
|
||||
1. In **Workspace** ⟩ **Chests** open **ChestScript**.
|
||||
|
||||
2. Create a new variable named `treasureManager` and require the **TreasureManager** module script in **ServerStorage**.
|
||||
|
||||
```lua
|
||||
local ServerStorage = game:GetService("ServerStorage")
|
||||
-- Require the module script below
|
||||
local treasureManager = require(ServerStorage:WaitForChild("TreasureManager"))
|
||||
|
||||
local chests = script.Parent
|
||||
local chestsFolder = chests.Parts
|
||||
local chestsArray = chestsFolder:GetChildren()
|
||||
```
|
||||
|
||||
3. In `partTouched()`, under the `if humanoid` statement, create a new variable named `canOpen` and set it equal to:
|
||||
|
||||
`treasureManager.canOpenChest(whichCharacter)`
|
||||
|
||||
```lua
|
||||
local function partTouched(otherPart, chestPart)
|
||||
local whichCharacter = otherPart.Parent
|
||||
local humanoid = whichCharacter:FindFirstChildWhichIsA("Humanoid")
|
||||
if humanoid then
|
||||
-- Check if the player can open a chest, then let them get treasure
|
||||
-- =============================================
|
||||
local canOpen = treasureManager.canOpenChest(whichCharacter)
|
||||
-- =============================================
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
4. Next, create an if statement to check if `canOpen` is true.
|
||||
|
||||
- If so, call the TreasureManager's `openChest()` function.
|
||||
|
||||
- Then, pass in two parameters: `chestPart`, the chest to destroy, and `whichCharacter`, the player to award treasure.
|
||||
|
||||
```lua
|
||||
local function partTouched(otherPart, chestPart)
|
||||
local whichCharacter = otherPart.Parent
|
||||
local humanoid = whichCharacter:FindFirstChildWhichIsA("Humanoid")
|
||||
if humanoid then
|
||||
-- Check if the player can open a chest, then let them get treasure
|
||||
-- =============================================
|
||||
local canOpen = treasureManager.canOpenChest(whichCharacter)
|
||||
if canOpen == true then
|
||||
treasureManager.openChest(chestPart, whichCharacter)
|
||||
end
|
||||
-- =============================================
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
5. Run the project. Check that:
|
||||
|
||||
- If you have at least 1 key, touching a chest will destroys it and awards treasure.
|
||||
- If you have 0 keys, you can't open a treasure chest.
|
||||
|
||||
### Troubleshooting tips
|
||||
|
||||
- In **ChestScript**, make sure that functions called from the module script like `canOpenChest()` are spelled exactly how they're found in the **TreasureManager** script. Any difference will cause an error.
|
||||
|
||||
- Check that copy and pasted functions, like `treasureManager.openChest()`, are exactly as shown in the lesson. Any differences can cause subtle errors in the script.
|
||||
|
||||
## Finished scripts
|
||||
|
||||
```lua title="Finished TreasureManager Script"
|
||||
|
||||
local TreasureManager = {}
|
||||
local Players = game:GetService("Players")
|
||||
local keyDrop = 1
|
||||
local chestPickCost = 1
|
||||
local chestReward = 100
|
||||
|
||||
------------------ Local Functions
|
||||
local function getPlayerKeys(whichCharacter)
|
||||
local player = Players:GetPlayerFromCharacter(whichCharacter)
|
||||
local leaderstats = player:FindFirstChild("leaderstats")
|
||||
return leaderstats:WaitForChild("Lockpicks")
|
||||
end
|
||||
|
||||
local function getPlayerTreasure(whichCharacter)
|
||||
local player = Players:GetPlayerFromCharacter(whichCharacter)
|
||||
local leaderstats = player:FindFirstChild("leaderstats")
|
||||
return leaderstats:WaitForChild("Treasure")
|
||||
end
|
||||
|
||||
------------------ Module Functions
|
||||
function TreasureManager.openChest(chestPart, whichCharacter)
|
||||
local playerKeys = getPlayerKeys(whichCharacter)
|
||||
local playerTreasure = getPlayerTreasure(whichCharacter)
|
||||
playerKeys.Value = playerKeys.Value - chestPickCost
|
||||
playerTreasure.Value = playerTreasure.Value + chestReward
|
||||
chestPart.Parent:Destroy()
|
||||
end
|
||||
|
||||
function TreasureManager.canOpenChest(whichCharacter)
|
||||
local playerKeys = getPlayerKeys(whichCharacter)
|
||||
if playerKeys.Value >= chestPickCost then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function TreasureManager.getKey(keyPart, whichCharacter)
|
||||
local playerKeys = getPlayerKeys(whichCharacter)
|
||||
playerKeys.Value = playerKeys.Value + keyDrop
|
||||
keyPart:Destroy()
|
||||
end
|
||||
|
||||
return TreasureManager
|
||||
```
|
||||
|
||||
```lua title="Finished ChestScript"
|
||||
local ServerStorage = game:GetService("ServerStorage")
|
||||
-- Require the module script below ⯆
|
||||
local treasureManager = require(ServerStorage:WaitForChild("TreasureManager"))
|
||||
|
||||
local chests = script.Parent
|
||||
local chestsFolder = chests.Parts
|
||||
local chestsArray = chestsFolder:GetChildren()
|
||||
|
||||
local function partTouched(otherPart, chestPart)
|
||||
local whichCharacter = otherPart.Parent
|
||||
local humanoid = whichCharacter:FindFirstChildWhichIsA("Humanoid")
|
||||
if humanoid then
|
||||
-- Check if the player can open a chest, then let them get treasure
|
||||
-- =============================================
|
||||
local canOpen = treasureManager.canOpenChest(whichCharacter)
|
||||
if canOpen == true then
|
||||
treasureManager.openChest(chestPart, whichCharacter)
|
||||
end
|
||||
-- =============================================
|
||||
end
|
||||
end
|
||||
|
||||
-- Binds every chest part to the touch function so it works on all parts
|
||||
for chestIndex = 1, #chestsArray do
|
||||
local chestPart = chestsArray[chestIndex]:WaitForChild("Collider")
|
||||
chestPart.Touched:Connect(function(otherPart)
|
||||
partTouched(otherPart, chestPart)
|
||||
end)
|
||||
end
|
||||
```
|
||||
|
||||
```lua title="Finished keyScript"
|
||||
local ServerStorage = game:GetService("ServerStorage")
|
||||
-- Require the module script below ⯆
|
||||
local treasureManager = require(ServerStorage:WaitForChild("TreasureManager"))
|
||||
|
||||
local keys = script.Parent
|
||||
local keysFolder = keys.Parts
|
||||
local keysArray = keysFolder:GetChildren()
|
||||
|
||||
local function partTouched(otherPart, keyPart)
|
||||
local whichCharacter = otherPart.Parent
|
||||
local humanoid = whichCharacter:FindFirstChildWhichIsA("Humanoid")
|
||||
if humanoid then
|
||||
-- Give the player a key and destroy the key part
|
||||
-- =============================================
|
||||
treasureManager.getKey(keyPart, whichCharacter)
|
||||
-- =============================================
|
||||
end
|
||||
end
|
||||
|
||||
-- Binds every key part to the touch function so it works on all parts
|
||||
for keyIndex = 1, #keysArray do
|
||||
local keyPart = keysArray[keyIndex]
|
||||
keyPart.Touched:Connect(function(otherPart)
|
||||
partTouched(otherPart, keyPart)
|
||||
end)
|
||||
end
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
A common application of using module scripts in Roblox experiences is to handle common tasks used by players, such as granting them points. For this example, a module script named TreasureManager was created to handle giving players keys and treasure whenever they interact with in-game objects.
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
---
|
||||
title: Intro to module scripts
|
||||
description: Learn key concepts around organizing and reusing code in Roblox with modular scripts.
|
||||
next: /tutorials/fundamentals/coding-6/create-with-module-scripts
|
||||
prev: /tutorials/fundamentals/coding-6/landing
|
||||
---
|
||||
|
||||
As projects become complex, it becomes important to think how scripts are organized. Good organization practices can ensure code isn't duplicated between scripts, or becomes hard to manage.
|
||||
|
||||
A better way to organize and reuse code is with **module scripts**, a unique type of script that stores a set of functions and variables designed to meet a shared purpose, like managing player money or enemies. Code within module scripts can be used by other scripts. That way, you can call the same function that gives coins from multiple different scripts whenever a player finishes a quest or finds a pickup.
|
||||
|
||||
By storing commonly used code in module scripts, it makes maintaining and organizing code easier since changes only need to be made to one module script, rather than updating multiple scripts.
|
||||
|
||||
<Alert severity="success">
|
||||
Normal scripts should be used for standalone elements of an experience, such as touching a pickup, while module scripts are useful for storing code that can be reused by multiple independent scripts, like rewarding points.
|
||||
</Alert>
|
||||
|
||||
## Module script basics
|
||||
|
||||
Module scripts are actually their own separate object compared to script objects. In Roblox, module scripts can be denoted with a **purple** icon.
|
||||
|
||||
### Create a module script
|
||||
|
||||
ModuleScripts are commonly placed in **ServerScriptService** when used by server-side scripts and **ReplicatedStorage** when used by client-side local scripts (such as GUI interactions).
|
||||
|
||||
1. Create a **ModuleScript** in **ServerScriptService**.
|
||||
|
||||
<img src="../../../assets/education/coding-6/intro-to-module-scripts/create-module-script.png" width="35%" />
|
||||
|
||||
### Structure of module scripts
|
||||
|
||||
When created, every module script starts out with the code below:
|
||||
|
||||
```lua
|
||||
local Module = {}
|
||||
|
||||
return Module
|
||||
```
|
||||
|
||||
The line `local Module = {}` creates a table, or container of code, where the module's shared functions and variables can be stored. This table should be renamed to the module's purpose, such as `RewardManager` or `ParticleController`. As opposed to other variables which are camel case (`myVariable`), module tables are recommended to use pascal case and start capitalized (`MyModule`).
|
||||
|
||||
```lua
|
||||
local RewardManager = {}
|
||||
|
||||
return RewardManager
|
||||
```
|
||||
|
||||
So other scripts can use a module's non-local functions or variables, every module ends with return `MyModule`. Whenever another script tries to get code from the module, return lets that script access code stored inside the module table.
|
||||
|
||||
### Add to module scripts
|
||||
|
||||
To add a function or variable to the module which can be used in another script, type the module table's name, followed by a dot, and the name of the function or variable, like in `TestModule.myVariable`. Using the dot operator is another way of adding code into a table, allowing other scripts to access that code whenever the module table is returned.
|
||||
|
||||
```lua
|
||||
local TestModule = {}
|
||||
|
||||
-- Adds a variable to 'TestModule' table
|
||||
TestModule.myVariable = 100
|
||||
|
||||
-- Adds a function to 'TestModule' table
|
||||
function TestModule.doTask(player)
|
||||
-- Placeholder code
|
||||
end
|
||||
|
||||
return TestModule
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
Anything added to the module table should be typed between `local MyModule = {}` and `return MyModule`, or else the code may create an error.
|
||||
</Alert>
|
||||
|
||||
### Scope in module scripts
|
||||
|
||||
For a module function or variable to be used in an outside script, **don't** type `local`.
|
||||
|
||||
Typing `local` in front of variables and functions means they are **only** usable by that script. While this is a good practice for most scripts for reducing errors and troubleshooting, you cannot make module script functions and variables local.
|
||||
|
||||
Any code used **only** by that module script should still include `local`. For instance, the code below includes the local variable `difficultyModifier`, which can only be used in that module script, and the function `getCoinReward()`, which can be used in scripts outside the module.
|
||||
|
||||
```lua
|
||||
local RewardManager = {}
|
||||
|
||||
-- Usable only in the module script
|
||||
local rewardCoins = 50
|
||||
|
||||
-- Usable only in the module script
|
||||
local difficultyModifier = {
|
||||
easy = 0.5,
|
||||
normal = 1,
|
||||
hard = 2
|
||||
}
|
||||
|
||||
-- Usable in other scripts
|
||||
function RewardManager.getCoinReward(difficulty)
|
||||
local coins = difficultyModifier[difficulty] * rewardCoins
|
||||
return coins
|
||||
end
|
||||
|
||||
return RewardManager
|
||||
```
|
||||
|
||||
## Use modules in other scripts
|
||||
|
||||
By itself, a module script can't run code — it needs to be loaded in another script using the keyword `Global.LuaGlobals.require()`. The function `Global.LuaGlobals.require()` accepts one argument, the location of the module script in the Explorer.
|
||||
|
||||
To use a module, in a separate script, set a variable equal to `require(moduleScript)`.
|
||||
|
||||
```lua
|
||||
local MyModule = require(ServerStorage.ModuleScript)
|
||||
```
|
||||
|
||||
Now, the variable `MyModule` contains the module table created in that module script. To use functions and variables from that table, type the variable name, followed by a dot, and the exact name of what to use in that module script, like `MyModule.myFunction()`. When the script runs and reaches that line, it'll access that specific function or variable stored in the module table.
|
||||
|
||||
```lua
|
||||
local MyModule = require(ServerStorage.ModuleScript)
|
||||
|
||||
MyModule.myFunction()
|
||||
```
|
||||
|
||||
## RewardManager example
|
||||
|
||||
```lua title="ModuleScript - RewardManager"
|
||||
local RewardManager = {}
|
||||
|
||||
-- Usable only in the module script
|
||||
local rewardCoins = 50
|
||||
|
||||
-- Usable only in the module script
|
||||
local difficultyModifier = {
|
||||
easy = 0.5,
|
||||
normal = 1,
|
||||
hard = 2
|
||||
}
|
||||
|
||||
-- Usable in other scripts
|
||||
function RewardManager.getCoinReward(difficulty)
|
||||
local coins = difficultyModifier[difficulty] * rewardCoins
|
||||
return coins
|
||||
end
|
||||
|
||||
return RewardManager
|
||||
```
|
||||
|
||||
```lua title="Script - TreasureChestScript"
|
||||
local ServerStorage = game:GetService("ServerStorage")
|
||||
|
||||
-- Load module script
|
||||
local RewardManager = require(ServerStorage.RewardManager)
|
||||
|
||||
--Calls function from module script
|
||||
local coins = RewardManager.getCoinReward("easy")
|
||||
print("Should award " .. coins .. " coins")
|
||||
```
|
||||
|
||||
<Alert severity="warning">
|
||||
If you're in another script, make sure that the module script function or variable is spelled **exactly** the same as found in that module. To help, you can copy the exact function or variable name from the module and then just paste it in the normal script where it'll be used.
|
||||
</Alert>
|
||||
|
||||
## General troubleshooting
|
||||
|
||||
Some of the tips here address common issues when working with module scripts. Keep in mind that module scripts can be a complicated topic with more nuance. For more details, see this more technical guide on [Module Scripts](../../../scripting/module.md).
|
||||
|
||||
**Issue:** Get an error message including: `"Infinite yield possible"` or `"not a valid member"`.
|
||||
|
||||
- Check the spelling of the module script where it's loaded. `Global.LuaGlobals.require()` must include the exact path and spelling of the module script, which may be named differently than the module table.
|
||||
|
||||
**Issue:** Get an error message including: `"attempt to index global"`.
|
||||
|
||||
- In any scripts using a module script, make sure it's loaded using the function `Global.LuaGlobals.require()`. If not, that script cannot use functions and variables from the module script.
|
||||
|
||||
## Summary
|
||||
|
||||
**Module scripts** in Roblox are a method coders use to organize and reuse code. A module script is often stored in ServerStorage (or ReplicatedStorage for client-based interactions). From there, other scripts are able to call functions and variables stored in that module script.
|
||||
|
||||
For instance, one experience may award points to players for collecting objects. A module script can handle code to give points. Then, scripts for different types of objects can just call the module script function. This reduces the need to reuse code between scripts, making code easier to understand and maintain.
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
title: Organizing code
|
||||
description: Roblox module scripts are one way of organizing code. This series covers how they work and how to implement them in an experience.
|
||||
next: /tutorials/fundamentals/coding-6/intro-to-module-scripts
|
||||
prev: /tutorials/fundamentals/coding-5/return-values-from-tables
|
||||
---
|
||||
|
||||
### Series description
|
||||
|
||||
As you continue to work with code, scripts will become more complex. To address this, coders have a variety of techniques to make coding efficient, easy to understand, and reduce the chance of error. This series covers methods of organizing scripts, such as module scripts, a special type in script that can store functions and variables used by other scripts.
|
||||
|
||||
### Objectives and prerequisites
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="20%"><b>Learning objectives</b></td>
|
||||
<td>
|
||||
Understand the logic behind module scripts, as well as how to code a module script and access it in other scripts.
|
||||
|
||||
Be able to identify patterns of abstraction and algorithms in computer science.
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Prerequisites</b></td>
|
||||
<td>
|
||||
Have an understanding of functions, events, and if/then statements.
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Series contents
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Article</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[Intro to module scripts](./intro-to-module-scripts.md)</td>
|
||||
<td>Learn how to use module scripts, a type of script that stores functions and variables that can be called or accessed from other scripts.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Create with module scripts](./create-with-module-scripts.md)</td>
|
||||
<td>Apply using module scripts to create a mini-game where players gather keys to open chests.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Coding abstraction](./coding-concept-abstraction.md)</td>
|
||||
<td>Abstractions in computer science provide a simplified representation of something larger. They pull out only the most necessary information and hide everything else.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[Coding algorithms](./coding-concept-algorithms.md)</td>
|
||||
<td>An **algorithm** uses a series of steps to determine an outcome. Steps can be a set of directions, comparisons, or even a mathematical formula.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
Loading…
Add table
Add a link
Reference in a new issue