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:
- Compile the game
- Open it in the Simulator
- 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?