Project OutFox Wiki
Project OutFox home View the OutFox Wiki source on GitHub Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

ActorScroller

The Actorscroller is an ActorFrame that acts as a scroller, allowing for a selection-styled menu with choices and animations.

Def.ActorScroller{
	NumItemsToDraw = 3,
	SecondsPerItem = 3,
	TransformFunction = function(self, offset, itemIndex, numItems)
	end,
	Subdivisions = 4,
	UseMask = false,
	MaskWidth = 30,
	MaskHeight = 50,
	LoopScroller = false,
	WrapScroller = false,
}

Attributes

Name Type Action
NumItemsToDraw number How many items will be drawn at once on the ActorScroller.
SecondsPerItem number How long will the scroller take before moving to the next item.
TransformFunction function The function that positions every item in the ActorScroller. For more information, check Transforming the Scroller.
Subdivisions number How many subdivisions should there be between each item? This allows for smoother movement for scrollers that contain any mathematical curve.
UseMask bool Toggles a mask on the top and bottom of the ActorScroller.
MaskHeight number Height of the mask present on the top and bottom of the ActorScroller. Requires UseMask to be true.
MaskWidth number Width of the mask present on the top and bottom of the ActorScroller. Requires UseMask to be true.
LoopScroller bool Loops the selection of the scroller to wrap around.
WrapScroller bool Wraps the items of the scroller to attempt a seamless transition back.

Adding actors

To add actors to the ActorScroller, simply add them directly to the scroller, or using the children attribute for ActorFrame.

The direct method.

local af = Def.ActorFrame{}

af[#af+1] = Def.ActorScroller{
	NumItemsToDraw = 15,
	TransformFunction=function(self, offset, itemIndex, numItems)
		self:y( 10 * offset )
	end,

	Def.BitmapText{ Font="Common Normal", Text="I am Item 1" },
	Def.BitmapText{ Font="Common Normal", Text="I am Item 2" },
	Def.BitmapText{ Font="Common Normal", Text="I am Item 3" },
	Def.BitmapText{ Font="Common Normal", Text="I am Item 4" },
}

return af

The function method

All actors being added via the children method have to be added to an ActorFrame wrapper, which will be included in this demonstration.
local af = Def.ActorFrame{}

local function generateItemsForScroller()
	-- When using the children attribute, the result of the function must
	-- be wrapped in an ActorFrame, which in this case is t.
	local t = Def.ActorFrame{}
	
	for i = 1,4 do
		t[#t+1] = Def.BitmapText{ Font="Common Normal", Text="I am Item ".. i }
	end
	
	return t
end

af[#af+1] = Def.ActorScroller{
	NumItemsToDraw = 15,
	TransformFunction=function(self, offset, itemIndex, numItems)
		self:y( 10 * offset )
	end,
	children = generateItemsForScroller()
}

return af

Transforming the Scroller

To perform a different scroll to the ActorScroller, the TransformFunction is used. This function provides 4 arguments:

  • self (Actor): The actor in question.
  • offset (number): The relative 0 offset of the current item.
By this, it means that, if the value is 0, That’s the current item. Anything before or after is - 1 / + 1 respectively.
  • itemIndex (number): The index of the current item to the entire list of items.
  • numItems (number): The total amount of items currently available.

For this example, let’s make a vertical scroller. When we say vertical, we mean that we want each item to scroll through the Y axis. So, taking that into consideration, we can end up with a function like this:

TransformFunction=function(self, offset, itemIndex, numItems)
	-- We're telling the game here that each item has a space
	-- of 60 vertical pixels between each item.
	self:y( 60 * offset )
end

This next example let’s us create a circular scroller. This is by using cosine and sine functions.

TransformFunction=function(self, offset, itemIndex, numItems)
	self:xy( math.cos(offset) * 150, math.sin(offset) * 150 )
end

Here we’re telling the game to perform the operation on the X and Y axis, and they’re using cosine and sine respectively. These two values return a value of -1 to 1. By having these two values in sync with each other, we’re effectively creating a circunference, which in turns provides us with a circle.

Subdivisions

You may have noticed that while scrolling with this, it won’t scroll like a circle, and that’s because there aren’t that many items to scroll through to provide the motion. You could either add more items to fulfill the item criteria or use Subdivisions.

The general (very summarized) rule with subdivisions on the actor scroller is that it adds N amount of items in-between existing items to provide a smoother scroll when using functions.

Subdivisions = 2

--[[
	Item 1
	--
	--
	Item 2
	--
	-- 
	Item 3
]]
local af = Def.ActorFrame{
	InitCommand=function(self)
		self:Center()
	end
}

local function generateItemsForScroller()
	-- When using the children attribute, the result of the function must
	-- be wrapped in an ActorFrame, which in this case is t.
	local t = Def.ActorFrame{}
	
	for i = 1,20 do
		t[#t+1] = Def.ActorFrame{
			Def.BitmapText{
				Font="_eurostile normal",
				Text="I am Item ".. i,
			}
		}
	end
	
	return t
end

af[#af+1] = Def.ActorScroller{
	NumItemsToDraw = 20,
	SecondsPerItem = 0.2,
	Subdivisions = 4,
	WrapScroller = true,
	LoopScroller = true,
	OnCommand=function(self)
		self:SetFastCatchup(true)

		-- For more information about this Input Controller, check "Custom Input".
		-- https://outfox.wiki/dev/theming/Theming-Custom-Input/
		self.controller = LoadModule("Lua.InputSystem.lua")(self)
		SCREENMAN:GetTopScreen():AddInputCallback(self.controller)
	end,
	OffCommand=function(self)
		SCREENMAN:GetTopScreen():RemoveInputCallback(self.controller)
	end,
	TransformFunction=function(self, offset, itemIndex, numItems)
		self:xy( math.cos(offset) * 150, math.sin(offset) * 150 )
		-- Let's mark the current choice with the color green.
		if offset == 0 then
			self:diffuse(Color.Green)
		else
			self:diffuse(Color.Orange)
		end

		-- You can also interpret that if statement with a ternary method.
		-- self:diffuse( offset == 0 and Color.Green or Color.Orange )
	end,
	children = generateItemsForScroller(),
	-- Let's add input to this scroller.
	MenuLeftCommand=function(self)
		self:SetDestinationItem( self:GetCurrentItem() - 1 )
	end,
	MenuRightCommand=function(self)
		self:SetDestinationItem( self:GetCurrentItem() + 1 )
	end
}

return af

Functions

PositionItems

Forces all items to position themselves back into position. Useful if you happen to encounter a situation where the scroller doesn’t end exactly on the item you’ve selected.

SetTransformFromFunction

(function transformFunction)

The equivalent of the TransformFunction provided on the Attributes list. Allows you to add a new function in runtime, such as for example, converting the list from a vertical one to a horizontal one once the user has selected something.

SetTransformFromHeight

(number itemHeight)

An alias for SetTransformFromFunction that will convert the scroller to a vertical one.

SetTransformFromWidth

(number itemWidth)

An alias for SetTransformFromFunction that will convert the scroller to a horizontal one.

SetCurrentAndDestinationItem

(number index)

Tells the ActorScroller to set both Current and Destination to index. This can be useful if you want to move to the option index instantly.

SetDestinationItem

(number index)

Tells the scroller to move to index for its destination.

GetSecondsToDestination

Gives you a number indicating how long it will take before reaching the destination, which is the newly selected item.

SetSecondsPerItem

(number seconds)

Changes the scroll length for each item.

SetSecondsPauseBetweenItems

(number seconds)

Changes how long the scroller must wait while scrolling through an item.

GetSecondsPauseBetweenItems

Gets the amount of time the scroller must wait while scrolling through an item.

SetPauseCountdownSeconds

(number state)

Set the amount of time to wait fully when pressing a button. This value works alongside SetSecondsPauseBetweenItems to calculate a pause time.

SetNumSubdivisions

(number numDivisions)

Sets the amount of Subdivisions for the scroller.

ScrollThroughAllItems

Forces the scroll to scroll through all of the items present.

ScrollWithPadding

(number beforeItems, number afterItems)

Makes the scroller move automatically with a number of empty items to add at the start and end. You can use this to create credit sequences.

SetFastCatchup

(bool state)

Accelerates the amount of time it takes to go from an item to another if it’s more than 1.

For example, let’s say you’re in position 1, and you want to go to 5. You have SecondsPerItem set to 1; so it would take a second to go through each item, totalling 5 seconds.

With SetFastCatchup, it will speed up based on how many items it needs to jump through to scroll roughly the same amount of time it takes to scroll to one.

SetLoop

(bool state) Toggles looping.

SetWrap

(bool state)

Toggles wrapping.

SetMask

(bool state)

Toggles the Mask.

SetNumItemsToDraw

(number numItems)

Changes the value of items to draw at once.

GetFullScrollLengthSeconds

Returns the total amount of time it would take to do a full rotation of the entire scroller. This is counting all of the items and subdivisions with the amount of time set in per item (SecondsPerItem).

GetCurrentItem

Returns the currently selected item.

GetDestinationItem

Gets the item that the scroller is currently traveling to.

GetNumItems

Returns the number of items available on the ActorScroller.