Custom Panel Functions

Any panel can assign a custom function to render the panel, determine when an auto-advance conditions is met, or reset custom properties when the panel leaves the screen.

Table of contents

Render

Assign a custom render function to a panel’s renderFunction property. This function will be called every frame while your panel is on screen.

A render function should accept two parameters. The first is a table that represents the panel being rendered. The second parameter is a table with the current x and y scroll offset. The function returns nothing.

Example:

local function renderPanel6B(panel, offset)
 -- render the panel
end

Render Individual Layers

Setting a render function for a panel ejects it from the framework’s normal rendering flow. This means your function becomes responsible for all the logic and drawing in your panel.

Normally this would mean you need to calculate parallax and layer positions manually before drawing images to the screen (see below).

You can bypass those requirements by using the Panels.renderLayerInPanel() function. This allows you to intercept panel rendering with a custom function, alter layer data or toggle layers based on global variables, then hand them over to Panels to render for you.

The function accepts the layer data, the panel data, and the scroll offset.

Example:

local function renderPanel6B(panel, offset)
    for i, layer in ipairs(panel.layers) do
        if layer.name ~= 'hiddenLayer' then
            Panels.renderLayerInPanel(layer, panel, offset)
        end
    end
end

Drawing Layers Manually

If you choose not to use Panels.renderLayerInPanel(), then you’ll need to draw everything in your panel manually.

You can access your panel’s layers with the panel.layers property. Loop through them to draw the contents of your panel. An image layer will have the playdate.graphics.image stored in its img property.

Example:

local function renderPanel6B(panel, offset)
    for i, layer in ipairs(panel.layers) do
        layer.img:draw(layer.x, layer.y)
    end
end

Calculating Parallax

Since your panel has been taken out of the render flow, if you’re not using Panels.renderLayerInPanel() you’ll need to calculate layer position yourself if you want parallax scrolling.

The example below shows how you might calculate x position for layers in a horizontally-scrolling sequence. A vertical sequence would be the same, substituting y for x and height for width.

Example:

local ScreenWidth <const> = playdate.display.getWidth()

local function renderPanel6B(panel, offset)
    local frame = panel.frame

    -- calculate a percentage (0 - 1) that represents how far
    -- the panel has scrolled onto screen
    -- 0 == just entering, 1 == just leaving
    local scrollPct = 1 - (frame.x - frame.margin + frame.width + offset.x) / (ScreenWidth + frame.width)

    for i, layer in ipairs(panel.layers) do
        -- calculate the  x position based on the panel's scroll percentage
        -- and the layer's parallax property
        local p = layer.parallax or 0
        local xPos = math.floor(layer.x + (panel.parallaxDistance * scrollPct - panel.parallaxDistance/2) * p)

        layer.img:draw(xPos, layer.y)
    end
end


Advance

FOR AUTO-SCROLLING SEQUENCES ONLY

Assign a custom advance function to a panel’s advanceFunction property. This function will be called every frame until your panel advances.

In an auto-scrolling sequence, you can use this to determine whether the panel should advance or not. Simply return true or false to indicate whether the advance condition has been met.

Example:

local function advancePanel06B()
    -- this condition is often based on
    -- things happening in a custom render function
    if zoomLevel > 6.75 then
        return true  -- ready to advance
    else
        return false -- stay on this panel
    end
end

Reset

Assign a custom reset function to a panel’s resetFunction property. This function will be called once when your panel leaves the screen.

If the user navigates back to a panel with an advance function, the advance condition will still be true, so they’ll immediately advance again. To avoid this, you can reset the panel state here. This is also a good place to kill any sound effects, timers or handle any other cleanup (like turning off the accelerometer) that may have been initiated in the render function.

Example:

local function resetPanel06B()
    zoomLevel = 0 -- reset the var that determines the advance condition
    playdate.stopAccelerometer() -- clean up
end

Target Sequence

FOR NONLINEAR COMICS ONLY

Assign a custom function to a panel’s targetSequenceFunction property. This function will be called once when your panel leaves the screen.

In a comic with a branching storyline, you can define the next sequence to present by returning the sequence number from this function.

Example:

local function targetSequenceForS02()
    if didWinMinigame then
        return 4
    else 
        return 5
    end
end

Update

Assign a custom function to a panel’s updateFunction property. This function will be called every frame while your panel is on screen.

Update functions allow you to intercept user input or perform other custom logic without having to take over rendering the panel as you would with a custom render function.

Example:

local function updatePanel6B(panel, offset)
 -- handle input or perform other custom logic
end