Developing for Playdate

Ok, time for the technical part. This section is aimed more towards people interested in developing for Playdate and includes a lengthy analysis of some SDK release notes. With that enticement I know it will be hard to stop reading, but I understand completely if you do.

Overview

SDK Scraps

Panic shared a screenshot of the internal release notes for Playdate SDK 0.6 which I have transcribed below.

Added

New CoreLibs/Animator module, and animator.lua single file example

Animators can now be added to sprites for automatic animation

playdate.graphics.tilemap:drawAt() can now accept a sourceRect argument

can now accept a sourceRect argument Added documentation for playdate.graphics.image:drawAnchored()

New gridview.lua single file example

Button polling functions playdate.buttonIsPressed() , playdate.buttonJustPressed() , and playdate.buttonJustreleased()

, , and Added playdate.sound.track and playdate.sound.controlsignal to audio sequencer API

and to audio sequencer API It’s now possible to create a playdate.sound.sequence from code, not just MIDI files

from code, not just MIDI files Added playdate->lua->getArgType() to C API

to C API Added playdate->lua->indexMetatable() for classes to use in their __index implementation

for classes to use in their implementation Added playdate->system-getSecondsSinceEpoch()

Added playdate->system->drawFPS() to C API and playdate.drawFPS to Lua

to C API and to Lua Added Inside Playdate with C documenting the C API

Added playdate->sprite->getImageFlip() to C API and playdate.graphics.sprite.getImageFlip() to Lua

to C API and to Lua Added Exposure demo to C API Examples

Added mouse-drag cranking to the simulator: double-click in the crank view to start, drag the mouse to crank, click again to end

Fixed

Truncation issue in playdate.graphics.drawTextInRect()

Settings menus don’t respond to holding down up/down button

Arguments returned in playdate.cranked() are no longer swapped

are no longer swapped playdate.graphics.tilemap:setTiles() now sets the last column properly

now sets the last column properly drawTextAligned() now correctly right-aligns strings containing newlines

now correctly right-aligns strings containing newlines Repeating timers now provide continuous values rather than snapping back to the start value

CoreLibs/gridview.lua bugs

playdate.graphics.sprites.getAllSprites() now returns an empty table instead of nil when there are no sprites

now returns an empty table instead of nil when there are no sprites Setting a draw offset now marks all sprites as dirty

Bug in some C API graphics functions causing screen to not be marked dirty

playdate.sound.lfo can now change values in the middle of an update cycle

can now change values in the middle of an update cycle playdate.sound.synth now uses bandlimited wave tables for higher frequencies to avoid aliasing

now uses bandlimited wave tables for higher frequencies to avoid aliasing added rate interpolation to audio render functions so that modulated pitches change smoothly

can now talk to device over serial when device is displaying error screen

added device reset shortcuts for disk modes: holding d-pad left+lock+menu for four seconds resets to data disk, down+lock+menu resets to boot disk

moved LFO type constants from playdate.sound.lfo to playdate.sound

to replaced “Dave screwed up” error with more descriptive text :)

fixed crash on device when too many audio channels are running

fixed stack overflow when decoding really deep JSON tables

register values in crashlogs.txt are now (usually) accurate

Sleep is now much more efficient

fixed potential crasher when using pathfinding functions

Added workaround for trouble getting into disk mode when bootloader and main firmware is mismatched

pd->lua->getArgType() can now tell the difference between ints and floats

Changed

example now uses playdate.graphics.sprite.addWallSprites() , resulting in fewer overall sprites

, resulting in fewer overall sprites playdate.graphics.nineslice is no longer a subclass of Object

is no longer a subclass of Object Updated and restructured Inside Playdate documentation

playdate.simulator.writeToFile() now expands ~ in the image path

now expands ~ in the image path Improved playdate->lua->regiserClass() : you can now provide a list of constants as well as functions, and isstatic flag avoids creating a metatable for the class.

: you can now provide a list of constants as well as functions, and isstatic flag avoids creating a metatable for the class. Simulator “Upload Game to Device” now launches game on device after copying it over

Device now reboots into a crash screen instead of hanging with a white LED

Renamed API folder to C_API

Renamed playdate->system->currentTimeMillis() to playdate->system->getCurrentTimeMilliseconds() to match Lua API

to to match Lua API playdate.graphcs.setPattern() can now take its data as an 8 or 16 arguments [sic], as well as packed in a table

can now take its data as an 8 or 16 arguments [sic], as well as packed in a table Renamed playdate->graphics->getBitmapInfo() to playdate->graphics->getBitmapData()

My Two Cents

I’m more of a hobbyist when it comes to game development so there are better folks than me to comment on the SDK hinted at above. That said, I’ve spent some time with Unity and Löve2D so I’ll give you my amateur’s perspective. Hopefully that will be useful for some other amateurs.

Panic was obviously inspired by Löve, which makes sense as it’s one of the more popular, if not the most popular, ways to develop Lua games from scratch. (Lua itself is also an extremely popular supplement to other languages, but more on that later.) Based on the experiments I’ve done in Löve there are already some similarities — but importantly there are huge improvements. Lua, as a scripting language, is very approachable to newcomers; I listened to an interview with Neven Mrgan (Panic designer and member of the Playdate team) where he described it as not unlike Javascript, which I think is apt. Lua is an interpreted scripting language like JS, and possesses a similar level of forgiveness that a strongly typed language does not. (Which is a double edged sword no doubt, but finding that out over time is the fun part of becoming a developer!) Löve continues down this path by providing a library full of useful utilities that remove a lot of the grunt work of game development. For instance, I am working on a prototype for Playdate in Löve that involves generating bezier curves, and Löve has built-in functions for generating beziers and evaluating them. That’s a lot of high-level math I don’t need to worry about. However, unlike kitchen-sink platforms like Unity, there’s a lot that Löve simply does not provide out of the box. Things like dealing with tilemaps or serializing data so you can save it to disk are not always covered by the core Löve library. There is a robust community that provides excellent solutions to these problems, but it’s up to you, the (potentially new) developer, to find them and use them.

Looking at these release notes for Playdate SDK, my first major takeaway is that Panic is providing first-party solutions for basic game development problems and that is something to be excited about. Animators, sound APIs, sprite & tilemap handling, typography tools, saving to disk, pathfinding!? — it’s only version 0.6 and they are already providing so many utilities to the developer. As I’ve been toying with Löve, and as a beginner, I’ve been somewhat overwhelmed by the idea of needing to seek out solutions to these same problems. This is especially true coming from Unity where so much is provided to you. For instance, Unity has built-in GUIs for building animations, shaders, tile-based maps and so much more. Everything is Löve is based completely in code, with no GUIs to help you along. That said, Unity is overwhelming in different ways: it provides solutions to all these problems (and more), but they demand a familiarity with the Unity paradigm, which is simply not beginner-friendly. Panic might be striking a nice balance here between the flexibility and approachability of Löve and the first-party toolbox nature of a Unity or Unreal.

What really clinches it for me is the references to “classes” in this documentation. I’m not exactly sure how to interpret something like playdate->lua->regiserClass() but I really hope it’s some sort of object oriented programming (OOP) helper method. The thing with Lua and C (the other language you can use) is that they don’t have concepts of classes. If you’re coming from C++ or C# this can be… annoying. You can actually implement OOP in Lua, but it’s up to you to learn how to do that and then maintain it. I’m not saying it’s necessarily hard, it’s just not very friendly. It’s not very… Panic. So I have a hunch they might want to make this side of game development a little easier. You don’t need objects to make a game, but there’s a reason most modern languages include OOP concepts. Edit: Dave Hayden of Panic says that while technically possible, OOP features ended up being too slow on the device.

At the very least that method demonstrates another theme in the notes: good interplay between Lua and C. One of the points of Lua is that it’s supposed to be easy to use with other languages; it’s described as “embeddable.” So you might build your game engine in C++ but handle certain pieces of logic with Lua. (World of Warcraft does this I believe.) Or, in the case of Playdate, you might use Lua for scripting your UI and turn to C for an otherwise system-crushing rendering algorithm. I’ve never personally used Lua like that, so I can’t say what that experience is like — but regardless it’s nice to see that Playdate’s Lua and C APIs talk to each other. I see this as another example of how Panic is thinking through issues you’ll run into as a developer. Edit: Dave Hayden has a little more to say about this here.

I’m astounded that Panic has taken on the burden of developing and producing not only hardware, not only an operating system, but also an SDK for building things in that OS and on that hardware. Not only that, but the SDK is (potentially) going to be available to us in a matter of months? Amazing! Sure, the SDK will probably be rough around the edges when we get out hands on it, but the work is never done. I’m impressed by what I’ve seen so far and I have a lot of faith that Panic is going to do a good job with this.

Getting Started Now

One last thing I want to touch on in this section is what you can do now. I think Löve is the best place for most of us to start. It’s based in Lua and it seems to have a very similar API to what Panic is building. To make the eventual transition easier, I’d suggest abstracting away any Löve-specific code you might be using. In my own prototype work, I’ve set up a library of go-between methods that hide away the Löve methods. For instance:

itw.graphics.circle = function(mode, x, y, radius, segments) love.graphics.circle(mode, x, y, radius, segments) end

So, let’s say Panic provides their own circle drawing method. Now you only need to change your code in one place instead of one hundred. This sort of assumes the method signature won’t change much, but even if it does you can do the work of translation inside your custom method. I’m not sure if you can implement interfaces in Lua, but that would go a long way towards ensuring code you replace works the way your system expects.

In any case, do as much as you can to make it so it doesn’t matter if you are using love.graphics.foo() or playdate.graphics.foo() . There’s going to be things Panic does drastically differently, and functionality they won’t provide — but don’t let that stop you from getting started now. Use Löve as a jumping off point and just start thinking about what might need to be replaced later on. Of course, if you’re comfortable enough with Lua or C to write the whole game from scratch that would be safest — but then, this part isn’t really for you!

Oh! One last thing: one easy way to contribute right now is to take Panic’s developer survey.