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.
|
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.
Create a new script in ServerScriptService named PartMaker. Copy the code below.
local numberOfBatches = 7local partsPerBatch = 5local partsMade = 0-- Makes a single cubelocal function createPart()local part = Instance.new("Part")part.Size = Vector3.new(2, 2, 2)part.CFrame = CFrame.new(20, 0, 20)part.Color = currentColorpart.Parent = workspaceend-- Outer loopfor partBatch = 1, numberOfBatches doprint("Top outer loop: part batch " .. partBatch)currentColor = Color3.fromRGB(math.random(0, 255), math.random(0, 255), math.random(0, 255))-- Inner loopfor partNumber = 1, partsPerBatch docreatePart()print("Inner loop: part " .. partNumber)partsMade += 1task.wait(0.5)endprint("Bottom outer loop: " .. partsMade .. " parts made so far.")task.wait(2)endWatch 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.
Coding 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.
Setting 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.
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.
Create a new script named TowerBuilder. Add variables for tower size and cube size at the top.
local TOWER_SIZE = 4local CUBE_SIZE = 2Add a local function named makeCube() that creates a single square cube using CUBE_SIZE.
local TOWER_SIZE = 4local CUBE_SIZE = 2-- Creates individual cubeslocal function makeCube()local cube = Instance.new("Part")cube.Size = Vector3.new(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE)endSet the cube's color to a variable which will be updated in the nested loops.
local function makeCube()local cube = Instance.new("Part")cube.Size = Vector3.new(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE)cube.Color = currentColorendLastly, parent the new cube to the workspace so it appears.
local function makeCube()local cube = Instance.new("Part")cube.Size = Vector3.new(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE)cube.Color = currentColorcube.Parent = workspaceend
Spawning 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.
In makeCube(), add parameters for spawnX, spawnY, and spawnZ. These numbers will set each new cube's spawn location.
-- Creates individual cubeslocal function makeCube(spawnX, spawnY, spawnZ)local cube = Instance.new("Part")cube.Size = Vector3.new(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE)cube.Color = currentColorcube.Parent = workspaceendInside the function, set the cube's CFrame property to a new CFrame using the spawnX, spawnY, spawnZ parameters.
local function makeCube(spawnX, spawnY, spawnZ)local cube = Instance.new("Part")cube.Size = Vector3.new(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE)cube.Color = currentColorcube.CFrame = CFrame.new(spawnX, spawnY, spawnZ)cube.Parent = workspaceend
Spawning 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.
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
-- Builds towerfor heightIndex = 1, TOWER_SIZE dolocal spawnY = (heightIndex - 1) * CUBE_SIZEendWith 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
for heightIndex = 1, TOWER_SIZE dolocal spawnY = (heightIndex - 1) * CUBE_SIZEfor lengthIndex = 1, TOWER_SIZE dolocal spawnX = lengthIndex * CUBE_SIZEendendInside 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.
-- Builds towerfor heightIndex = 1, TOWER_SIZE dolocal spawnY = (heightIndex - 1) * CUBE_SIZEfor lengthIndex = 1, TOWER_SIZE dolocal spawnX = lengthIndex * CUBE_SIZEfor widthIndex = 1, TOWER_SIZE dolocal spawnZ = widthIndex * CUBE_SIZEmakeCube(spawnX, spawnY, spawnZ)task.wait(0.25)endendendTo have each floor be a random color, change currentColor to random RGB numbers in the same loop in which you create a new floor.
for heightIndex = 1, TOWER_SIZE dolocal spawnY = (heightIndex - 1) * CUBE_SIZEcurrentColor = Color3.fromRGB(math.random(0, 255), math.random(0, 255), math.random(0, 255))for lengthIndex = 1, TOWER_SIZE dolocal spawnX = lengthIndex * CUBE_SIZEfor widthIndex = 1, TOWER_SIZE dolocal spawnZ = widthIndex * CUBE_SIZEmakeCube(spawnX, spawnY, spawnZ)task.wait(0.25)endendendRun the project and wait to see that a full tower has been created without any errors in the Output Window.
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.
The code solution is below.
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 Exampleto use your object instead of parts.
A sample is shown here.
A code solution using cupcakes is included.
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.