How to use playdate.serialMessageReceived to optimize your dev workflow

An important part of using any SDK is optimizing the developer experience. When building web applications, URLs make it pretty fast to iterate on a given page's design and functionality by just refreshing your browser. With games, since there's not a concept of a URL, it can be quite painful to:

  1. Compile the game
  2. Open it in the Simulator
  3. Play the game until to you get the point of the screen you're working on

Part 3 can be super tedious. And if you're making small changes often and testing them out, this becomes untenable.

I've been exploring the different ways to optimize this developer experience and wanted to share how one could use playdate.serialMessageReceived in the SDK to issue commands that your game can respond to, speeding up the development process.

playdate.serialMessageReceived is a callback that you can implement that receives a message parameter that you send to your device or the Simulator via the Lua console and entering !msg yourMessage. There are a lot of possibilities of what you could use this for:

  • Switching to a specific scene or a level
  • Sending along JSON data that you process for something that assists with development
  • Sending along custom level data without reuploading the game
  • Changing variables
  • More things I'm not even aware of yet??

In this little tutorial, we'll do the first one: quickly switch between the scenes in our game.

Let's say you have a Playdate game with a scenes table. And each scene implements update(), like function scenes.gameplay.update() and function scenes.mainMenu.update():

local scenes = {}

scenes.mainMenu = {}
function scenes.mainMenu.update()
	playdate.graphics.drawText("Main Menu", 10, 10)
	if playdate.buttonJustPressed(playdate.kButtonA) then
		scenes.current = scenes.gameplay
	end
end

scenes.gameplay = {}
function scenes.gameplay.update()
	playdate.graphics.drawText("Gameplay", 10, 10)
	if playdate.buttonJustPressed(playdate.kButtonB) then
		scenes.current = scenes.mainMenu
	end
end

scenes.current = scenes.mainMenu

function playdate.update()
	playdate.graphics.clear()
	scenes.current.update()
end

We set the current scene to the main menu when the game boots. And we call out to the current scene's update function in playdate.update().

If you want to switch scenes, you'd just change scenes.current. Pretty simple. To make it easy to switch to a given scene from the Lua console, just add this function:

function playdate.serialMessageReceived(message)
	print("Received message: " .. message)
	if string.find(message, "scene:") == 1 then
		local scene = string.sub(message, 7)
		print("Switching to " .. scene .. " from serialMessageReceived")
		local newScene = scenes[scene]

		if newScene == nil then
			print("Scene " .. scene .. " does not exist")
			return
		end

		scenes.current = newScene
	end
end

This implements the callback for whenever a message is received from the Lua console. If !msg scene:gameplay or !msg scene:mainMenu is passed in, it switches to it.

Here's a screenshot of me testing this out with the Simulator:

If your Playdate device was connected and unlocked, you could send these commands to your actual hardware.

Also, when my Playdate is connected to my Linux machine at /dev/ttyACM0, I'm able to send it messages like this:

echo "msg scene:gameplay" > /dev/ttyACM0

While the example provided is quite trivial, imagine your game has dozens of scenes and some of them are quite complex to get to. This could save you minutes of navigating to it. And it's much more flexible than using the simulator's keyboard callbacks or magic button presses.

Because of the serial connection, it wouldn't be too difficult to write a script that executes a series of in-game commands.

Here's the full source code on GitHub: pdprototypes/signal_switch/source/main.lua at main · brettchalupa/pdprototypes · GitHub

There are lots more possibilities here that I'm excited to explore! Hope this helps some folks.

Do you use playdate.serialMessageReceived for anything in your game?

13 Likes

Yeah I use it on every project.
In debug builds I hook up config vars so they can be tweaked by command.

I use it for jumping to specific scenes similar to you. For giving items to the player, clearing save data or tweaking save data values.
It's really handy.

Another useful tool is listening for inputs in the simulator. I bind keyboard buttons to my commands as well so if I'm testing in sim, I can press 'h' to heal, or the '1', '2', '3', etc keys for each scene.

3 Likes

Awesome idea, I'm going to start doing this too. Between the serial messages and sim keyboard, the possibilities are quite robust.

2 Likes