Robert Mion
Posted on January 17, 2023
In a previous article I downloaded 21 games.
Two of those games made their JSON
files available for download, too.
That means:
- Their game was built in Pulp
- I can import the file to inspect all of their game assets
In the last article I inspected one game, Snakes.
In this article, I'll inspect the other, Rescues.
Inspecting Rescues
I'll study each view carefully.
Font
Looks like a simple sans-serif font.
Sound
Three simple sounds: bounce, beep and ouch
Room
Aside from the title card, there's only one room: start
.
It has no exits.
It has no items.
It has about 1/3 of the world tiles as Snakes.
It has two sprites: jumper
and jumper ouch
It has two player tiles: player
and player down
player
has a script attached to it.
Script
Player
There are five functions in the script attached to player
.
I've seen cancel
, confirm
and update
.
crank
and draw
are new to me.
Revelation: confirm
and cancel
functions
In Rescues, you can only move two people and a stretcher left or right.
You can use:
- The left and right d-pad buttons
- The B and A buttons
- The crank
How the map to movement:
- D-pad right performs the same action as A
- D-pad left performs the same action as B
- Crank one way performs the same action as D-pad right
- Crank the other way performs the same action as D-pad left
I most menu screens, A is used to continue or confirm
a prompt; B is used to go back or cancel
a prompt.
It seems here that the game developer has hooked into the event listeners for the A and B buttons to perform the same movement logic as in the event listener for update
, which I assume fires any time an button was pressed.
In each of the on confirm do
and on cancel do
functions, the developer knows which button was pressed.
In the on update do
function, the developer does a check of whether event.dx
is 1
or -1
- seemingly to check for left or right movement.
In the on crank do
function after a few lines that store values in variables, the developer updates the player's position based on whether a value is greater than or equal to a number...or less than or equal to a different number.
I assume those conditions determine which direction the crank was rotated.
on draw do
label "{points}" at 13,0
label "MISS" at 18,0
if misses>=1 then
draw "miss" at 21,1
end
if misses>=2 then
draw "miss" at 20,1
end
if misses>=3 then
draw "miss" at 19,1
end
-
label ... at X,Y
is new - Having played the game and seeing the use of coordinates, it seems this sets text from left-to-right starting at the given coordinate
-
misses
must be initialized somewhere else in this or another script - It's odd that this logic moves some
miss
thing one more unit to the left depending on whether it is greater than 1, 2 or 3 - Wait, nevermind. Playing showed me that
miss
is a tile representing a missed rescue. Each miss gives a strike, drawn from right-to-left. It makes sense now.
The next series of commands place specific tiles at specific positions in the room.
on update do
, on confirm do
, on cancel do
As mentioned earlier:
- The main logic in each one consists of three clauses
- Each clause checks which of the four possibly-occupied spots the player was in, and moves the player and both guys to the correct - or only - adjacent spot
on crank do
The beginning of this event's code contains four statements:
crankRot += event.ra
sensitivity = 70
sensNeg = sensitivity
sensNeg *= -1
-
ra
must be a property of theevent
object pertaining to the crank's state - The developer must need negative and positive versions of a value, hence the duplication and changing of sign
The next two conditions are:
if crankRot>=sensitivity then
elseif crankRot<=sensNeg then
Interesting. One checks for a number greater than 70. The other for a number less than -70.
Game
This script is almost 500 lines long!
At first glance it seems complicated and a bit redundant.
After analyzing a bit, I understand the redundancy:
- The game features four jumpers at its most difficult stage
- This script is responsible for managing the state of - and resetting - each jumper: via functions labeled
moveJumper
andresetJumper
on load do
Surprisingly this function does only three things, and two of them are given helpful context by the developer
on load do
// first time playing the game, this needs to be 0
has_played = 0
// if the game has been played, this will set has_played to 1
restore
call "init"
end
I assume this information is found in the documentation for Pulp or PulpScript. Still, I'm glad this developer reiterated it.
on init do
This function creates and sets the values of a slew of variables.
It makes use of event.px
and event.py
.
It uses strings that don't seem to reference tiles:
jumper1_y_direction = "down"
jumper1_x_direction = "straight"
It uses a handy round
function:
jumper_speed = round jumper_speed
on loop do
More use of the name
function to seemingly set a string from two values and store them as the value of another variable:
tile_name1 = name jumper1_x,jumper1_y
tile_name2 = name jumper2_x,jumper2_y
tile_name3 = name jumper3_x,jumper3_y
tile_name4 = name jumper4_x,jumper4_y
Next, jumper_frames
is incremented. It is initially 0
.
jumper_frames += 1
Then, a nested set of conditions to determine which of the four jumpers to move.
if jumper_frames==jumper_speed then
call "moveJumper1"
if points>9 then
call "moveJumper2"
end
if points>22 then
call "moveJumper3"
end
if points>67 then
call "moveJumper4"
end
jumper_frames = 1
end
I'm not exactly sure how the outer-most condition works.
But it seems like new jumpers are only introduced once a point threshold is reached.
Next, three other functions are invoked.
call "checkForMatches"
call "checkForMisses"
call "increaseSpeed"
Time to inspect each of those functions!
on checkForMatches do
This function seems to account for two jumpers being at the same height on their descent by adjusting one jumper's height by one to ensure the player can rescue each one with a fast enough movement.
Each of the six conditions has this structure:
if jumper1_y_direction=="down" then
if jumper2_y_direction=="down" then
if jumper1_y==jumper2_y then
sameY_1 = 1
else
sameY_1 = 0
end
end
end
on checkForMisses do
This function checks whether the player has accrued three misses and, if so, displays the end-game screen which shows their high score: the greater number between the score this round and the largest number from all previous rounds.
on checkForMisses do
if misses==3 then
if has_played==0 then
high_score = points
else
if points>high_score then
high_score = points
else
high_score = high_score
end
end
wait 2 then
fin "HI SCORE: {high_score}"
end
end
end
on increaseSpeed do
Thanks to the comment, this function increases the speed after 30 points are accrued.
on increaseSpeed do
if points>30 then
jumper_speed_per_second = 2
end
end
on finish do
Lastly, the high score is saved and the game is marked as having been played.
on finish do
store "high_score"
has_played = 1
store "has_played"
end
on moveJumper do
Each of these four functions contains eight conditions:
- Move the jumper up or down by one and play the
beep
sound - Move the jumper right by one
- Increment
points
by one when the jumper has made it as far right the player can move - Update the direction of the jumper
- Update the direction of the jumper
- Update the direction of the jumper
- Handle when the player doesn't successfully rescue the jumper: increment
misses
, play a sound, update the jumper tile, reset the jumper - Get a point when jumper reaches the ambulance
on resetJumper do
Set four values that control the position of the jumper and which direction it moves in.
Keywords and syntax learned
-
restore
- or what it does, at least event.ra
round
-
call
as an alternative toemit
? shake
tell ... to
-
label ... at X,Y
to display text in the UI -
{...}
in a string as text interpolation -
draw ... at X,Y
to replace a tile with another by name -
variable,variable
to be evaluated as numbers when drawing a tile -
goto
as a way to move the player to a new position - Why events like
confirm
andcancel
are useful during gameplay
Before jumping away
- I'm glad this game was vastly different than Snakes
- It revealed even more of Playdate's (or PulpScript's?) APIs
- It made me recognize that I should strive for little or no redundancy in my code, but sometimes it may be unavoidable...and that's ok as long as the game works as intended
What next?
- Hunt for more
JSON
files so I can inspect other developers' Pulp games? - Try building a rudimentary game in Pulp that allows me to practice all these new keywords and syntax I've learned?
- Start reading the official PulpScript documentation?
- Try following one of the tutorials linked to by Playdate?
No matter what I choose, I'm sure it will help me become more comfortable and familiar with building games for Playdate!
Posted on January 17, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.