This is the full code for a playable, pacman-style game in R.
The game plays in realtime using 2 key packages:
{nara}
for manipulation of nativeRaster images as a fast in-memory drawing canvas{eventloop}
for event-driven interaction - allowing for keyboard feedback while rendering the game with sound.
The aim of this pacman-style game is to eat all 288 dots before you lose your 5 pacman lives.
- Run game with
source('game.R')
- Control pacman with arrow keys (or WASD).
- Score 10 points for each dot consume.
- Lose 100 points for every collision with a ghost.
- Maximum possible score: 2880 for consume all dots and never colliding with a ghost.
- There are no power-ups. Ghosts cannot die. Every collision with a ghost will take one of your lives.
- Install the dependencies
- Retrieve the pacman game code from github
- Note that this is not a package, but just a collection of R scripts and code. This should make it easier to hack on, extend and adapt.
library(remotes)
# Packages required for interactive rendering
remotes::install_github("coolbutuseless/eventloop")
remotes::install_github("coolbutuseless/nara")
install.packages('audio')
# Grab a copy of the pacman game code by cloning the repository
system("git clone https://github.com/coolbutuseless/pacman.git")
# Change into the source code directory and run
setwd('pacman')
source('game.R')
macOS
Running this on macOS requires XQuartz to have been
installed in order to support the x11()
device.
Linux
R needs to have been compiled with x11()
and Cairo support.
The WindowsOS version of R does not currently have support for the onIdle
callback and
therefore does not support event-driven interactive graphics as implemented
in the {eventloop}
package.
If you are a windows developor capable of adding support for an onIdle
callback
to R itself, please get in touch!
The cursor icon in an {eventloop}
window will flicker because of some hard-coded
behaviour in R's double-buffered x11()
graphics device.
{eventloop}
makes use of the x11()
graphics device with a double-buffered
backend based on Cairo (x11(type = 'dbcairo')
).
The double-buffering within the graphics device is coordinated through use
of dev.hold()
and dev.flush()
calls.
Whenever dev.hold()
is called, the cursor will be set to the busy cursor
(usually a stopwatch on macOS), and when dev.flush()
is called the
cursor reverts to a normal pointer arrow.
Since dev.hold()
and dev.flush()
are called when drawing every single
frame, the cursor will flicker between these two images.
The interim solution is to not have the cursor over the window when interacting with the app. This only really works when the app solely relies on keyboard feedback (like this pacman game).
The more complicated solution will involve crafting a patch to R itself to make the cursor change behaviour user-configurable rather than hard-coded.
If you are are an R developer capable of crafting such a patch to R , please get in touch with me!