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,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