RoboCatz.com
About FLL | Navigation | Playbook | Strategy | Models | Techniques | RobotC | Programming | Robot News |

Roblox Basics

This lesson is a continuation of previous lessons in Roblox programming. If you are not familiar with how to create the genericShapes module, please review the other Roblox lessons first.

What is the genericShapes ModuleScript?

The genericShapes module is a graphic library used to create and manipulate simple graphic shapes using a set of functions that accept a wide variety of data in various formats used to configure the shapes. The genericShapes module is to be located in the ReplicatedStorage area in the Explorer windows of Roblox Studio.

Where can I find the genericShapes ModuleScript?

You create the genericShapes module by inserting a ModuleScript in the ReplicatedStorage area. Then renaming the new module to "genericShapes". Then you can copy the code from the web page linked below. Be careful to only copy the Roblox code. Do not copy the web page's menu or headers/footers.

genericShapes Module (genericShapes-ModuleScript.htm)
Copy the code from this page into the genericShapes module in your program.

Adding the genericShapes ModuleScript

Add a module to ReplicatedStorage. Rename the module: "genericShapes"

This module will contain the basic functions for drawing shapes such as squares, circles, cubes, spheres, panels, rectangles, discs, etc. As a module, it will be initially created with the default beginning and ending lines (see below).

In Lua, the expression "{}" represents an empty Table. It has some similarities to an "object" in JavaScript. The empty table is assigned to a variable and then the variable is returned as the last line in the module.

Example:
local module = {}

return module
The example above is the default code that will appear when you first create the ModuleScript file. You need to replace this code with the contents copied from the web page linked above.

In case you missed it. You need to CLICK on the link to the genericShapes module. Then COPY the contents of the web page (not the header and footer). Then PASTE it into the genericShapes Module you just created in Roblox.

In summary, you are copying code from a website and pasting it into your Roblox project in a specific module called genericShapes.

Do not proceed with this lesson until you have performed this Copy-and-Paste.

Why Copy-and-Paste from the website?

The reason why you are copying-and-pasting code from the website is because
  1. The amount of code to be copied is well over 2000 lines of code. It is a Graphics Library of functions.
  2. The website will have the most up-to-date version of the Graphics Library
  3. There will be more consistency between our programs if everyone is using the same Graphics Library

Is your genericShapes module in place?

If your genericShapes module is in the ReplicatedStorage of your Roblox project and you have copied and pasted the thousands of lines of code into the file, then you may continue with the lesson.


The next step is to go to the Workspace in Roblox and add a Script. Rename that script: startingScript and paste the code in the example below.

Example:
--Workspace.startingScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local s = require(ReplicatedStorage.genericShapes)
The three lines of code above create a local variable "s" that will contain the genericShapes module. You can then use this variable to call the functions of genericShapes to create "generic shapes".

Add the line of code below.

Example:
s.circle()
The line of code above creates a circle. Note that the circle() function is now part of the variable "s" and if you want to draw a circle, you have to make a reference to the "s" variable.

At this point, the starting script should appear as shown in the example below.

Example:
--Workspace.startingScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local s = require(ReplicatedStorage.genericShapes)

s.circle()
Run the program now and you should see a circle.

The line of code below creates a cube. Note that the cube() function is part of the genericShapes module which is now stored in the variable "s" and if you want to draw a cube, you have to reference the "s" variable when calling the function.

Replace the circle function with the line of code below.

Example:
s.cube()
The line of code above creates a cube. Note that the cube() function is part of the genericShapes module and because the module is stored in the variable "s", if you want to draw a cube, you have to make a reference to the "s" variable.

At this point, the starting script should appear as shown in the example below.

Example:
--Workspace.startingScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local s = require(ReplicatedStorage.genericShapes)

s.cube()
Run the program now and you should see a cube.

The line of code below creates a disc. Note that the disc() function is part of the genericShapes module which is now stored in the variable "s" and if you want to draw a disc, you have to reference the "s" variable when calling the function.

Replace the cube function with the line of code below.

Example:
s.disc()
At this point, the starting script should appear as shown in the example below.

Example:
--Workspace.startingScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local s = require(ReplicatedStorage.genericShapes)

s.disc()
Run the program now and you should see a disc.

These shapes were drawn using default settings for each shape. You are able to create shapes with different sizes, colors, orientations, and positions. For example, try the following code.

Example:
s.circle("red")
Or, how about the following:

Example:
s.disc("lavender")
Or, how about the following:

Example:
s.cube("MediumSpringGreen")

Color names in this graphics library are case insensitive.

The color name could be upper case, mixed case, or lower case. It doesn't matter to the function. The only thing important for the function is the spelling of the color name.

How do you know what color names are used by the program?

Open the genericShapes script (you may have to double-click on the genericShapes module in ReplicatedStorage). Then scroll to about line 120 in genericShapes. There you will find a list of about 120 color names.

Specifying a color using the Color3 object.

Instead of typing a color name, you can specify a color by using a color function and giving 3 numbers to represent the amount of red, green, and blue. For example, see below.

Example:
s.cube(Color3.new(1, 0, 1))
If you use the Color3.new() function for specifying a color, please note that the capitalization is important when typing: Color3.new().

color3.new() - Incorrect capitalization
Color.new() - Forgot the number "3"
Color3() - Forgot the ".new"

Specifying an object's size

You can specify a size of an object simply by entering a number as a parameter for the constructor function. See below.

Example:
s.circle(25)

Specifying an object's position

If you pass two numbers to the function, the first will be interpreted as the x-coordinate and the second will be interpreted as the y-coordinate.

Example:
s.sphere(5, 15)
Passing three numbers to the function will be interpreted as the x, y and z-coordinates.

Example:
s.sphere(-5, 15, 30)
And 4 numbers will be interpreted as the x, y, z coordinates and radius.

Example:
s.sphere(-5, 15, 30, 3)

How do you know what each number and word means?

You could examine the genericShapes module for some clues as to what the different parameters mean. A paragraph of text is shown before each function definition in the genericShapes module. This paragraph will include examples of the different forms of the function. You can pass strings, numbers, colors, and materials into the functions.

The functions in the genericShapes module will examine the arguments, determine their type, and then use them as specific parameters for the function based on the argument type.

The first 100 lines of the genericShapes module is a comment explaining the different forms of the functions and ways you can use them in your program.

Passing an Object

You can pass an object which contains name/value pairs. This may be an easier way for you to specify what number represents what type of value. For example, you could include an expression such as "x=5" to indicate that the x-coordinate should have the value "5".

If you use name/value pairs, you just need to remember that each name/value pair must be separated from other pair using the comma and the entire list of name/value pairs needs to be encapsulated with curly braces. See example below.

Example:
--Workspace.startingScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local s = require(ReplicatedStorage.genericShapes)

-- 2D and 3D objects positioned using only an X, Y, and Z Coordinate
s.disc(     { x=-16,y=3, z=15, size=6, thickness=0.5, color="red" })
s.circle(   { x=-8, y=3, z=15, size=6, thickness=0.5, color="red", luminosityRange=1, luminosityHue=Color3.new(1,1,0)})
s.square(   { x=0,  y=3, z=15, size=6, thickness=0.5, color="red", luminosityRange=1, luminosityHue=Color3.new(1,1,0)})
s.rectangle({ x=8,  y=5, z=15, height=8, width=4, thickness=0.5, color="red", luminosityRange=1, luminosityHue=Color3.new(1,1,0)})
s.rectangle({ x=8,  y=5, z=35, height=8, width=4, thickness=0.5, length=15, color="blue", luminosityRange=1, luminosityHue=Color3.new(1,1,0)})
s.panel(    { x=16, y=5, z=15, height=8, width=4, thickness=0.5, color="red", luminosityRange=1, luminosityHue=Color3.new(1,1,0)})

s.disc(     { x=-16,y=3, z=25, size=0.2, thickness=15, color="yellow", rotateBy=Vector3.new (0, 0,90) })
s.disc(     { x=-16,y=3, z=35, size=0.2, thickness=15, color="yellow", rotateBy=Vector3.new(90, 0, 0) })
s.disc(     { x=-16,y=5, z=45, size=8,   thickness=10, color="green",  rotateBy=Vector3.new( 0, 0,90) })
s.sphere(   { x=-24,y=3, z=15, size=2,                 color="green" })
s.sphere(   { x=-24,y=3, z=25, size=6,                 color="green" })
s.sphere(   { x=-24,y=6, z=35, size=9,                 color="green" })
s.sphere(   { x=-24,y=-3,z=55, size=12,  color="lightcoral", opacity=0.7, material=Enum.Material.Air })

s.cube(     { x=16, y=6, z=25, size=4, color="green", rotateBy=Vector3.new(0,0,45) })
s.cube(     { x=16, y=3, z=45, size=6, color="brown", material=Enum.Material.Wood  })

s.cube(     { x=0, y=-0.35 * 8, z=8/1.5+25, size=8, rotateBy=Vector3.new(45,0,45), Material = Enum.Material.Granite, Color="tan" } )

s.circle(   { x=-32, y=3, z=35, size=10, thickness=0.5, length=21, color="blue", luminosityRange=1, luminosityHue=Color3.new(1,1,0)})
s.tube(     { x1=-48, y1=3, z1=55, x2=-48, y2=3, z2=25, size=20, thickness=10, color="orange"})

s.wall(     { x1=36, y1=0, z1=55, x2=36, y2=10, z2=25, thickness=10, color="red", material=Enum.Material.Brick})
s.wall(     { x1=58, y1=0, z1=55, x2=58, y2=10, z2=25, thickness=10, color="gray", material=Enum.Material.Cobblestone})
s.wall(     { x1=80, y1=0, z1=55, x2=80, y2=10, z2=25, thickness=10, color="brown", material=Enum.Material.WoodPlanks})

s.archway(  { x=16, y=3, z=55, size=0.5, height=10, width=10, color="brown", material=Enum.Material.Wood  })
s.archway(  { x=16, y=3, z=65, size=5, height=10, width=10, color="gray", material=Enum.Material.Cobblestone  })
s.archway(  { x=16, y=3, z=85, size=15, height=30, width=30, color="gray", material=Enum.Material.Cobblestone  })

s.sphere(   { x=48, y=4, z=105, size=8,  color=s.randomColor(), material=Enum.Material.Pebble, anchored=false })
s.sphere(   { x=40, y=4, z=105, size=8,  color=s.randomColor(), material=Enum.Material.Mud, anchored=false })
s.sphere(   { x=32, y=4, z=105, size=8,  color=s.randomColor(), material=Enum.Material.Wood, anchored=false })
s.sphere(   { x=24, y=4, z=105, size=8,  color=s.randomColor(), material=Enum.Material.Brick, anchored=false })
s.sphere(   { x=16, y=4, z=105, size=8,  color=s.randomColor(), material=Enum.Material.Cobblestone, anchored=false })
s.sphere(   {  x=8, y=4, z=105, size=8,  color=s.randomColor(), material=Enum.Material.Rock, anchored=false })
s.sphere(   {  x=0, y=4, z=105, size=8,  color=s.randomColor(), material=Enum.Material.Neon, anchored=false })
s.sphere(   { x=-8, y=4, z=105, size=8,  color=s.randomColor(), material=Enum.Material.Fabric, anchored=false })
s.sphere(   { x=-16,y=4, z=105, size=8,  color=s.randomColor(), material=Enum.Material.Foil, anchored=false })
s.sphere(   { x=-24,y=4, z=105, size=8,  color=s.randomColor(), material=Enum.Material.Glass, anchored=false })
s.sphere(   { x=-32,y=4, z=105, size=8,  color=s.randomColor(), material=Enum.Material.Plaster, anchored=false })
s.sphere(   { x=-40,y=4, z=105, size=8,  color=s.randomColor(), material=Enum.Material.Marble, anchored=false })
s.sphere(   { x=-48,y=4, z=105, size=8,  color="darkgray", material=Enum.Material.CorrodedMetal, anchored=false })
Copy and paste the above example into your startingScript. Make sure to delete all of the code from your startingScript before pasting in the new example code. The above example code contains all of the statements and functions needed for this example startingScript.

This example creates a variety of shapes in a variety of locations, sizes, orientations and colors. Run it to examine what shapes are created.

Can you locate any specific shapes and find the code in the example that created that shape?

Coordinates

Most of the examples shown have x, y and z coordinates. There are a few shapes that require two sets of coordinates (x1, y1, z1, x2, y2, z2). These shapes originate at one of the coordinates and then extend to the other coordinate. For example, the s.wall() function requires two sets of coordinates (one for the beginning of the wall and one for the end of the wall). The height of the wall is specified through the variation in the two y-coordinates. The location of the wall is specified through the x and z coordinates.

Anchored

The parts are "anchored" to the world by default. However, if you set the "anchored" property to "false" you will be able to move the part (depending on its size and shape). Try moving the spheres in the back row of the previous example.

Your Turn

Try to create a new scene using the various shapes, materials, sizes, and colors.

New Project

Delete everything from the starting script (leave the genericShapes module intact). Then copy the code below to the starting script.

Example:
--Workspace.startingScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local s = require(ReplicatedStorage.genericShapes)

local base = 10
s.cube( { x=0, y=-0.35 * base, z=base/1.5+25, size=base, rotateBy=Vector3.new(45,0,45), Material = Enum.Material.Granite, Color=Color3.new(1, 0.333333, 0) } )
What do you think the expression "base = 10" means?

Try changing the value to a higher number. Does Roblox have a limit on the size of the objects it can draw? Can you find the limit?

Ok. Delete that code from the startingScript and copy the example below.

Example:
--Workspace.startingScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local s = require(ReplicatedStorage.genericShapes)

local numLayers = 12
local base = 100
local baseInterval = base / numLayers
local centerX, centerZ = base/2, base/2+25
local currentY = (base/numLayers)/2
for i=1,numLayers do
	local layer = s.cube( { x=centerX, y = currentY, z=centerZ, size = 1, Material = Enum.Material.Granite, Color=Color3.new(1, 0.333333, 0)})
	layer.Size = Vector3.new(base, baseInterval, base)
	currentY = currentY + baseInterval
	base = base - baseInterval
end
The above example uses a for loop to create the various layers of the pyramid. Try changing the numLayers variable to 36 instead of 12. Do you see more layers?

Within each iteration of the for loop, a variable called "layer is created and assigned the value of a "s.cube()" which has a size of 1. The layer is then "resized on the next line of code where it says: layer.Size = Vector3.new(base, baseInterval, base)

In this code, the base represents the length of the layer's sides. The height of the layer is set to the value of the baseInterval which is the original base divided by the number of layers.

Each time through the loop, the base is shrunk (diminished) by the baseInterval value. Also, the y-coordinate is incremented by the baseInterval value.

New Project

Delete all the code from the startingScript and copy the code below.

Example:
--Workspace.startingScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local s = require(ReplicatedStorage.genericShapes)

local base = 100
local pyramid = s.cube( { x=0, y=-0.35 * base, z=base/1.5+25, size=base, rotateBy=Vector3.new(45,0,45), Material = Enum.Material.Granite, Color=Color3.new(1, 0.333333, 0) } )
for j=1,30 do
	local randomSphere = s.sphere({ x=base*0.4*math.random()-20, y=base*0.4*math.random(), z=base*0.8*math.random()+30, size=math.random()*base*0.3})
	pyramid = s.subtract(pyramid, randomSphere)

	s.sleepMilliseconds(250)
end
This program uses a for loop--but not to create the pyramid. This program uses a for loop to delete the pyramid. You may notice that as you run over the pyramid, you are sometime entering the interior and sometimes floating in space above the pyramid. This is because the computer is altering the "mesh" but does so in a way that is not very precise.

Note also that the s.sleepMilliseconds() allows you to visually observe the deletions. Try commenting out that line of code.

Subtraction

As you can see from the previous example, you can subtract one part from another part. This is how shapes such as the s.archway(), s.circle(), s.tube(), and s.square() were created.

To subtract a part, you need to write a specific form of expression:

newPart = s.subtract(mainPart, partBeingSubtracted)

I highlighted newPart and mainPart because in some cases they may be the same part. But they do not always have to be the same part.

To subtract a sphere from a cube, you would write the following:

Example:
--Workspace.startingScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local s = require(ReplicatedStorage.genericShapes)

local myCube = s.cube({ x=0, y=10, z=30, size=20})
local myNegativeSphere = s.sphere({ x=0, y=10, z=30, size=25})
local myNewCube = s.subtract(myCube, myNegativeSphere)

Your Turn

Create new shapes by subtracting one shape from another.
Try using a for loop to make multiple subtractions from one shape.

Using For Loops

Look at the following code. Copy and run it in your world.

Example:
--Workspace.startingScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local s = require(ReplicatedStorage.genericShapes)

local numRows = 10
local numCols = 10
local size=10
for i=1,numRows do
	for j=1, numCols do
		s.panel( { x=(i-numRows/2)*size, y=math.random()*1, z=(j-numCols/2)*size, width=size, height=size, thickness=0.5, color=s.randomColor(), rotateBy=Vector3.new(0,0,0) })
	end
end
What do you think the y-coordinate does? How is the value for the y-coordinate determined? What does *1 do? What if you changed it to *10?

For a panel, the dimensions of width and height change the shape of the panel. Try using the expression width=size*0.6

Next try changing the height to: height=size*0.6

Altering the Baseplate

Example:
--Workspace.startingScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local s = require(ReplicatedStorage.genericShapes)

local numRows = 10
local numCols = 10
local size=10
for i=1,numRows do
	for j=1, numCols do
		s.panel( { x=(i-numRows/2)*size, y=math.random()*10, z=(j-numCols/2)*size, width=size*0.6, height=size*0.6, thickness=0.5, color=s.randomColor(), rotateBy=Vector3.new(0,0,0) })
	end
end
if workspace:FindFirstChild("Baseplate") then workspace.Baseplate:Destroy() end

Altering the Time of Day

Example:
--Workspace.startingScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local s = require(ReplicatedStorage.genericShapes)

local numRows = 10
local numCols = 10
local size=10
for i=1,numRows do
	for j=1, numCols do
		s.panel( { x=(i-numRows/2)*size, y=math.random()*10, z=(j-numCols/2)*size, width=size*0.6, height=size*0.6, thickness=0.5, color=s.randomColor(), rotateBy=Vector3.new(0,0,0) })
	end
end
if workspace:FindFirstChild("Baseplate") then workspace.Baseplate:Destroy() end
game.Lighting.TimeOfDay = "1:30"

Your Turn

Experiment with different shapes. In the examples above, the s.panel() function is used.

Do you remember how to draw other shapes? Look at the previous examples if you want to see how to draw different shapes. Try altering the above program to use different shapes. What about different widths, heights, thicknesses. Use your imagination to make a complex world to explore.

Can you randomize the particular shapes being drawn? For example: sometimes drawing a circle, sometimes drawing a cube, sometimes drawing a sphere, etc.


End of Document