Skip to main content

The Shindig: Building a cursor

· 5 min read
beho

As part of the PiCoSteveMo game jam I'm building a deck builder game where you host a great party.

The last time (see day 4) I worked on adding interactivity to show guests on the screen as they arrive at the party. I'd like to start working on showing a cursor to allow the party to be interactive.

I found a very cool cheat sheet for the PICO-8 APIs and specifications generally. Apparently there are an additional 16 secret colours I didn't know about. I might set this as my desktop background for a while whilst I get familiar with the system.

2025-11-10 1930: the cursor

Let's start by drawing a rectangle to represent the cursor. I think I'll do four one-pixel lines - and luckily there is a line method.

-- assuming a start x, y
-- the the other corner of a 2x3 block rectangle is
-- x + 8 * 2, y + 8 * 3
line(x, y, x + 8 * 2, y )
line(x, y, x, y + 8 * 3)
line(x + 8 * 2, y, x + 8 * 2, y + 8 * 3)
line(x, y + 8 * 3, x + 8 * 2, y + 8 * 3)

I want to be able to move the cursor with my arrow keys; this game is 1-D really so just left and right (buttons 0 and 1).

I can increase or decreate the cursor index to move left and right. I don't want the cursor index to go below zero or above the capacity of the party so I use max and min.

-- in function _update()
-- left button is pressed
if btnp(0) then Cursor = max(Cursor - 1, 0) end
-- right button is pressed
if btnp(1) then Cursor = min(Cursor + 1, Capacity) end

Finally I want to simulate cursor index 0 as the door, so let's limit accepting new guests to when the cursor is at the door.

-  if btnp(5) then
+ if btnp(5) and Cursor == 0 then

I would quite like to work out how to provide a user instruction with the special x button character.

It looks like the way is to write SHIFT-X in the PICO-8 code editor. Apparently they also have support for Japanese characters!

Saving SHIFT-X gives me a ❎ character so I'll try

print("press ❎ to let in a guest", 3)

a screenshot showing the cursor and the special glyph

Nice! I also found out I can hit F6 to take screenshots.

2000: wrapping guests

I'd like to visually represent the capacity of the party. So I'll draw the available space with a different colour.

-- assuming x, y as the start of party space
-- fill Capacity many 2x3 blocks
rect(x, y, x + 8 * 2 * (1 + Capacity), y + 8 * 3)

OK wild, rect is a method for drawing a rectangle outline and rectfill is a method for filling a rectangle. I can really simplify my cursor logic now.

It also looks like there's a method pset for my single pixel stars. Nice.

If I want to be able to support a party with more than 7 guests then I need to be able to wrap around. The logic for a cursor index should be:

-- x position is Cursor modulo 7
local cX = Cursor % 7
-- y position is Cursor divided by 7 with no remainder
local cY = flr(Cursor / 7)

I'm going to need to do something similar for printing the size of the room and each of the guests to wrap around.

2030: scenes

That seems to be more or less working. Now seems about the right time to introduce the party planning scene.

I'd like to split the state for these two scenes to separate logical objects. For this I think we can use the same init, update, draw hooks and call them from some scene manager. Then hopefully our draw logic would become something like this:

function _draw() {
CurrentScene:draw()
}

How does lua work? It looks like some functional something; this might work?

local PartyScene = {}
-- for unknown methods look in this PartyScene table
PartyScene.__index = PartyScene

function PartyScene:new()
local self = setmetatable({}, PartyScene)
return self
end

function PartyScene:init() end
function PartyScene:update() end
function PartyScene:draw() end

and then the import kind of works - it looks like I need to import everything in the .p8 cartridge and get the ordering right.

-- the-shindig.p8
#import party-scene.lua -- must come first
#import main.lua

-- main.lua
function _init()
Scene = PartyScene:new()
Scene:init()

I think I'll make a commit before doing this refactoring :/

Wow ok I think that worked.

function _init()
Scene = PartyScene:new()
Scene:init()
end

function _update()
Scene:update()
end

function _draw()
-- clear the screen to black
cls(0)

Scene:draw()
end

I probably want to work out where using global variables is appropriate but for now I'm happy.

2100 switching scenes

How to switch to the other scene?

It looks like I can switch to one scene if I have declared the other class first. But I want to also be able to switch back...

The game is having trouble indexing the global party scene :D.

an error message from lua about indexing the global party scene

Ah the issue is maybe that I'm declaring each of these classes as a local variable but I'm keeping this as a global. Maybe a problem for another day.