And because this section is titled “Storing Functions,” let’s use that to simplify the previous example.
First class functions… something something. Which means we can store functions in a table and also invoke it from there.
local functionList = {}
local objectList = {}
do
local model = Instance.new("Model")
local modelPart = Instance.new("Part")
modelPart.Position = Vector3.new(5, 5, 0)
modelPart.Anchored = true
modelPart.Parent = model
model.PrimaryPart = modelPart
model.Parent = game.Workspace
local part = Instance.new("Part")
part.Position = Vector3.new(-5, 5, 0)
part.Anchored = true
part.Parent = game.Workspace
objectList[1] = model
objectList[2] = part
end
local moveAmount = Vector3.new(0, 0, -0.25)
local runTimeLength = 10
local function moveModel(model)
model:TranslateBy(moveAmount)
end
local function movePart(part)
part.Position = part.Position + moveAmount
end
functionList["Model"] = moveModel
functionList["Part"] = movePart
local stopTime = tick() + runTimeLength
while tick() < stopTime do
for _, object in ipairs(objectList) do
functionList[object.ClassName](object)
end
task.wait()
end
We get rid of the getter function and store the function in a table using the object’s class name as the key.
If this looks confusing, functionList is just a key-value pair. The object’s class name is a string datatype, in this case ‘Part’ or ‘Model,’ and we use that for each key.
In line 40, the actual object’s class name indexes the required function. And then the parenthesis invokes the function, passing it the object as argument.
Here’s a similar example using an indexed array to store three functions. Each function will perform some animation on a part. We can then index the functions randomly and run them.
local part = Instance.new("Part")
part.Position = Vector3.new(0, 10, 0)
part.Anchored = true
part.Parent = game.Workspace
local function animatePartPosition(part)
local animationTime = 1
local radius = 10
local originalPosition = part.Position
local center = originalPosition + Vector3.new(radius, 0, 0)
local arcPerSec = 360 / animationTime
local currentAngle = -180
while animationTime > 0 do
local dt = task.wait() --delta time. how long the wait was.
currentAngle = currentAngle + dt * arcPerSec
part.CFrame = CFrame.Angles(0, math.rad(currentAngle), 0) * CFrame.new(radius, 0, 0) + center
animationTime = animationTime - dt
end
part.CFrame = CFrame.new(originalPosition)
end
local function animatePartSize(part)
local animationTime = 2
local originalSize = part.Size
local endSize = Vector3.new(8, 4, 16)
local xChangePerSec = (endSize.X - originalSize.X) / animationTime
local yChangePerSec = (endSize.Y - originalSize.Y) / animationTime
local zChangePerSec = (endSize.Z - originalSize.Z) / animationTime
while animationTime > 0 do
local dt = task.wait()
part.Size = part.Size + Vector3.new(xChangePerSec * dt, yChangePerSec * dt, zChangePerSec * dt)
animationTime = animationTime - dt
end
part.Size = originalSize
end
local function animatePartColor(part)
local animationTime = 3
local colorShowTime = 0.05
local maxShowTime = 0.5
local lastChange = math.huge
while animationTime > 0 do
local dt = task.wait()
lastChange = lastChange + dt
if lastChange > colorShowTime then
part.BrickColor = BrickColor.random()
lastChange = 0
if colorShowTime < maxShowTime then
colorShowTime = colorShowTime + dt / 2 --this increase amount is arbritrary
end
end
animationTime = animationTime - dt
end
end
local functionList = {
animatePartPosition,
animatePartSize,
animatePartColor
}
while task.wait(1) do --returns truthy value (number) and waits here
local randIndex = math.random(#functionList)
print(randIndex)
functionList[randIndex](part)
end
It’s worth noting that these examples were written to illustrate the process of approaching a problem and not designed to be optimal.
Later on we’ll learn how to use the built-in methods to accomplish similar results more efficiently. Take from it the process and don’t attempt to commit the solution to memory.