pico-8 logo

PICO-8



Animate a Sprite

animate sprite pico-8 cart

Follow along to learn easy sprite animation!


In making this demo, we learn about drawing sprites, using coordinates X and Y, and decimals.


This lesson focuses on ANIMATION!




Challenges!

After following the lesson, take on some of these challenges to test your knowledge and skills!

1. Change the sprite to a different character!

2. Make the sprite move on the Y axis.

3. Instead of warping the sprite back to the left side, make him flip around and jump the other way.

How to animate a sprite!


[ Video Coming Soon! ]


Explanation of Code!


  • 1. Draw your Sprites

      What is a sprite?

      Here are the sprites we use in this example animation cartridge.

      pixelart soldier sprites

      You can copy these sprites or make your own! Make sure you draw each of these sprites in the exact same place, because the code will look for their sprite number. But once you understand the code, you can draw as many sprites as you want, where ever you want!


      This is where you will want to draw your sprites in the PICO-8 sprite editor.

      pico-8 spritesheet

      (We try not to draw in the very first space (Sprite #0) because that is a default empty tile when using the map editor.)



      pixelart icon


  • 2. Set up the Variables

      What is a variable?

      The first code we write at the top of the file are the variables. These help us set up the game and keep track of data.

      When variables are set outside of any function, that means that they will be set before anything even starts running in the game. And that means any code written after these variables will be able to find and use them.

      If you are using the _init() function, then that would be a good place to put these variables for each game object that you want to animate. Or if you are using tables to organize your game objects then these variables can be inside of the objects' tables. There is an example of that at the end of this page.

      sprite = 1
      x = -8
      y = 59
      timing = 0.25
      

      The first variable is named sprite. Then the equals sign tells the game to remember it with whatever we write next. sprite holds a number and that number is the sprite-number of the first sprite in the sprite sheet.


      What is a sprite?

      The next variables are named x and y. Together these tell the game where the sprite is on the screen.

      pico-8 screen position

      x = -8 and y = 59 because the screen has 128 pixels from left-to-right and top-to-bottom (# 0-127). The X is where the sprite will start on the X-axis (horizontally) and -8 will be just to the left of the visible screen. The Y is where the sprite will start on the Y-axis (vertically) and 59 places the sprite in the middle of the screen.

      pico-8 sprite position

      The next set of variables are for keeping track of the animation timing.

      timing = 0.25

      timing is for setting a delay time between each animation (sprite change).



      pixelart icon


  • 3. Draw the Sprite

      function _draw()
        cls()
      
        spr(sprite, x, y)
      
        print(sprite)
      end

      _draw() runs after _update and draws to the game screen 30 times every second.

      cls() clears the game screen.

      spr() draws a sprite at X and Y coordinates on the screen.

      spr(sprite, x, y) tells the SPR function to draw the sprite number at the X and Y variables we set above.


      print(sprite) will write the sprite variable to the screen. It will show as the number as it counts up by timing so you can see how fast the animation is happening.



      pixelart icon


  • 4. Update the Animation

      function _update()
          --animate
          sprite += timing
          if sprite > 4 then sprite = 1 end
      
          --move
          x += 1
          if x > 127 then x = -8 end
      end

      The function _update() makes changes to the game 30 times every second.

      You can also use _update60() to double that speed to 60 times per second. But if you choose to do that, then the animation will move twice as fast, so you should cut the timing variable in half.


      The first thing we will update is the sprite number to create the animation.

      sprite += timing increases the sprite-number by the number you set in the timing variable.


      Why should timing be a decimal between 0 and 1.

      Because the very next sprite is 1 sprite number away but if we add 1 every time _update() runs, then we will be changing the sprite way too fast. And obviously, if we add 0, then the sprite number will never change. So it has to be a decimal between those two.

      Let's say we use 0.5 for our timing number. That means 30 times a second (every time _update runs) the sprite number will increase halfway towards the next sprite. And that means instead of changing the sprite 30 times every second, it will change the sprite 15 times every second. That is how we are controlling the timing with this number.

      So play around with this number to get the animation timing how you'd like it. The closer to 0 you make it will slow down the animation. The closer to 1 you make it will speed up the animation.


      To make this work, you must draw your sprites next to each other in a row and slightly change each drawing, and that will create the look of one character being animated.


      Now that we are increasing the sprite number, what happens when it gets to the end of our character's sprites?

      Well that means we need to restart the animation loop. So let's check when the sprite number gets to the end, and reset it to the start. It's as simple as this one line of code:

      if sprite > 4 then sprite = 1 end

      pixelart sprite animation loop

      pixelart icon


      The next thing we will update about this sprite animation is the position.

      x += 1 will increase the X position by 1 pixel, making the sprite drawn 1 pixel to the right.


      if x > 127 then x = -8 end will check if the sprite moved too far to the right and off the screen. And if that happens, then x = -8 will reset the sprite's X position to where it started.

      Together, this code will simply start the sprite on the far left, make it move to the right, and then warp it back to the left side to infinitely walk across the screen.

      pico-8 sprite position start

      pixelart icon


  • Full Code!

      sprite = 1
      x = -8
      y = 59
      timing = 0.25
      
      function _draw()
          cls()
      
          spr(sprite, x, y)
      
          print(sprite)
      end
      
      function _update()
          --animate
          sprite += timing
          if sprite > 4 then sprite = 1 end
      
          --move
          x += 1
          if x > 127 then x = -8 end
      end
      

      RUN!

      gif pico-8 sprite animation

  • pixelart icon
  • Controlling Multiple Animations

      Warning: If you are new to coding, this may look complicated. It uses tables to organize all of the different game objects. So if you have not used tables before, we suggest reading about tables in our Guide to help understand this.


      What's up with tables?
      function _init()
          --create a table for player data
          player = {
              sprite = 1,
              x = -8,
              y = 59,
              timing = 0.25,
          }
      
          --create a table for enemies data
          enemies = {}
          --set enemy sprites, positions, and timing
          enemy1 = { sprite=5 , x = -20, y = 5, timing = 0.1, speed = 1.25, first = 5, last = 9 }
          enemy2 = { sprite=9 , x = -14, y = 30, timing = 0.2, speed = 0.4, first = 9, last = 13 }
          enemy3 = { sprite=13 , x = -11, y = 90, timing = 0.4, speed = 0.75, first = 13, last = 17 }
          --add each enemy to enemies table
          add(enemies,enemy1)
          add(enemies,enemy2)
          add(enemies,enemy3)
      
          --create a table for items data
          items = {}
          --set items sprites, positions, and timing
          item1 = { sprite=48 , x = 30, y = 110, timing = 0.3, first = 48, last = 56 }
          item2 = { sprite=56 , x = 60, y = 110, timing = 0.25, first = 56, last = 60 }
          item3 = { sprite=60 , x = 90, y = 110, timing = 0.15, first = 60, last = 64 }
          --add each enemy to enemies table
          add(items,item1)
          add(items,item2)
          add(items,item3)
      end
      
      function _draw()
          cls()
      
          --draw player
          spr(player.sprite, player.x, player.y)
      
          --draw enemies
          for enemy in all(enemies) do
              spr(enemy.sprite, enemy.x, enemy.y)
          end
      
          --draw items
          for item in all(items) do
              spr(item.sprite, item.x, item.y)
          end
      
      end
      
      function _update()
          --animate player
          player.sprite += player.timing
          if player.sprite >= 5 then player.sprite = 1 end
          --move player
          player.x+=1
          if player.x > 127 then player.x=-8 end
      
          --enemies
          for enemy in all(enemies) do
              --animate
              enemy.sprite += enemy.timing
              if enemy.sprite >= enemy.last then enemy.sprite = enemy.first end
              --move
              enemy.x += enemy.speed
              if enemy.x > 127 then enemy.x=-8 end
          end
      
          --items
          for item in all(items) do
              --animate
              item.sprite += item.timing
              if item.sprite >= item.last then item.sprite = item.first end
              --don't move
          end
      end
      

      Run

      pixelart pico-8 animate sprites

      Here is what we drew in our sprite sheet. The same player as before, then 3 enemies, and 3 items.

      pico-8 spritesheets

      Notice that they all use only 4 sprites to create their animation except for the coin which uses 8.


      We separate the player, enemies, and items into 3 different tables. For the player, we simply wrote the player data directly into the table. But the enemies and items table will hold smaller tables for each enemy's data and each item's data. So we wrote out those tables for each enemy as enemy1, enemy2, enemy3, and each item as item1, item2, item3.

      You may notice some new variables stored with those objects. After timing, we also added speed to the enemies to allow each enemy to move at different speeds. Then we added first to remember the starting sprite number and last to remember to last sprite number to be used in the checks that happen in the _update() function.

      The _draw() and _update() functions use a special table loop.

      for entry in all(table)

      That will cycle through each entry in a table and run the same code over them. This keeps our code nice and short. The only hard part is imagining what the tables look like and understanding how to prepare the table data for loops like this.


      Save this cartridge image and open in your PICO-8 to get the sprites and the code so you can start playing around with it.



      pico-8 sprite animation game cart




      pixelart icon


font
nerdy teachers share