A fighting game for Playdate!

GRAB is a fighting game for the Playdate game console.
The Playdate uses a raw Lua & C SDK, as well as a wholly unique control layout including a crank. The console runs at a maximum of 50 fps, features a miniscule 16MB RAM, and uses a stateful ereader-like screen, that only consumes battery when changing pixels. The screen results in an SDK that behaves abnormally to most other rendering tech; as refreshing the entire screen every frame would destroy the console's tiny battery. The console also does not feature multiplayer of any kind, as its Wi-Fi chip is far too slow for even the simplest of online games.

All this to say, the console is challenging to develop for. Especially an online multiplayer fighting game for a console with no multiplayer.

Design, and Tech

To my knowledge, GRAB is the first original fighting game for Playdate, and this comes with many unique challenges.

For its online multiplayer, GRAB relies on a reverse-engineering of the console's USB interface. Playdate does not allow connecting two consoles by USB, but it does allow connecting a console to a web browser! Using this, we can connect the game to a website that handles all communication through websockets. You can read more about this solution here. I am working on a solution to allow the Playdate Simulator to interface over USB with this technology, as well as integrating it with rollback-based reconciliation techniques.

This behaviour is officially unsupported by the console's creators, and the install base is very small regardless, so GRAB is also designed to cater to singleplayer audiences first and foremost, featuring a singleplayer campaign involving AI controlled opponents.

A sketch of the AI opponent's state machine on a whiteboard, color coded by node.
First draft of the AI opponent's state machine on a whiteboard, color coded by node type.

The actual behavior tree, in a custom editor that exports Lua code.
The actual behavior tree, in a custom editor that exports Lua code.

A code snippet, showing the actual code implementation of one of the behaviour tree's end states.
A code snippet, showing the actual code implementation of one of the behaviour tree's end states. The state modifies its actor's input state to perform actions.

GRAB's AI is behaviour tree based. The tree itself is designed using modern strategies. Instead of simply picking the most optimal choice, the tree is designed "emotionally." The actor uses rough metrics of the game state to determine its "confidence," which determines how aggressively or cowardly the actor behaves. At low confidence values, the actor will even "panic." This gives the actor a sense of personality and nondeterminism, and the player a sense that the actor is intelligent and making decisions in the way a player would. State is sampled from a few frames in the past and adjusted based on player trajectories; this simulates a human reaction time and eliminates "input reading" behaviour.

I took GRAB to a major convention in August 2024, and used it to playtest this AI against real players. The AI was strong, and didn't lose often, but most players felt it was a fair challenge and had few complaints. Thanks to Playdate SDK's quick build times, I was able to iterate on what issues I did see and test new builds on the spot. I'm still fine tuning the AI to be a bit easier; my game presents challenges that my target demographic will not have seen before, so I want to ease them in a bit gentler. The NAIR games are first and foremost about teaching transferable skills.