PICO-8



Basic Sprite



Follow along with the video to learn basic sprite coding!


The video moves quickly so pause whenever you need.

The video doesn't explain everything, but this page does!


Use this page and lesson as a reference for customizing the movement physics in your games.

Movement Physics!

  • Simple Movement


      You can copy this code into PICO-8 to try it out. But you also have to draw something in the sprite editor for sprite #1 (the second tile).


      function _init()
          player_x=63
          player_y=63
          speed=1
      end
      
      function _update()
          if (btn(0)) then player_x-=speed end -- left
          if (btn(1)) then player_x+=speed end -- right
          if (btn(2)) then player_y-=speed end -- up
          if (btn(3)) then player_y+=speed end -- down
      end
      
      function _draw()
          cls()
          spr(1,player_x,player_y)
      end

      So this is the simplest code to control a player character's movement in all four directions. We first set the player in the middle of the screen with the variables in the _init() function. Then we check for buttons being pressed inside _update() and depending on the button, we just add or subtract 1 from the player's X or Y position. Then we just clear the screen and draw the player's sprite at its new position.


      How does this work?


      player_x is the number of pixels from the left that the player will start at.


      player_y is the number of pixels from the top that the player will start at.



      Everything that has a position on the game screen, uses X and Y coordinates. Changing the X coordinate will move the position left or right. Changing the Y coordinate will move the position up or down.



      Move Left: check if button zero is pressed, then subtract from the player's X position.

      if (btn(0)) then player_x-=1 end


      Move Right: check if button one is pressed, then add to the player's X position.

      if (btn(1)) then player_x+=1 end


      Move Up: check if button two is pressed, then subtract from the player's Y position.

      if (btn(2)) then player_y-=1 end


      Move Down: check if button three is pressed, then add to the player's Y position.

      if (btn(3)) then player_y+=1 end


      Changing the speed number will basically change how many pixels the player moves each frame. Here is what it looks like when speed=1 so that 1 pixel is added to X each frame to move right:






  • Tinker with Platformer Physics!



  • Advanced Movement


      This code is much more complicated than simple movement above. But it creates much more realistic and natural movement in the player. You may copy this code to test it out in PICO-8, but you will need to draw something in sprite #1 (the second tile).


      function _init()
          player={
              x=59,
              y=59,
              dx=0,
              dy=0,
              max_dx=2,
              max_dy=3,
              acc=0.5,
              boost=4,
          }
      
          gravity=0.3
          friction=0.85
      end
      
      function _update()
          player.dy+=gravity
          player.dx*=friction
      
          --controls
          if (btn(0)) then player.dx-=player.acc end -- left
          if (btn(1)) then player.dx+=player.acc end -- right
          if (btnp(5)) then player.dy-=player.boost end -- X
      
          --limit left/right speed
          player.dx=mid(-player.max_dx,player.dx,player.max_dx)
          --limit fall speed
          if (player.dy>0) then
              player.dy=mid(-player.max_dy,player.dy,player.max_dy)
          end
      
          --apply dx and dy to player position
          player.x+=player.dx
          player.y+=player.dy
      
          --simple ground collision
          if (player.y>110) then player.y=110 player.dy=0 end
      
          --if run off screen warp to other side
          if (player.x>128) then player.x=-8 end
          if (player.x<-8) then player.x=128 end
      end
      
      function _draw()
          cls()
          spr(1,player.x,player.y)
      
          --ground
          rectfill(0,118,127,127,13)
      
          --display info
          print("dx= "..player.dx)
          print("dy= "..player.dy)
      end

      Try changing the variables in the game while reading below to experience how they affect the movement.



      How does this work?


      Similar to Simple Movement, we have player variables for X and Y position, but we put them inside a table named player. So to access the values of the variables that are in the table, we use the table name, then a dot (.), then the variable name. Note that when variables are inside a table, the variable name actually becomes a "key". So that's the proper term, but it's alright to still think of them as variables. Learn more about tables here:

      What are tables, keys, and values?


      player.x is the number of pixels from the left that the player will start at.


      player.y is the number of pixels from the top that the player will start at.




      player.dx is the number of pixels that the player will move either left or right. If dx is a positive number, then the player will move to the right. If dx is a negative number, then the player will move to the left.


      player.dy is the number of pixels that the player will move either up or down. If dy is a positive number, then the player will move down. If dy is a negative number, then the player will move up.



      In Simple Movement, the number of pixels the player moves each frame is fixed (never changes). Which also means that the player's speed never changes.

      But in Advanced Movement, we have turned that fixed number into variables dx and dy so that we can change them to make the player move at different speeds.

      We will use this to create a build up of speed when the player starts moving and a slow down before the players stops.


      Here is an example showing how a positive DX increases over time to slowly build up the speed of the player moving right:



      NOTE: Changing the dx and dy in _init() will have no effect in the game, because they are constantly updated during the game based on acc (acceleration) and boost (jump power)



      player.max_dx is the limit of how many pixels we want to allow the player to move left or right each frame.

      player.max_dy is the limit of how many pixels we want to allow the player to move up or down each frame.


      So we build up speed with dx or dy then don't let it go past max_dx or max_dy

      NOTE: we only limit the dy when falling, so that the jump power (boost) can be a high number to create a sudden launch of the jump before gravity pulls the player back down. Also note that we are not limiting the number of times the player is allowed to jump, which allows for double or more jumps in the air and that creates an effect like Flappy Bird.





      player.acc (short for acceleration) is how much DX will change when the player pushes the left or right buttons.

      Changing this variable will change how fast or slow the player builds up speed. Balance this with friction.



      player.boost (jump power) is how much DY will suddenly decrease (making the player position higher) when the player pushes the jump button.

      Changing this variable will change how high the player can jump. Balance this with gravity.





      gravity (the force that constantly pulls "down") is how much DY will be increased every frame.

      Changing this variable will change how strong the player is pulled downward. Balance this with boost.



      friction (the force that slows moving things down) is how much DX will be shortened every frame.



      To really understand the math we use with friction, you should have a solid understanding of positive and negative numbers, and multiplying or dividing by decimals (or fractions).

      In this example, friction=0.85, so that is a decimal and less than 1. And let's imagine the player runs to the right to build up the dx to 3. Then when the player stops pushing the right button, what will happen is friction will be multiplied to the DX and here is what the math looks like for each frame that this happens:

      FrameOld DX * FrictionNew DX
      13 * 0.852.55
      22.55 * 0.852.16
      32.16 * 0.851.84
      41.84 * 0.851.56
      51.56 * 0.851.33
      61.33 * 0.851.13

      Changing the friction variable will change how much resistance is against the player moving left and right.

      However, because we are multiplying by a decimal between 0 and 1, a high decimal number means lower friction.

      A High friction decimal means that the player will quickly speed up and slowly slow down.

      A Low friction decimal means that the player will slowly speed up and quickly slow down.

      Balance this with acc.



      So overall, when you are playing with and deciding the physics of your player movement, here is what you should be considering:

      ProblemSolution
      Player is too slow.Increase acc
      or decrease friction
      or increase max_dx
      Player is too fast.Increase friction
      or decrease acc
      or decrease max_dx
      Player barely jumps.Increase boost
      or decrease gravity
      Player jumps too high.Increase gravity
      or decrease boost
      Player falls too slow.Increase gravity
      or increase max_dy
      Player falls too fast.Decrease gravity
      or decrease max_dy






font