Completing two Pulp tutorials

rmion

Robert Mion

Posted on January 25, 2023

Completing two Pulp tutorials

Playdate's developer site has a list of links on several topics.

One such section features links to tutorials on Pulp.

Three are youtube videos, two of which are by user SquidGodDev.

The rest are articles on Playdate's developer forum.

I intend to work my way top to bottom.

In this article, I work through both of SquidGodDev's tutorials.

PulpScript: A Beginner's Guide

This is the first video I will watch and code along with in Pulp:

Sections in the video:

  • Scripts
  • Event handlers
  • Variables
  • Conditionals
  • Functions
  • Event variable

PulpScript snippets:

on any do
  if keys==1 then
    // do something
  end
end
Enter fullscreen mode Exit fullscreen mode
on enter do
  say "You entered a new room!"
end
Enter fullscreen mode Exit fullscreen mode
on load do
  health = 10
  maxHealth = 15
end
Enter fullscreen mode Exit fullscreen mode
on draw do
  label "Health: {health}" at 0,0
end
Enter fullscreen mode Exit fullscreen mode
on interact do
  health += 1
  health++
  health--
  if health > maxHealth then
    health = maxHealth
  end
  if health <= 0 then
    health = 0
    fin "You died..."
  end
end
Enter fullscreen mode Exit fullscreen mode
on collect do
  teleportX = event.x
  teleportY = event.y
  teleportX += 5
  goto teleportX,teleportY
  sound "teleport"
end
Enter fullscreen mode Exit fullscreen mode

Impressions

  • This video - like many other tutorials on Youtube - was cut together to present information at a rapid pace
  • That made it difficult to fully absorb all of what was being taught without having to pause and rewind
  • I learned how swapping tiles is pertinent
  • I learned how easy it is to place text on the screen

I'm excited to watch the next video and make a simple game

Make an Adventure Game for the Playdate with Pulp

This is the second video I'll watch and code along with in Pulp:

Intro

  • The first 25 seconds make me very excited to follow along and complete this whole tutorial
  • I imagine I'll be doing a lot of pausing and rewinding, given this editor's tendency for sharp cuts

Making a Door

  • From Room mode, make a new World tile called wall
  • Update the pixels to match what the author drew
  • Toggle the option to make this a wall tile
  • Paint the room with both white and wall tiles such that all tiles are white except the border tiles, which are wall tiles
  • Delete the only exit tile in the current room
  • Create a new Sprite tile called gate
  • Update the pixels to match what the author drew
  • Add the sprite to the room at the indicated position
  • Create two additional World tiles that are each slight variants on the wall tile
  • Paint an enclosed area in the room using the three World tiles
  • Create a new Item tile called key
  • Update the pixels to match what the author drew
  • Add a Behavior script to the gate sprite
  • Go to the Script mode and select gate
  • Write an on interact do event listener that checks the value of keys and performs a tile swap if it is 1 or alerts the player to collect a necessary key otherwise

Displaying the number of keys

  • Create a new World tile called keysicon
  • Update the pixels to match what the author drew
  • Toggle the option to make this a wall tile
  • Go to the Script mode and select player
  • Write an on draw do event listener that updates the top-right tiles such that the left-most tile is the keysicon tile and the right-most tile is black and then the amount of keys collected by the player

Health system

  • Write an on load do event listener in the player script, setting max health and health variables
  • Create three Sprite tiles for each of the heart UI states: full, half, empty

Drawing the hearts in the UI

Clever: a loop that draws one heart for every two health.

There's some counting by 2 and by 1 to account for number of hearts and placement in the UI.

  • Initialize two variables to track current heart and static Y position
  • Store the desired tile name in a variable
  • Set the current heart to half of the total possible hearts
  • Swap the tile at the desired position with the desired tile
  • Update the current heart variable

Draw the correct hearts in the UI

Some additional conditionals are needed to account for the half-hearts.

This took a few pause-rewind-think-play loops for me, but I think I get it now.

  • Set a variable equal to the current health
  • Check whether the variable is greater than the current heart being drawn
  • If it does, decrement it by one, then check if it is now equal to the current heart
  • If it is, queue up the half heart
  • Otherwise, queue up the full heart
  • If it wasn't greater to begin with, proceed with the empty heart

Spikes

Form and Function

  • Create a new Item tile called spikeOut
  • Update the pixels to match what the author drew
  • Create a new Item tile called spikeIn
  • Update the pixels to match what the author drew
  • Go to the Script mode and the game script
  • Delete the contents of the script
  • Write an on loop do event listener that emits a yet-to-be-written function each time a certain amount of frames have passed
  • The dependencies of the conditional are: event.frames, an interval, a division and rounding operation, and a check for equality
  • The interval is then separated into an on load do event listener and used in the loop event listener
  • Set the behaviors for both spike tiles to script
  • In each script write a custom on spikeUpdate do event listener that swaps one tile for the other

Spike Damage

  • Amend the spikeUpdate function in the spikeOut script
  • Add nested conditionals to check whether the player is on a spikeOut tile
  • Decrement health by 1

But wait...there's a better, far more complicated approach?

Better writing it, I notice that health is only decremented when the tiles are swapped from spikeIn to spikeOut.

If the player moves onto a spikeOut tile, no damage is dealt.

Turns out that the better, more complicated approach accounts for this mistake:

  • In the script for the recessed, non-damaging spike tile
  • Instead of decrementing health by one...
  • A copy of spikeDamage is made - saved as damage - as a way to future-proof this algorithm for other items that may damage the player
  • A yet-to-be-written custom event called damagePlayer is called only on the Player
  • That event just decrements health by damage
  • Also in the Player script, write an on update do event listener that emits - thereby calling some function on every tile that listens for that function - a custom function called playerUpdated
  • In the script for the raised, damaging spike tile, that event is written and inside it is the exact same code inside the spikeUpdated function in the spikeIn tile

The way all of this seems to work is:

  • Whenever the non-damaging spike tile updates...
  • Check if the player is on that type of spike tile...
  • And decrement health by the value stored in damage, because it just changed to the damaging spike tile
  • Also, whenever the player moves...
  • Check if the player is on a damaging spike tile...
  • And decrement health by the value stored in damage

I think I understand it all.

Though I'm not confident I could write it all from scratch yet.

Still, it's great that it appears to add the expected behavior to the spikes and the player and the health!

Moving Hazards

This is a long section. I wondered why. So I watched it all first.

Answer: because simulating an item moving requires

  • Four tiles
  • Conditionals
  • Direction
  • Tile swapping
  • Code duplication

By the end, the items move up-down and left-right against any wall items, and unfortunately merge into a single item when two of them collide.

Time to study the code!

  • Created four identical tiles, named per their direction of initial movement, and set their behavior to Script
  • New variables in the load event to track timing and damage amount
  • Duplicated the code in the loop event, adjusting for the new interval and event emitted
  • In the new custom event - being written first in the downward moving spike tile - the event object's x and y members are used to capture the position of the next tile and swap two tiles: current tile for white and next tile for current tile...simulating downward movement
  • Bug: the spike never moves upward!
  • Use of the solid function helps determine the type of the next tile
  • Check whether the type is solid - is it 1? - and if so adjust the tile name and the position at which to swap
  • Duplicate the player collision detection code, adjusting variables where necessary
  • Add a playerUpdated function and duplicate the same player collision detection code
  • Duplicate all of the above code for the three other tile directions

I play tested a bit between each code addition to confirm the spikes moved as expected.

Then I added some spikes and walls and play tested to confirm the player takes damage when colliding with the spikes.

Everything appears to work!

Screen Shake

  • A simple one-line update, thanks to the use of the custom player function

Sound Effects

This section is difficult to follow due to the speed of the author's video cuts and the small font size of the UI.

I'll try my best to re-create what is being setup.

Creating the sounds

  • move: success
  • hurt: mostly a success, though I feel like my sound lasts longer
  • key: success
  • doorOpen: success
  • spikeOut: success
  • spikeIn: success
  • spikeBallBounce: success

Scripting the sounds

  • move: success
  • hurt: mostly a success, though I feel like my sound lasts longer
  • key: success
  • doorOpen: success
  • spikeOut: success
  • spikeIn: success
  • spikeBallBounce: success x4

Play testing confirms the sounds work as expected!

Final Touches

Exits

  • First I tried a one-way connection
  • Then connecting rooms

I realized I needed another key to open the gate to the new room.

I put the key in a spot that a spike would interact with.

This made the key disappear.

I tried troubleshooting:

  • Adding a conditional in the key's collect event handler that made it disappear only when the player interacts with it

Sadly, the spike overrides this by swapping the tile to which it is adjacent.

For now, this is still an issue: I can't place a key in the line of a spike.

Fin

  • I added a Fin exit
  • And created a flag to signify it
  • Then, added a health-based ending for 0 health

Conclusion

  • The author alludes to several fun ways to improve upon the game
  • All of them seem like great exercises to further practice what I learned here

This video tutorial turned out to be a fantastic exercise in applying much of what I learned by reading the Docs and inspecting other games' code.

Other tutorials, here I come!

💖 💪 🙅 🚩
rmion
Robert Mion

Posted on January 25, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Completing two Pulp tutorials
gamedev Completing two Pulp tutorials

January 25, 2023

Inspecting Rescues in Pulp
gamedev Inspecting Rescues in Pulp

January 17, 2023

Reading the PulpScript Docs
gamedev Reading the PulpScript Docs

January 21, 2023