Skip to content

Instantly share code, notes, and snippets.

@iiviigames
Created January 21, 2025 02:09
Show Gist options
  • Save iiviigames/4f04a9059ee37a2786965990cf0c6781 to your computer and use it in GitHub Desktop.
Save iiviigames/4f04a9059ee37a2786965990cf0c6781 to your computer and use it in GitHub Desktop.
Reddit Response - r/pico8 - January 20, 2024

I believe you are misunderstanding the concept of scope. This is a wide topic, but for your case, you are overwriting your PICO-8 global function _update with a second variable named the same thing.

Here's what is happening in the example:

  • A player can move and be shown
    • The only named variables are px, py, _update, _draw
  • When attempting to add new functionality of sprite appearing when a button is held, the game ceases to draw anything

Writing out your issue like this will be instrumental in solving bugs yourself. In the future, try to include a checklist like this to give us an idea of where your confusion lies, because, as you'll see, it could be many things.

TLDR
You are have misunderstood the order and use of the _update and _draw functions, resulting in an accidental overwriting of the behavior you desired.

This didn't throw an error, but can be traced by making using of the printh function.

Solution Online

Keep reading for a solution.

Part 1 - Examine the Working Code

  1. Initialize positions
  2. Check movement behavior
  3. Draw sprite at position
  • _update has already called, so the new values are used for the sprite's position
px=90
py=90

-- Update and update60 are global functions 
-- always called before draw when present
function _update()
 if btn(⬅️) then px-=1 end
 if btn(➡️) then px+=1 end

end

-- _draw is of lower priority when accompanied by
-- update functionality. 
function _draw()
 -- clear graphical buffer 
 cls()
 -- draw sprite #1 at screen position (px,py)
 spr(1,px,py)
end

Part 2 - Accidental Erasure

The order which Pico-8 performs its engine critical functions assuming all three are present is as follows:

  1. _init - Called a single time at game start.
  2. _update/_update60 - Always fires before draw when present
  3. _draw - Will be performed after any _update function logic, disregarding the order you have written them in
-- assuming the prior logic exists still 
function _update()
 -- the following line is telling pico-8
 -- to set the draw function to do nothing if
 -- and only if you press ❎

 -- if ❎ is pressed, the draw call is essentially 
 -- overwritten to contain nothing because of the 
 -- incorrect scoping and placement of the END keyword 
 if btn(❎) then function _draw end
  -- this will not fire because you are attempting to
  -- use a call from the graphical api while inside of
  -- an update function. this behavior is only accepted 
  -- by pico-8 when ONLY a update call is present or…
  -- (no graphical function calls allowed outside the 
  -- _draw function when _update also is defined)
  spr(22,px,py) end -- this end matches to _update as is
  
-- so this end is likely extraneous or something else
-- is going on you didn't include 
end

Part 3 - Learning and Fixing

So, I think there were some real basic problems that you can learn to avoid in the future by reading the manual carefully, and keeping the following in mind.

  • Update values before drawing values they are related to.
  • Ensure positional logic and graphical logic are well labeled.
  • If possible, use clear and consistent nomenclature so a complete stranger can understand what you meant. (This will save your skin so many times when you come back to old projects!)
px=90
py=90
-- we can use a boolean to communicate changes 
-- between update and draw calls
showsprite=false

-- our new function 
-- snum is a sprite to draw, ex. 22
-- xoff and yoff are offset distances from your player's position
--  ex 4, -2 would put it 4 pixels right, 2 pixels up
function x_action(snum,xoff,yoff)
 -- set default values to the arguments so they are optional
 snum = snum or 22
 xoff = xoff or 0
 yoff = yoff or 0

 -- only do the following when showsprite is true
 if showsprite then
  -- draw the sprite or whatever else is needed
  -- at the player's position plus the offsets
  spr(snum, px+xoff, py+yoff)
 
  -- anytime the ❎ button is pressed this code fires
  -- so to prevent an infinite loop we reset showsprite
  showsprite = false
 end
end

-- Update and update60 are global functions 
-- always called before draw when present
function _update()
 if btn(⬅️) then px-=1 end
 if btn(➡️) then px+=1 end
 -- when ❎ is pressed, toggle our boolean
 -- if you want it to have it on hold, use btn()
 if btnp(❎) then
  showsprite=true
 end
end

-- update this to check for our btnp logic
-- we'll make it tidy by using a new function
function _draw()
 -- clear graphical buffer 
 cls()
 -- draw sprite #1 at screen position (px,py)
 spr(1,px,py)
 -- perform any draw calls tied to input actions
 x_action()
end

PS: If I failed to address a concern, let me know and I'll get back to you.
PPS: You can't make code blocks bold on Reddit, but you can do this:

bold code
**`bold code`**

LOVE, 💌

iivii

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment