DEV Community

Cover image for Inspecting Rescues in Pulp
Robert Mion
Robert Mion

Posted on

Inspecting Rescues in Pulp

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.

Generic font

Sound

Three simple sounds: bounce, beep and ouch

Sounds in the game

Room

Aside from the title card, there's only one room: start.

Start room

It has no exits.

It has no items.

It has about 1/3 of the world tiles as Snakes.

World layer

It has two sprites: jumper and jumper ouch

Sprite tiles

It has two player tiles: player and player down

Player tile

player has a script attached to it.

Script

Player

There are five functions in the script attached to player.

Player scripts

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
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode
  • ra must be a property of the event 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
Enter fullscreen mode Exit fullscreen mode

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 and resetJumper
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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

It uses a handy round function:

jumper_speed = round jumper_speed
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

Next, jumper_frames is incremented. It is initially 0.

jumper_frames += 1
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode
on moveJumper do

Each of these four functions contains eight conditions:

  1. Move the jumper up or down by one and play the beep sound
  2. Move the jumper right by one
  3. Increment points by one when the jumper has made it as far right the player can move
  4. Update the direction of the jumper
  5. Update the direction of the jumper
  6. Update the direction of the jumper
  7. Handle when the player doesn't successfully rescue the jumper: increment misses, play a sound, update the jumper tile, reset the jumper
  8. 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 to emit?
  • 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 and cancel 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!

Top comments (0)