5.4.2 Storing Functions

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.

Lua
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.

Lua
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.